summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp2
-rw-r--r--apct-tests/perftests/core/src/android/app/OWNERS2
-rw-r--r--apex/media/framework/java/android/media/ApplicationMediaCapabilities.java84
-rw-r--r--config/preloaded-classes-denylist1
-rw-r--r--core/api/current.txt4
-rw-r--r--core/api/system-current.txt8
-rw-r--r--core/api/test-current.txt37
-rw-r--r--core/java/android/app/ActivityManagerInternal.java6
-rw-r--r--core/java/android/app/AnrController.java29
-rw-r--r--core/java/android/app/OWNERS2
-rw-r--r--core/java/android/app/RESOURCES_OWNERS2
-rw-r--r--core/java/android/app/WindowTokenClient.java4
-rw-r--r--core/java/android/app/admin/DevicePolicyCache.java12
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java79
-rw-r--r--core/java/android/app/admin/FullyManagedDeviceProvisioningParams.java43
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl1
-rw-r--r--core/java/android/content/Context.java1
-rw-r--r--core/java/android/content/pm/LauncherApps.java1
-rw-r--r--core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java19
-rw-r--r--core/java/android/hardware/biometrics/BiometricManager.java12
-rw-r--r--core/java/android/hardware/biometrics/BiometricPrompt.java77
-rw-r--r--core/java/android/hardware/biometrics/PromptInfo.java11
-rw-r--r--core/java/android/hardware/devicestate/DeviceStateManager.java74
-rw-r--r--core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java191
-rw-r--r--core/java/android/hardware/devicestate/DeviceStateRequest.java163
-rw-r--r--core/java/android/hardware/devicestate/IDeviceStateManager.aidl40
-rw-r--r--core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl37
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java62
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java7
-rw-r--r--core/java/android/hardware/fingerprint/IFingerprintService.aidl2
-rw-r--r--core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl9
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java2
-rw-r--r--core/java/android/net/OemNetworkPreferences.java71
-rw-r--r--core/java/android/os/UserHandle.java13
-rw-r--r--core/java/android/os/incremental/IncrementalManager.java13
-rw-r--r--core/java/android/security/keymaster/KeymasterDefs.java13
-rw-r--r--core/java/android/service/rotationresolver/RotationResolutionRequest.java3
-rw-r--r--core/java/android/service/rotationresolver/RotationResolverService.java7
-rw-r--r--core/java/android/text/DynamicLayout.java6
-rw-r--r--core/java/android/uwb/RangingManager.java5
-rw-r--r--core/java/android/view/IWindowManager.aidl14
-rw-r--r--core/java/android/view/View.java19
-rw-r--r--core/java/android/view/WindowManagerGlobal.java1
-rw-r--r--core/java/android/view/inputmethod/BaseInputConnection.java4
-rw-r--r--core/java/android/view/inputmethod/EditorInfo.java7
-rw-r--r--core/java/android/view/inputmethod/InputConnection.java17
-rw-r--r--core/java/android/view/inputmethod/InputConnectionWrapper.java4
-rw-r--r--core/java/android/widget/TextView.java24
-rw-r--r--core/java/com/android/internal/compat/IPlatformCompat.aidl3
-rw-r--r--core/java/com/android/internal/os/KernelCpuTotalBpfMapReader.java5
-rw-r--r--core/java/com/android/internal/os/ZygoteServer.java18
-rw-r--r--core/java/com/android/internal/view/IInputConnectionWrapper.java19
-rw-r--r--core/java/com/android/internal/view/IInputContext.aidl2
-rw-r--r--core/java/com/android/internal/view/InputConnectionWrapper.java6
-rw-r--r--core/java/com/android/internal/widget/EditableInputConnection.java6
-rw-r--r--core/jni/Android.bp6
-rw-r--r--core/jni/com_android_internal_os_KernelCpuTotalBpfMapReader.cpp5
-rw-r--r--core/res/AndroidManifest.xml2
-rw-r--r--core/res/res/values/strings.xml2
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/tests/coretests/src/android/app/WindowContextTest.java3
-rw-r--r--core/tests/coretests/src/android/widget/TextViewTest.java12
-rw-r--r--core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java155
-rw-r--r--data/etc/platform.xml1
-rw-r--r--data/etc/privapp-permissions-platform.xml3
-rw-r--r--keystore/java/android/security/keystore/KeyProperties.java15
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java24
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java19
-rw-r--r--keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java22
-rw-r--r--libs/hwui/jni/fonts/FontFamily.cpp2
-rw-r--r--media/java/android/media/AudioManager.java1
-rw-r--r--media/java/android/media/AudioPlaybackConfiguration.java43
-rw-r--r--media/java/android/media/AudioTrack.java4
-rw-r--r--media/java/android/media/HwAudioSource.java2
-rwxr-xr-xmedia/java/android/media/IAudioService.aidl2
-rw-r--r--media/java/android/media/MediaPlayer.java18
-rw-r--r--media/java/android/media/PlayerBase.java32
-rw-r--r--media/java/android/media/SoundPool.java3
-rw-r--r--media/java/android/media/tv/tuner/Tuner.java12
-rw-r--r--media/jni/Android.bp4
-rw-r--r--media/jni/android_media_MediaPlayer.cpp2
-rw-r--r--native/android/system_fonts.cpp2
-rw-r--r--packages/Connectivity/framework/src/android/net/ConnectivityManager.java10
-rw-r--r--packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl3
-rw-r--r--packages/Connectivity/framework/src/android/net/NetworkRequest.java20
-rw-r--r--packages/Connectivity/framework/src/android/net/Proxy.java60
-rw-r--r--packages/Connectivity/framework/src/android/net/ProxyInfo.java4
-rw-r--r--packages/Connectivity/framework/src/android/net/VpnManager.java105
-rw-r--r--packages/SettingsLib/res/values-af/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-am/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-as/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-az/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-bg/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-bn/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-bs/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-cs/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-da/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-de/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-el/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-es-rUS/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-es/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-et/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-eu/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-fi/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-fr/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-gl/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-gu/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-hr/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-hu/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-hy/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-in/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-is/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-it/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ja/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ka/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-kk/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-km/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-kn/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ko/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ky/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-lo/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-lt/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-mk/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ml/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-mn/strings.xml7
-rw-r--r--packages/SettingsLib/res/values-mr/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ms/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-nb/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ne/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-nl/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-or/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-pa/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-pl/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ro/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-si/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sk/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sl/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sq/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sr/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sv/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-sw/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ta/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-te/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-th/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-tl/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-tr/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-uk/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-ur/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-uz/strings.xml5
-rw-r--r--packages/SettingsLib/res/values-vi/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-zh-rHK/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/strings.xml3
-rw-r--r--packages/SettingsLib/res/values-zu/strings.xml3
-rw-r--r--packages/SystemUI/res/drawable/controls_dialog_bg.xml21
-rw-r--r--packages/SystemUI/res/drawable/udfps_progress_bar.xml44
-rw-r--r--packages/SystemUI/res/layout/controls_in_dialog.xml45
-rw-r--r--packages/SystemUI/res/layout/keyguard_bottom_area.xml11
-rw-r--r--packages/SystemUI/res/layout/long_screenshot.xml22
-rw-r--r--packages/SystemUI/res/layout/udfps_view.xml15
-rw-r--r--packages/SystemUI/res/values/attrs.xml8
-rw-r--r--packages/SystemUI/res/values/colors.xml4
-rw-r--r--packages/SystemUI/res/values/dimens.xml5
-rw-r--r--packages/SystemUI/res/values/styles.xml21
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsProgressBar.java59
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/Utils.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsDialog.kt90
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ContextualButton.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/CropView.java105
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java184
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java84
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java14
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java10
-rw-r--r--packages/VpnDialogs/src/com/android/vpndialogs/AlwaysOnDisconnectedDialog.java21
-rw-r--r--packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java38
-rw-r--r--packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java16
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java2
-rw-r--r--services/core/Android.bp18
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java22
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java85
-rw-r--r--services/core/java/com/android/server/TestNetworkService.java7
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java11
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java8
-rw-r--r--services/core/java/com/android/server/am/ProcessErrorStateRecord.java10
-rw-r--r--services/core/java/com/android/server/am/SettingsToPropertiesMapper.java1
-rw-r--r--services/core/java/com/android/server/audio/AudioDeviceBroker.java4
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java638
-rw-r--r--services/core/java/com/android/server/audio/PlaybackActivityMonitor.java27
-rw-r--r--services/core/java/com/android/server/biometrics/PreAuthInfo.java9
-rw-r--r--services/core/java/com/android/server/biometrics/Utils.java41
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java7
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java116
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUtils.java56
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java2
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java11
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintEnrollClient.java14
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java8
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java3
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java32
-rw-r--r--services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java13
-rw-r--r--services/core/java/com/android/server/compat/PlatformCompat.java4
-rw-r--r--services/core/java/com/android/server/connectivity/DnsManager.java3
-rw-r--r--services/core/java/com/android/server/connectivity/Nat464Xlat.java4
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java34
-rw-r--r--services/core/java/com/android/server/connectivity/PermissionMonitor.java10
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java12
-rw-r--r--services/core/java/com/android/server/devicestate/DeviceState.java10
-rw-r--r--services/core/java/com/android/server/devicestate/DeviceStateManagerService.java501
-rw-r--r--services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java85
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java4
-rw-r--r--services/core/java/com/android/server/graphics/fonts/FontManagerService.java1
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java6
-rw-r--r--services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java3
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java3
-rw-r--r--services/core/java/com/android/server/pm/DefaultAppProvider.java9
-rw-r--r--services/core/java/com/android/server/pm/IncrementalStates.java18
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java37
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java67
-rw-r--r--services/core/java/com/android/server/pm/PackageSetting.java4
-rw-r--r--services/core/java/com/android/server/pm/PackageSettingBase.java8
-rw-r--r--services/core/java/com/android/server/pm/ShortcutPackage.java21
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java72
-rw-r--r--services/core/java/com/android/server/policy/DisplayFoldController.java4
-rw-r--r--services/core/java/com/android/server/policy/WindowManagerPolicy.java4
-rw-r--r--services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java57
-rw-r--r--services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java20
-rw-r--r--services/core/java/com/android/server/rotationresolver/RotationResolverManagerService.java2
-rw-r--r--services/core/java/com/android/server/rotationresolver/RotationResolverShellCommand.java (renamed from services/core/java/com/android/server/rotationresolver/RotationResolverShellCommend.java)4
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java3
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java712
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java1
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java36
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java3
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java48
-rw-r--r--services/core/java/com/android/server/wm/DisplayRotation.java4
-rw-r--r--services/core/java/com/android/server/wm/DisplayWindowSettings.java37
-rw-r--r--services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java7
-rw-r--r--services/core/java/com/android/server/wm/DockedStackDividerController.java2
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java4
-rw-r--r--services/core/java/com/android/server/wm/ShellRoot.java2
-rw-r--r--services/core/java/com/android/server/wm/TaskDisplayArea.java6
-rw-r--r--services/core/java/com/android/server/wm/WallpaperWindowToken.java3
-rw-r--r--services/core/java/com/android/server/wm/WindowAnimator.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java45
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java192
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java24
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java23
-rw-r--r--services/core/jni/Android.bp8
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java11
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java5
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java21
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java59
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java40
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/Owners.java37
-rw-r--r--services/incremental/Android.bp6
-rw-r--r--services/tests/servicestests/Android.bp6
-rw-r--r--services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java273
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java20
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java75
-rw-r--r--services/tests/shortcutmanagerutils/Android.bp4
-rw-r--r--services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java90
-rw-r--r--services/tests/uiservicestests/Android.bp2
-rw-r--r--services/tests/wmtests/Android.bp2
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java14
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java10
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java64
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java31
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java15
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java3
-rw-r--r--telephony/java/android/telephony/data/DataCallResponse.java43
-rw-r--r--telephony/java/android/telephony/data/EpsQos.java4
-rw-r--r--telephony/java/android/telephony/data/Qos.java18
-rw-r--r--telephony/java/android/telephony/data/QosBearerFilter.java (renamed from telephony/java/android/telephony/data/QosFilter.java)62
-rw-r--r--telephony/java/android/telephony/data/QosBearerSession.java137
-rw-r--r--telephony/java/android/telephony/data/QosSession.java125
-rw-r--r--tests/net/common/java/android/net/OemNetworkPreferencesTest.java92
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java193
-rw-r--r--tests/net/java/com/android/server/connectivity/VpnTest.java13
-rw-r--r--tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java29
307 files changed, 5875 insertions, 2094 deletions
diff --git a/Android.bp b/Android.bp
index 2ccadd318df6..9655daf649c7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -536,7 +536,7 @@ java_library {
"android.hardware.vibrator-V1.3-java",
"android.security.apc-java",
"android.security.authorization-java",
- "android.system.keystore2-java",
+ "android.system.keystore2-V1-java",
"android.system.suspend.control.internal-java",
"cameraprotosnano",
"devicepolicyprotosnano",
diff --git a/apct-tests/perftests/core/src/android/app/OWNERS b/apct-tests/perftests/core/src/android/app/OWNERS
new file mode 100644
index 000000000000..4f168ceb3c55
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/app/OWNERS
@@ -0,0 +1,2 @@
+per-file Overlay* = file:/core/java/android/app/RESOURCES_OWNERS
+per-file Resources* = file:/core/java/android/app/RESOURCES_OWNERS
diff --git a/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java b/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
index e1a859648ee6..aefeab621778 100644
--- a/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
+++ b/apex/media/framework/java/android/media/ApplicationMediaCapabilities.java
@@ -36,30 +36,46 @@ import java.util.Map;
import java.util.Set;
/**
- * ApplicationMediaCapabilities is an immutable class that encapsulates an application's
- * capabilities for handling newer video codec format and media features.
- *
- * The ApplicationMediaCapabilities class is used by the platform to represent an application's
- * media capabilities as defined in their manifest(TODO: Add link) in order to determine
- * whether modern media files need to be transcoded for that application (TODO: Add link).
- *
- * ApplicationMediaCapabilities objects can also be built by applications at runtime for use with
- * {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)} to provide more
- * control over the transcoding that is built into the platform. ApplicationMediaCapabilities
- * provided by applications at runtime like this override the default manifest capabilities for that
- * media access.
- *
- * <h3> Video Codec Support</h3>
- * Newer video codes include HEVC, VP9 and AV1. Application only needs to indicate their support
- * for newer format with this class as they are assumed to support older format like h.264.
- *
- * <h4>Capability of handling HDR(high dynamic range) video</h4>
- * There are four types of HDR video(Dolby-Vision, HDR10, HDR10+, HLG) supported by the platform,
- * application will only need to specify individual types they supported.
+ ApplicationMediaCapabilities is an immutable class that encapsulates an application's capabilities
+ for handling newer video codec format and media features.
+
+ <p>
+ Android 12 introduces seamless media transcoding feature. By default, Android assumes apps can
+ support playback of all media formats. Apps that would like to request that media be transcoded
+ into a more compatible format should declare their media capabilities in a media_capabilities
+ .xml resource file and add it as a property tag in the AndroidManifest.xml file. Here is a example:
+ <pre>
+ {@code
+ <media-capabilities xmlns:android="http://schemas.android.com/apk/res/android">
+ <format android:name="HEVC" supported="true"/>
+ <format android:name="HDR10" supported="false"/>
+ <format android:name="HDR10Plus" supported="false"/>
+ </media-capabilities>
+ }
+ </pre>
+ The ApplicationMediaCapabilities class is generated from this xml and used by the platform to
+ represent an application's media capabilities in order to determine whether modern media files need
+ to be transcoded for that application.
+ </p>
+
+ <p>
+ ApplicationMediaCapabilities objects can also be built by applications at runtime for use with
+ {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)} to provide more
+ control over the transcoding that is built into the platform. ApplicationMediaCapabilities
+ provided by applications at runtime like this override the default manifest capabilities for that
+ media access.The object could be build either through {@link #createFromXml(XmlPullParser)} or
+ through the builder class {@link ApplicationMediaCapabilities.Builder}
+
+ <h3> Video Codec Support</h3>
+ <p>
+ Newer video codes include HEVC, VP9 and AV1. Application only needs to indicate their support
+ for newer format with this class as they are assumed to support older format like h.264.
+
+ <h3>Capability of handling HDR(high dynamic range) video</h3>
+ <p>
+ There are four types of HDR video(Dolby-Vision, HDR10, HDR10+, HLG) supported by the platform,
+ application will only need to specify individual types they supported.
*/
-// TODO(huang): Correct openTypedAssetFileDescriptor with the new API after it is added.
-// TODO(hkuang): Add a link to seamless transcoding detail when it is published
-// TODO(hkuang): Add code sample on how to build a capability object with MediaCodecList
public final class ApplicationMediaCapabilities implements Parcelable {
private static final String TAG = "ApplicationMediaCapabilities";
@@ -105,9 +121,9 @@ public final class ApplicationMediaCapabilities implements Parcelable {
*/
public boolean isVideoMimeTypeSupported(
@NonNull String videoMime) throws FormatNotFoundException {
- if (mUnsupportedVideoMimeTypes.contains(videoMime)) {
+ if (mUnsupportedVideoMimeTypes.contains(videoMime.toLowerCase())) {
return false;
- } else if (mSupportedVideoMimeTypes.contains(videoMime)) {
+ } else if (mSupportedVideoMimeTypes.contains(videoMime.toLowerCase())) {
return true;
} else {
throw new FormatNotFoundException(videoMime);
@@ -262,11 +278,27 @@ public final class ApplicationMediaCapabilities implements Parcelable {
/**
* Creates {@link ApplicationMediaCapabilities} from an xml.
+ *
+ * The xml's syntax is the same as the media_capabilities.xml used by the AndroidManifest.xml.
+ * <p> Here is an example:
+ *
+ * <pre>
+ * {@code
+ * <media-capabilities xmlns:android="http://schemas.android.com/apk/res/android">
+ * <format android:name="HEVC" supported="true"/>
+ * <format android:name="HDR10" supported="false"/>
+ * <format android:name="HDR10Plus" supported="false"/>
+ * </media-capabilities>
+ * }
+ * </pre>
+ * <p>
+ *
* @param xmlParser The underlying {@link XmlPullParser} that will read the xml.
* @return An ApplicationMediaCapabilities object.
* @throws UnsupportedOperationException if the capabilities in xml config are invalid or
* incompatible.
*/
+ // TODO: Add developer.android.com link for the format of the xml.
@NonNull
public static ApplicationMediaCapabilities createFromXml(@NonNull XmlPullParser xmlParser) {
ApplicationMediaCapabilities.Builder builder = new ApplicationMediaCapabilities.Builder();
@@ -430,7 +462,7 @@ public final class ApplicationMediaCapabilities implements Parcelable {
mIsSlowMotionSupported = isSupported;
break;
default:
- throw new UnsupportedOperationException("Invalid format name " + name);
+ Log.w(TAG, "Invalid format name " + name);
}
// Save the name and isSupported into the map for validate later.
mFormatSupportedMap.put(name, isSupported);
diff --git a/config/preloaded-classes-denylist b/config/preloaded-classes-denylist
index 43a8a878a624..da4b25519e80 100644
--- a/config/preloaded-classes-denylist
+++ b/config/preloaded-classes-denylist
@@ -4,7 +4,6 @@ android.os.FileObserver
android.os.NullVibrator
android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask
android.widget.Magnifier
-com.android.server.BootReceiver$2
gov.nist.core.net.DefaultNetworkLayer
android.net.rtp.AudioGroup
android.net.rtp.AudioStream
diff --git a/core/api/current.txt b/core/api/current.txt
index bfdfb4060078..f5c67c170931 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -6930,6 +6930,7 @@ package android.app.admin {
method public void addPersistentPreferredActivity(@NonNull android.content.ComponentName, android.content.IntentFilter, @NonNull android.content.ComponentName);
method public void addUserRestriction(@NonNull android.content.ComponentName, String);
method public boolean bindDeviceAdminServiceAsUser(@NonNull android.content.ComponentName, android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull android.os.UserHandle);
+ method public boolean canAdminGrantSensorsPermissions();
method public void clearApplicationUserData(@NonNull android.content.ComponentName, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.app.admin.DevicePolicyManager.OnClearApplicationUserDataListener);
method public void clearCrossProfileIntentFilters(@NonNull android.content.ComponentName);
method @Deprecated public void clearDeviceOwnerApp(String);
@@ -7227,6 +7228,7 @@ package android.app.admin {
field public static final String EXTRA_PROVISIONING_LOGO_URI = "android.app.extra.PROVISIONING_LOGO_URI";
field public static final String EXTRA_PROVISIONING_MAIN_COLOR = "android.app.extra.PROVISIONING_MAIN_COLOR";
field public static final String EXTRA_PROVISIONING_MODE = "android.app.extra.PROVISIONING_MODE";
+ field public static final String EXTRA_PROVISIONING_PERMISSION_GRANT_OPT_OUT = "android.app.extra.PROVISIONING_PERMISSION_GRANT_OPT_OUT";
field public static final String EXTRA_PROVISIONING_SERIAL_NUMBER = "android.app.extra.PROVISIONING_SERIAL_NUMBER";
field public static final String EXTRA_PROVISIONING_SKIP_EDUCATION_SCREENS = "android.app.extra.PROVISIONING_SKIP_EDUCATION_SCREENS";
field public static final String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
@@ -51073,7 +51075,7 @@ package android.view.inputmethod {
method public boolean sendKeyEvent(android.view.KeyEvent);
method public boolean setComposingRegion(int, int);
method public boolean setComposingText(CharSequence, int);
- method public default boolean setImeTemporarilyConsumesInput(boolean);
+ method public default boolean setImeConsumesInput(boolean);
method public boolean setSelection(int, int);
field public static final int CURSOR_UPDATE_IMMEDIATE = 1; // 0x1
field public static final int CURSOR_UPDATE_MONITOR = 2; // 0x2
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 3111b7c00630..4d24cad699b6 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -870,6 +870,7 @@ package android.app.admin {
}
public class DevicePolicyManager {
+ method public boolean canAdminGrantSensorsPermissionsForUser(int);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean getBluetoothContactSharingDisabled(@NonNull android.os.UserHandle);
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwner();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.content.ComponentName getDeviceOwnerComponentOnAnyUser();
@@ -4971,6 +4972,7 @@ package android.media {
method public android.media.PlayerProxy getPlayerProxy();
method public int getPlayerState();
method public int getPlayerType();
+ method @IntRange(from=0) public int getSessionId();
method public boolean isActive();
field public static final int PLAYER_STATE_IDLE = 1; // 0x1
field public static final int PLAYER_STATE_PAUSED = 3; // 0x3
@@ -8643,6 +8645,7 @@ package android.os {
method @NonNull public static String formatUid(int);
method public static int getAppId(int);
method public int getIdentifier();
+ method public static int getUid(@NonNull android.os.UserHandle, int);
method @Deprecated public boolean isOwner();
method public boolean isSystem();
method public static int myUserId();
@@ -9510,6 +9513,11 @@ package android.security.keystore {
method @Deprecated @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUid(int);
}
+ public abstract class KeyProperties {
+ field public static final int NAMESPACE_APPLICATION = -1; // 0xffffffff
+ field public static final int NAMESPACE_WIFI = 102; // 0x66
+ }
+
}
package android.security.keystore.recovery {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 79917d020198..e39b2b856661 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -12,6 +12,7 @@ package android {
field public static final String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA";
field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
field public static final String CONTROL_DEVICE_LIGHTS = "android.permission.CONTROL_DEVICE_LIGHTS";
+ field public static final String CONTROL_DEVICE_STATE = "android.permission.CONTROL_DEVICE_STATE";
field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
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";
@@ -463,6 +464,7 @@ package android.app.admin {
}
public final class FullyManagedDeviceProvisioningParams implements android.os.Parcelable {
+ method public boolean canDeviceOwnerGrantSensorsPermissions();
method public int describeContents();
method @NonNull public android.content.ComponentName getDeviceAdminComponentName();
method public long getLocalTime();
@@ -477,6 +479,7 @@ package android.app.admin {
public static final class FullyManagedDeviceProvisioningParams.Builder {
ctor public FullyManagedDeviceProvisioningParams.Builder(@NonNull android.content.ComponentName, @NonNull String);
method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams build();
+ method @NonNull public android.app.admin.FullyManagedDeviceProvisioningParams.Builder setDeviceOwnerCanGrantSensorsPermissions(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);
@@ -900,6 +903,40 @@ package android.hardware.camera2 {
}
+package android.hardware.devicestate {
+
+ public final class DeviceStateManager {
+ method public void addDeviceStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateListener);
+ method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) public void cancelRequest(@NonNull android.hardware.devicestate.DeviceStateRequest);
+ method @NonNull public int[] getSupportedStates();
+ method public void removeDeviceStateListener(@NonNull android.hardware.devicestate.DeviceStateManager.DeviceStateListener);
+ method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE) public void requestState(@NonNull android.hardware.devicestate.DeviceStateRequest, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.devicestate.DeviceStateRequest.Callback);
+ }
+
+ public static interface DeviceStateManager.DeviceStateListener {
+ method public void onDeviceStateChanged(int);
+ }
+
+ public final class DeviceStateRequest {
+ method public int getFlags();
+ method public int getState();
+ method @NonNull public static android.hardware.devicestate.DeviceStateRequest.Builder newBuilder(int);
+ field public static final int FLAG_CANCEL_WHEN_BASE_CHANGES = 1; // 0x1
+ }
+
+ public static final class DeviceStateRequest.Builder {
+ method @NonNull public android.hardware.devicestate.DeviceStateRequest build();
+ method @NonNull public android.hardware.devicestate.DeviceStateRequest.Builder setFlags(int);
+ }
+
+ public static interface DeviceStateRequest.Callback {
+ method public default void onRequestActivated(@NonNull android.hardware.devicestate.DeviceStateRequest);
+ method public default void onRequestCanceled(@NonNull android.hardware.devicestate.DeviceStateRequest);
+ method public default void onRequestSuspended(@NonNull android.hardware.devicestate.DeviceStateRequest);
+ }
+
+}
+
package android.hardware.display {
public class AmbientDisplayConfiguration {
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 9b6f4b43581b..c31c22cca329 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -538,4 +538,10 @@ public abstract class ActivityManagerInternal {
* @return mBootTimeTempAllowlistDuration of ActivityManagerConstants.
*/
public abstract long getBootTimeTempAllowListDuration();
+
+ /** Register an {@link AnrController} to control the ANR dialog behavior */
+ public abstract void registerAnrController(AnrController controller);
+
+ /** Unregister an {@link AnrController} */
+ public abstract void unregisterAnrController(AnrController controller);
}
diff --git a/core/java/android/app/AnrController.java b/core/java/android/app/AnrController.java
new file mode 100644
index 000000000000..cfc9d2715720
--- /dev/null
+++ b/core/java/android/app/AnrController.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+/**
+ * Interface to control the ANR dialog within the activity manager
+ * {@hide}
+ */
+public interface AnrController {
+ /**
+ * Returns the delay in milliseconds for an ANR dialog that is about to be shown for
+ * {@code packageName}.
+ */
+ long getAnrDelayMillis(String packageName, int uid);
+}
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index e6aa7a77357c..1ff64dbe6d2e 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -59,7 +59,7 @@ per-file IInstantAppResolver.aidl = file:/services/core/java/com/android/server/
per-file InstantAppResolveInfo.aidl = file:/services/core/java/com/android/server/pm/OWNERS
# ResourcesManager
-per-file ResourcesManager.java = rtmitchell@google.com, toddke@google.com
+per-file ResourcesManager.java = file:RESOURCES_OWNERS
# VoiceInteraction
per-file *VoiceInteract* = file:/core/java/android/service/voice/OWNERS
diff --git a/core/java/android/app/RESOURCES_OWNERS b/core/java/android/app/RESOURCES_OWNERS
new file mode 100644
index 000000000000..21c39a8828ad
--- /dev/null
+++ b/core/java/android/app/RESOURCES_OWNERS
@@ -0,0 +1,2 @@
+rtmitchell@google.com
+toddke@google.com
diff --git a/core/java/android/app/WindowTokenClient.java b/core/java/android/app/WindowTokenClient.java
index 9092ef36deb6..29792ac47a36 100644
--- a/core/java/android/app/WindowTokenClient.java
+++ b/core/java/android/app/WindowTokenClient.java
@@ -44,8 +44,8 @@ public class WindowTokenClient extends IWindowToken.Stub {
* Attaches {@code context} to this {@link WindowTokenClient}. Each {@link WindowTokenClient}
* can only attach one {@link Context}.
* <p>This method must be called before invoking
- * {@link android.view.IWindowManager#addWindowTokenWithOptions(IBinder, int, int, Bundle,
- * String)}.<p/>
+ * {@link android.view.IWindowManager#registerWindowContextListener(IBinder, int, int,
+ * Bundle, boolean)}.<p/>
*
* @param context context to be attached
* @throws IllegalStateException if attached context has already existed.
diff --git a/core/java/android/app/admin/DevicePolicyCache.java b/core/java/android/app/admin/DevicePolicyCache.java
index 8b0c7061925f..9c07f85a6390 100644
--- a/core/java/android/app/admin/DevicePolicyCache.java
+++ b/core/java/android/app/admin/DevicePolicyCache.java
@@ -57,6 +57,13 @@ public abstract class DevicePolicyCache {
public abstract int getPermissionPolicy(@UserIdInt int userHandle);
/**
+ * Caches {@link DevicePolicyManager#canAdminGrantSensorsPermissionsForUser(int)} for the
+ * given user.
+ */
+ public abstract boolean canAdminGrantSensorsPermissionsForUser(@UserIdInt int userHandle);
+
+
+ /**
* Empty implementation.
*/
private static class EmptyDevicePolicyCache extends DevicePolicyCache {
@@ -77,5 +84,10 @@ public abstract class DevicePolicyCache {
public int getPermissionPolicy(int userHandle) {
return DevicePolicyManager.PERMISSION_POLICY_PROMPT;
}
+
+ @Override
+ public boolean canAdminGrantSensorsPermissionsForUser(int userHandle) {
+ return false;
+ }
}
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 06fe9d764f25..82255c87c971 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -980,6 +980,19 @@ public class DevicePolicyManager {
= "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
/**
+ * A boolean extra indicating the admin of a fully-managed device opts out of controlling
+ * permission grants for sensor-related permissions,
+ * see {@link #setPermissionGrantState(ComponentName, String, String, int)}.
+ *
+ * The default for this extra is {@code false} - by default, the admin of a fully-managed
+ * device has the ability to grant sensors-related permissions.
+ *
+ * <p>Use with {@link #ACTION_PROVISION_MANAGED_DEVICE} only.
+ */
+ public static final String EXTRA_PROVISIONING_PERMISSION_GRANT_OPT_OUT =
+ "android.app.extra.PROVISIONING_PERMISSION_GRANT_OPT_OUT";
+
+ /**
* A String extra holding the URL-safe base64 encoded SHA-256 checksum of any signature of the
* android package archive at the download location specified in {@link
* #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION}.
@@ -10520,6 +10533,13 @@ public class DevicePolicyManager {
* As this policy only acts on runtime permission requests, it only applies to applications
* built with a {@code targetSdkVersion} of {@link android.os.Build.VERSION_CODES#M} or later.
*
+ * <p>
+ * NOTE: On devices running {@link android.os.Build.VERSION_CODES#S} and above, an auto-grant
+ * policy will not apply to certain sensors-related permissions on some configurations.
+ * See {@link #setPermissionGrantState(ComponentName, String, String, int)} for the list of
+ * permissions affected, and the behavior change for managed profiles and fully-managed
+ * devices.
+ *
* @param admin Which profile or device owner this request is associated with.
* @param policy One of the policy constants {@link #PERMISSION_POLICY_PROMPT},
* {@link #PERMISSION_POLICY_AUTO_GRANT} and {@link #PERMISSION_POLICY_AUTO_DENY}.
@@ -10578,6 +10598,31 @@ public class DevicePolicyManager {
* application built with a {@code targetSdkVersion} &lt;
* {@link android.os.Build.VERSION_CODES#M} the app-op matching the permission is set to
* {@link android.app.AppOpsManager#MODE_IGNORED}, but the permission stays granted.
+ * <p>
+ * NOTE: On devices running {@link android.os.Build.VERSION_CODES#S} and above, control over
+ * the following, sensors-related, permissions is restricted:
+ * <ul>
+ * <li>Manifest.permission.ACCESS_FINE_LOCATION</li>
+ * <li>Manifest.permission.ACCESS_BACKGROUND_LOCATION</li>
+ * <li>Manifest.permission.ACCESS_COARSE_LOCATION</li>
+ * <li>Manifest.permission.CAMERA</li>
+ * <li>Manifest.permission.RECORD_AUDIO</li>
+ * <li>Manifest.permission.RECORD_BACKGROUND_AUDIO</li>
+ * <li>Manifest.permission.ACTIVITY_RECOGNITION</li>
+ * <li>Manifest.permission.BODY_SENSORS</li>
+ * </ul>
+ * <p>
+ * A profile owner may not grant these permissions (i.e. call this method with any of the
+ * permissions listed above and {@code grantState} of {@code #PERMISSION_GRANT_STATE_GRANTED}),
+ * but may deny them.
+ * <p>
+ * A device owner, by default, may continue granting these permissions. However, for increased
+ * user control, the admin may opt out of controlling grants for these permissions by including
+ * {@link #EXTRA_PROVISIONING_PERMISSION_GRANT_OPT_OUT} in the provisioning parameters. In that
+ * case the device owner's control will be limited do denying these permissions.
+ * <p>
+ * Attempts by the admin to grant these permissions, when the admin is restricted from doing
+ * so, will be silently ignored (no exception will be thrown).
*
* @param admin Which profile or device owner this request is associated with.
* @param packageName The application to grant or revoke a permission to.
@@ -13271,4 +13316,38 @@ public class DevicePolicyManager {
}
}
}
+ /**
+ * Returns true if the caller is running on a device where the admin can grant
+ * permissions related to device sensors.
+ * This is a signal that the device is a fully-managed device where personal usage is
+ * discouraged.
+ * The list of permissions is listed in
+ * {@link #setPermissionGrantState(ComponentName, String, String, int)}.
+ *
+ * May be called by any app.
+ * @return true if the app can grant device sensors-related permissions, false otherwise.
+ */
+ public boolean canAdminGrantSensorsPermissions() {
+ return canAdminGrantSensorsPermissionsForUser(myUserId());
+ }
+
+ /**
+ * Returns true if the admin can control grants of sensors-related permissions, for
+ * a given user.
+ *
+ * @hide
+ * @param userId The ID of the user to check.
+ * @return if the admin may grant these permissions, false otherwise.
+ */
+ @SystemApi
+ public boolean canAdminGrantSensorsPermissionsForUser(int userId) {
+ if (mService == null) {
+ return false;
+ }
+ try {
+ return mService.canAdminGrantSensorsPermissionsForUser(userId);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/admin/FullyManagedDeviceProvisioningParams.java b/core/java/android/app/admin/FullyManagedDeviceProvisioningParams.java
index 83af0195ddba..5e1cbadb458e 100644
--- a/core/java/android/app/admin/FullyManagedDeviceProvisioningParams.java
+++ b/core/java/android/app/admin/FullyManagedDeviceProvisioningParams.java
@@ -42,6 +42,7 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
private final long mLocalTime;
@SuppressLint("UseIcu")
@Nullable private final Locale mLocale;
+ private final boolean mDeviceOwnerCanGrantSensorsPermissions;
private FullyManagedDeviceProvisioningParams(
@NonNull ComponentName deviceAdminComponentName,
@@ -49,13 +50,16 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
boolean leaveAllSystemAppsEnabled,
@Nullable String timeZone,
long localTime,
- @Nullable @SuppressLint("UseIcu") Locale locale) {
+ @Nullable @SuppressLint("UseIcu") Locale locale,
+ boolean deviceOwnerCanGrantSensorsPermissions) {
this.mDeviceAdminComponentName = requireNonNull(deviceAdminComponentName);
this.mOwnerName = requireNonNull(ownerName);
this.mLeaveAllSystemAppsEnabled = leaveAllSystemAppsEnabled;
this.mTimeZone = timeZone;
this.mLocalTime = localTime;
this.mLocale = locale;
+ this.mDeviceOwnerCanGrantSensorsPermissions =
+ deviceOwnerCanGrantSensorsPermissions;
}
private FullyManagedDeviceProvisioningParams(
@@ -64,13 +68,15 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
boolean leaveAllSystemAppsEnabled,
@Nullable String timeZone,
long localTime,
- @Nullable String localeStr) {
+ @Nullable String localeStr,
+ boolean deviceOwnerCanGrantSensorsPermissions) {
this(deviceAdminComponentName,
ownerName,
leaveAllSystemAppsEnabled,
timeZone,
localTime,
- getLocale(localeStr));
+ getLocale(localeStr),
+ deviceOwnerCanGrantSensorsPermissions);
}
@Nullable
@@ -107,6 +113,14 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
}
/**
+ * @return true if the device owner can control sensor-related permission grants, false
+ * if the device owner has opted out of it.
+ */
+ public boolean canDeviceOwnerGrantSensorsPermissions() {
+ return mDeviceOwnerCanGrantSensorsPermissions;
+ }
+
+ /**
* Builder class for {@link FullyManagedDeviceProvisioningParams} objects.
*/
public static final class Builder {
@@ -117,6 +131,8 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
private long mLocalTime;
@SuppressLint("UseIcu")
@Nullable private Locale mLocale;
+ // Default to allowing control over sensor permission grants.
+ boolean mDeviceOwnerCanGrantSensorsPermissions = true;
/**
* Initialize a new {@link Builder} to construct a
@@ -181,6 +197,17 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
}
/**
+ * Marks that the Device Owner may grant permissions related to device sensors.
+ * See {@link DevicePolicyManager#EXTRA_PROVISIONING_PERMISSION_GRANT_OPT_OUT}.
+ */
+ @NonNull
+ @SuppressLint("MissingGetterMatchingBuilder")
+ public Builder setDeviceOwnerCanGrantSensorsPermissions(boolean mayGrant) {
+ mDeviceOwnerCanGrantSensorsPermissions = mayGrant;
+ return this;
+ }
+
+ /**
* Combines all of the attributes that have been set on this {@code Builder}
*
* @return a new {@link FullyManagedDeviceProvisioningParams} object.
@@ -193,7 +220,8 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
mLeaveAllSystemAppsEnabled,
mTimeZone,
mLocalTime,
- mLocale);
+ mLocale,
+ mDeviceOwnerCanGrantSensorsPermissions);
}
}
@@ -211,6 +239,8 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
+ ", mTimeZone=" + (mTimeZone == null ? "null" : mTimeZone)
+ ", mLocalTime=" + mLocalTime
+ ", mLocale=" + (mLocale == null ? "null" : mLocale)
+ + ", mDeviceOwnerCanGrantSensorsPermissions="
+ + mDeviceOwnerCanGrantSensorsPermissions
+ '}';
}
@@ -222,6 +252,7 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
dest.writeString(mTimeZone);
dest.writeLong(mLocalTime);
dest.writeString(mLocale == null ? null : mLocale.toLanguageTag());
+ dest.writeBoolean(mDeviceOwnerCanGrantSensorsPermissions);
}
@NonNull
@@ -235,6 +266,7 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
String timeZone = in.readString();
long localtime = in.readLong();
String locale = in.readString();
+ boolean deviceOwnerCanGrantSensorsPermissions = in.readBoolean();
return new FullyManagedDeviceProvisioningParams(
componentName,
@@ -242,7 +274,8 @@ public final class FullyManagedDeviceProvisioningParams implements Parcelable {
leaveAllSystemAppsEnabled,
timeZone,
localtime,
- locale);
+ locale,
+ deviceOwnerCanGrantSensorsPermissions);
}
@Override
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index cf0b31ea8cb2..89f30cc821ab 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -500,4 +500,5 @@ interface IDevicePolicyManager {
void provisionFullyManagedDevice(in FullyManagedDeviceProvisioningParams provisioningParams, in String callerPackage);
void resetDefaultCrossProfileIntentFilters(int userId);
+ boolean canAdminGrantSensorsPermissionsForUser(int userId);
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 5d28216756ae..2a402b204cb7 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3552,6 +3552,7 @@ public abstract class Context {
//@hide: NETWORK_SCORE_SERVICE,
USAGE_STATS_SERVICE,
MEDIA_SESSION_SERVICE,
+ MEDIA_COMMUNICATION_SERVICE,
BATTERY_SERVICE,
JOB_SCHEDULER_SERVICE,
//@hide: PERSISTENT_DATA_BLOCK_SERVICE,
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 62925757cde1..0c0e4020d04a 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -450,6 +450,7 @@ public class LauncherApps {
FLAG_MATCH_PINNED,
FLAG_MATCH_MANIFEST,
FLAG_MATCH_CACHED,
+ FLAG_MATCH_PINNED_BY_ANY_LAUNCHER,
FLAG_GET_KEY_FIELDS_ONLY,
FLAG_GET_PERSONS_DATA,
})
diff --git a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
index cbd2c550a797..9012b5ce2b1e 100644
--- a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
@@ -108,17 +108,14 @@ public class ParsedPermissionUtils {
permission.protectionLevel = PermissionInfo.fixProtectionLevel(permission.protectionLevel);
- if (permission.getProtectionFlags() != 0) {
- if ((permission.protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) == 0
- && (permission.protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY)
- == 0
- && (permission.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
- != PermissionInfo.PROTECTION_SIGNATURE
- && (permission.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE)
- != PermissionInfo.PROTECTION_INTERNAL) {
- return input.error("<permission> protectionLevel specifies a non-instant flag "
- + "but is not based on signature or internal type");
- }
+ final int otherProtectionFlags = permission.getProtectionFlags()
+ & ~(PermissionInfo.PROTECTION_FLAG_APPOP | PermissionInfo.PROTECTION_FLAG_INSTANT
+ | PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY);
+ if (otherProtectionFlags != 0
+ && permission.getProtection() != PermissionInfo.PROTECTION_SIGNATURE
+ && permission.getProtection() != PermissionInfo.PROTECTION_INTERNAL) {
+ return input.error("<permission> protectionLevel specifies a non-instant, non-appop,"
+ + " non-runtimeOnly flag but is not based on signature or internal type");
}
return ComponentParseUtils.parseAllMetaData(pkg, res, parser, tag, permission, input);
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 4145a7273ed2..08b1e245dc83 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -29,7 +29,6 @@ import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.Context;
import android.os.RemoteException;
-import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.util.Slog;
@@ -47,6 +46,13 @@ public class BiometricManager {
private static final String TAG = "BiometricManager";
/**
+ * An ID that should match any biometric sensor on the device.
+ *
+ * @hide
+ */
+ public static final int SENSOR_ID_ANY = -1;
+
+ /**
* No error detected.
*/
public static final int BIOMETRIC_SUCCESS =
@@ -139,7 +145,7 @@ public class BiometricManager {
*
* <p>This corresponds to {@link KeyProperties#AUTH_BIOMETRIC_STRONG} during key generation.
*
- * @see KeyGenParameterSpec.Builder#setUserAuthenticationParameters(int, int)
+ * @see android.security.keystore.KeyGenParameterSpec.Builder
*/
int BIOMETRIC_STRONG = 0x000F;
@@ -182,7 +188,7 @@ public class BiometricManager {
* <p>This corresponds to {@link KeyProperties#AUTH_DEVICE_CREDENTIAL} during key
* generation.
*
- * @see KeyGenParameterSpec.Builder#setUserAuthenticationParameters(int, int)
+ * @see android.security.keystore.KeyGenParameterSpec.Builder
*/
int DEVICE_CREDENTIAL = 1 << 15;
}
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 76cf9b9d28b9..4f6a7c75cca6 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -36,7 +36,6 @@ import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.security.identity.IdentityCredential;
-import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.text.TextUtils;
import android.util.Log;
@@ -325,7 +324,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
* request authentication with the proper set of authenticators (e.g. match the
* authenticators specified during key generation).
*
- * @see KeyGenParameterSpec.Builder#setUserAuthenticationParameters(int, int)
+ * @see android.security.keystore.KeyGenParameterSpec.Builder
* @see KeyProperties#AUTH_BIOMETRIC_STRONG
* @see KeyProperties#AUTH_DEVICE_CREDENTIAL
*
@@ -365,6 +364,21 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
}
/**
+ * If set, authenticate using the biometric sensor with the given ID.
+ *
+ * @param sensorId The ID of a biometric sensor, or -1 to allow any sensor (default).
+ * @return This builder.
+ *
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ @NonNull
+ public Builder setSensorId(int sensorId) {
+ mPromptInfo.setSensorId(sensorId);
+ return this;
+ }
+
+ /**
* Creates a {@link BiometricPrompt}.
*
* @return An instance of {@link BiometricPrompt}.
@@ -589,7 +603,8 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
*
* <p>Cryptographic operations in Android can be split into two categories: auth-per-use and
* time-based. This is specified during key creation via the timeout parameter of the
- * {@link KeyGenParameterSpec.Builder#setUserAuthenticationParameters(int, int)} API.
+ * {@code setUserAuthenticationParameters(int, int)} method of {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder}.
*
* <p>CryptoObjects are used to unlock auth-per-use keys via
* {@link BiometricPrompt#authenticate(CryptoObject, CancellationSignal, Executor,
@@ -778,6 +793,27 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
@NonNull @CallbackExecutor Executor executor,
@NonNull AuthenticationCallback callback,
int userId) {
+ authenticateUserForOperation(cancel, executor, callback, userId, 0 /* operationId */);
+ }
+
+ /**
+ * Authenticates for the given user and keystore operation.
+ *
+ * @param cancel An object that can be used to cancel authentication
+ * @param executor An executor to handle callback events
+ * @param callback An object to receive authentication events
+ * @param userId The user to authenticate
+ * @param operationId The keystore operation associated with authentication
+ *
+ * @hide
+ */
+ @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+ public void authenticateUserForOperation(
+ @NonNull CancellationSignal cancel,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull AuthenticationCallback callback,
+ int userId,
+ long operationId) {
if (cancel == null) {
throw new IllegalArgumentException("Must supply a cancellation signal");
}
@@ -787,7 +823,7 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
if (callback == null) {
throw new IllegalArgumentException("Must supply a callback");
}
- authenticateInternal(null /* crypto */, cancel, executor, callback, userId);
+ authenticateInternal(operationId, cancel, executor, callback, userId);
}
/**
@@ -912,11 +948,31 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
}
}
- private void authenticateInternal(@Nullable CryptoObject crypto,
+ private void authenticateInternal(
+ @Nullable CryptoObject crypto,
@NonNull CancellationSignal cancel,
@NonNull @CallbackExecutor Executor executor,
@NonNull AuthenticationCallback callback,
int userId) {
+
+ mCryptoObject = crypto;
+ final long operationId = crypto != null ? crypto.getOpId() : 0L;
+ authenticateInternal(operationId, cancel, executor, callback, userId);
+ }
+
+ private void authenticateInternal(
+ long operationId,
+ @NonNull CancellationSignal cancel,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull AuthenticationCallback callback,
+ int userId) {
+
+ // Ensure we don't return the wrong crypto object as an auth result.
+ if (mCryptoObject != null && mCryptoObject.getOpId() != operationId) {
+ Log.w(TAG, "CryptoObject operation ID does not match argument; setting field to null");
+ mCryptoObject = null;
+ }
+
try {
if (cancel.isCanceled()) {
Log.w(TAG, "Authentication already canceled");
@@ -925,13 +981,11 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
cancel.setOnCancelListener(new OnAuthenticationCancelListener());
}
- mCryptoObject = crypto;
mExecutor = executor;
mAuthenticationCallback = callback;
- final long operationId = crypto != null ? crypto.getOpId() : 0;
final PromptInfo promptInfo;
- if (crypto != null) {
+ if (operationId != 0L) {
// Allowed authenticators should default to BIOMETRIC_STRONG for crypto auth.
// Note that we use a new PromptInfo here so as to not overwrite the application's
// preference, since it is possible that the same prompt configuration be used
@@ -952,10 +1006,9 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan
} catch (RemoteException e) {
Log.e(TAG, "Remote exception while authenticating", e);
- mExecutor.execute(() -> {
- callback.onAuthenticationError(BiometricPrompt.BIOMETRIC_ERROR_HW_UNAVAILABLE,
- mContext.getString(R.string.biometric_error_hw_unavailable));
- });
+ mExecutor.execute(() -> callback.onAuthenticationError(
+ BiometricPrompt.BIOMETRIC_ERROR_HW_UNAVAILABLE,
+ mContext.getString(R.string.biometric_error_hw_unavailable)));
}
}
}
diff --git a/core/java/android/hardware/biometrics/PromptInfo.java b/core/java/android/hardware/biometrics/PromptInfo.java
index c2eff7de832b..0e99f31d3b52 100644
--- a/core/java/android/hardware/biometrics/PromptInfo.java
+++ b/core/java/android/hardware/biometrics/PromptInfo.java
@@ -40,6 +40,7 @@ public class PromptInfo implements Parcelable {
private @BiometricManager.Authenticators.Types int mAuthenticators;
private boolean mDisallowBiometricsIfPolicyExists;
private boolean mReceiveSystemEvents;
+ private int mSensorId = -1;
public PromptInfo() {
@@ -59,6 +60,7 @@ public class PromptInfo implements Parcelable {
mAuthenticators = in.readInt();
mDisallowBiometricsIfPolicyExists = in.readBoolean();
mReceiveSystemEvents = in.readBoolean();
+ mSensorId = in.readInt();
}
public static final Creator<PromptInfo> CREATOR = new Creator<PromptInfo>() {
@@ -93,6 +95,7 @@ public class PromptInfo implements Parcelable {
dest.writeInt(mAuthenticators);
dest.writeBoolean(mDisallowBiometricsIfPolicyExists);
dest.writeBoolean(mReceiveSystemEvents);
+ dest.writeInt(mSensorId);
}
public boolean containsPrivateApiConfigurations() {
@@ -166,6 +169,10 @@ public class PromptInfo implements Parcelable {
mReceiveSystemEvents = receiveSystemEvents;
}
+ public void setSensorId(int sensorId) {
+ mSensorId = sensorId;
+ }
+
// Getters
public CharSequence getTitle() {
@@ -226,4 +233,8 @@ public class PromptInfo implements Parcelable {
public boolean isReceiveSystemEvents() {
return mReceiveSystemEvents;
}
+
+ public int getSensorId() {
+ return mSensorId;
+ }
}
diff --git a/core/java/android/hardware/devicestate/DeviceStateManager.java b/core/java/android/hardware/devicestate/DeviceStateManager.java
index 29a6ee278d9c..f175e7b00b7e 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManager.java
+++ b/core/java/android/hardware/devicestate/DeviceStateManager.java
@@ -16,8 +16,12 @@
package android.hardware.devicestate;
+import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.content.Context;
import java.util.concurrent.Executor;
@@ -28,13 +32,19 @@ import java.util.concurrent.Executor;
*
* @hide
*/
+@TestApi
@SystemService(Context.DEVICE_STATE_SERVICE)
public final class DeviceStateManager {
- /** Invalid device state. */
+ /**
+ * Invalid device state.
+ *
+ * @hide
+ */
public static final int INVALID_DEVICE_STATE = -1;
- private DeviceStateManagerGlobal mGlobal;
+ private final DeviceStateManagerGlobal mGlobal;
+ /** @hide */
public DeviceStateManager() {
DeviceStateManagerGlobal global = DeviceStateManagerGlobal.getInstance();
if (global == null) {
@@ -45,23 +55,73 @@ public final class DeviceStateManager {
}
/**
+ * Returns the list of device states that are supported and can be requested with
+ * {@link #requestState(DeviceStateRequest, Executor, DeviceStateRequest.Callback)}.
+ */
+ @NonNull
+ public int[] getSupportedStates() {
+ return mGlobal.getSupportedStates();
+ }
+
+ /**
+ * Submits a {@link DeviceStateRequest request} to modify the device state.
+ * <p>
+ * By default, the request is kept active until a call to
+ * {@link #cancelRequest(DeviceStateRequest)} or until one of the following occurs:
+ * <ul>
+ * <li>Another processes submits a request succeeding this request in which case the request
+ * will be suspended until the interrupting request is canceled.
+ * <li>The requested state has become unsupported.
+ * <li>The process submitting the request dies.
+ * </ul>
+ * However, this behavior can be changed by setting flags on the {@link DeviceStateRequest}.
+ *
+ * @throws IllegalArgumentException if the requested state is unsupported.
+ * @throws SecurityException if the {@link android.Manifest.permission#CONTROL_DEVICE_STATE}
+ * permission is not held.
+ *
+ * @see DeviceStateRequest
+ */
+ @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE)
+ public void requestState(@NonNull DeviceStateRequest request,
+ @Nullable @CallbackExecutor Executor executor,
+ @Nullable DeviceStateRequest.Callback callback) {
+ mGlobal.requestState(request, callback, executor);
+ }
+
+ /**
+ * Cancels a {@link DeviceStateRequest request} previously submitted with a call to
+ * {@link #requestState(DeviceStateRequest, Executor, DeviceStateRequest.Callback)}.
+ * <p>
+ * This method is noop if the {@code request} has not been submitted with a call to
+ * {@link #requestState(DeviceStateRequest, Executor, DeviceStateRequest.Callback)}.
+ *
+ * @throws SecurityException if the {@link android.Manifest.permission#CONTROL_DEVICE_STATE}
+ * permission is not held.
+ */
+ @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_STATE)
+ public void cancelRequest(@NonNull DeviceStateRequest request) {
+ mGlobal.cancelRequest(request);
+ }
+
+ /**
* Registers a listener to receive notifications about changes in device state.
*
- * @param listener the listener to register.
* @param executor the executor to process notifications.
+ * @param listener the listener to register.
*
* @see DeviceStateListener
*/
- public void registerDeviceStateListener(@NonNull DeviceStateListener listener,
- @NonNull Executor executor) {
+ public void addDeviceStateListener(@NonNull @CallbackExecutor Executor executor,
+ @NonNull DeviceStateListener listener) {
mGlobal.registerDeviceStateListener(listener, executor);
}
/**
* Unregisters a listener previously registered with
- * {@link #registerDeviceStateListener(DeviceStateListener, Executor)}.
+ * {@link #addDeviceStateListener(Executor, DeviceStateListener)}.
*/
- public void unregisterDeviceStateListener(@NonNull DeviceStateListener listener) {
+ public void removeDeviceStateListener(@NonNull DeviceStateListener listener) {
mGlobal.unregisterDeviceStateListener(listener);
}
diff --git a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
index c8905038d056..b9ae88ea840f 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
+++ b/core/java/android/hardware/devicestate/DeviceStateManagerGlobal.java
@@ -20,9 +20,11 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.devicestate.DeviceStateManager.DeviceStateListener;
+import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.util.ArrayMap;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -67,6 +69,9 @@ public final class DeviceStateManagerGlobal {
@GuardedBy("mLock")
private final ArrayList<DeviceStateListenerWrapper> mListeners = new ArrayList<>();
+ @GuardedBy("mLock")
+ private final ArrayMap<IBinder, DeviceStateRequestWrapper> mRequests = new ArrayMap<>();
+
@Nullable
@GuardedBy("mLock")
private Integer mLastReceivedState;
@@ -77,9 +82,84 @@ public final class DeviceStateManagerGlobal {
}
/**
+ * Returns the set of supported device states.
+ *
+ * @see DeviceStateManager#getSupportedStates()
+ */
+ public int[] getSupportedStates() {
+ try {
+ return mDeviceStateManager.getSupportedDeviceStates();
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Submits a {@link DeviceStateRequest request} to modify the device state.
+ *
+ * @see DeviceStateManager#requestState(DeviceStateRequest,
+ * Executor, DeviceStateRequest.Callback)
+ * @see DeviceStateRequest
+ */
+ public void requestState(@NonNull DeviceStateRequest request,
+ @Nullable DeviceStateRequest.Callback callback, @Nullable Executor executor) {
+ if (callback == null && executor != null) {
+ throw new IllegalArgumentException("Callback must be supplied with executor.");
+ } else if (executor == null && callback != null) {
+ throw new IllegalArgumentException("Executor must be supplied with callback.");
+ }
+
+ synchronized (mLock) {
+ registerCallbackIfNeededLocked();
+
+ if (findRequestTokenLocked(request) != null) {
+ // This request has already been submitted.
+ return;
+ }
+
+ // Add the request wrapper to the mRequests array before requesting the state as the
+ // callback could be triggered immediately if the mDeviceStateManager IBinder is in the
+ // same process as this instance.
+ IBinder token = new Binder();
+ mRequests.put(token, new DeviceStateRequestWrapper(request, callback, executor));
+
+ try {
+ mDeviceStateManager.requestState(token, request.getState(), request.getFlags());
+ } catch (RemoteException ex) {
+ mRequests.remove(token);
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Cancels a {@link DeviceStateRequest request} previously submitted with a call to
+ * {@link #requestState(DeviceStateRequest, DeviceStateRequest.Callback, Executor)}.
+ *
+ * @see DeviceStateManager#cancelRequest(DeviceStateRequest)
+ */
+ public void cancelRequest(@NonNull DeviceStateRequest request) {
+ synchronized (mLock) {
+ registerCallbackIfNeededLocked();
+
+ final IBinder token = findRequestTokenLocked(request);
+ if (token == null) {
+ // This request has not been submitted.
+ return;
+ }
+
+ try {
+ mDeviceStateManager.cancelRequest(token);
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
* Registers a listener to receive notifications about changes in device state.
*
- * @see DeviceStateManager#registerDeviceStateListener(DeviceStateListener, Executor)
+ * @see DeviceStateManager#addDeviceStateListener(Executor, DeviceStateListener)
*/
@VisibleForTesting(visibility = Visibility.PACKAGE)
public void registerDeviceStateListener(@NonNull DeviceStateListener listener,
@@ -112,7 +192,7 @@ public final class DeviceStateManagerGlobal {
* Unregisters a listener previously registered with
* {@link #registerDeviceStateListener(DeviceStateListener, Executor)}.
*
- * @see DeviceStateManager#registerDeviceStateListener(DeviceStateListener, Executor)
+ * @see DeviceStateManager#addDeviceStateListener(Executor, DeviceStateListener)
*/
@VisibleForTesting(visibility = Visibility.PACKAGE)
public void unregisterDeviceStateListener(DeviceStateListener listener) {
@@ -144,6 +224,17 @@ public final class DeviceStateManagerGlobal {
return -1;
}
+ @Nullable
+ private IBinder findRequestTokenLocked(@NonNull DeviceStateRequest request) {
+ for (int i = 0; i < mRequests.size(); i++) {
+ if (mRequests.valueAt(i).mRequest.equals(request)) {
+ return mRequests.keyAt(i);
+ }
+ }
+ return null;
+ }
+
+ /** Handles a call from the server that the device state has changed. */
private void handleDeviceStateChanged(int newDeviceState) {
ArrayList<DeviceStateListenerWrapper> listeners;
synchronized (mLock) {
@@ -156,11 +247,68 @@ public final class DeviceStateManagerGlobal {
}
}
+ /**
+ * Handles a call from the server that a request for the supplied {@code token} has become
+ * active.
+ */
+ private void handleRequestActive(IBinder token) {
+ DeviceStateRequestWrapper request;
+ synchronized (mLock) {
+ request = mRequests.get(token);
+ }
+ if (request != null) {
+ request.notifyRequestActive();
+ }
+ }
+
+ /**
+ * Handles a call from the server that a request for the supplied {@code token} has become
+ * suspended.
+ */
+ private void handleRequestSuspended(IBinder token) {
+ DeviceStateRequestWrapper request;
+ synchronized (mLock) {
+ request = mRequests.get(token);
+ }
+ if (request != null) {
+ request.notifyRequestSuspended();
+ }
+ }
+
+ /**
+ * Handles a call from the server that a request for the supplied {@code token} has become
+ * canceled.
+ */
+ private void handleRequestCanceled(IBinder token) {
+ DeviceStateRequestWrapper request;
+ synchronized (mLock) {
+ request = mRequests.remove(token);
+ }
+ if (request != null) {
+ request.notifyRequestCanceled();
+ }
+ }
+
private final class DeviceStateManagerCallback extends IDeviceStateManagerCallback.Stub {
@Override
public void onDeviceStateChanged(int deviceState) {
handleDeviceStateChanged(deviceState);
}
+
+ @Override
+ public void onRequestActive(IBinder token) {
+ handleRequestActive(token);
+ }
+
+ @Override
+ public void onRequestSuspended(IBinder token) {
+ handleRequestSuspended(token);
+ }
+
+ @Override
+ public void onRequestCanceled(IBinder token) {
+ handleRequestCanceled(token);
+ }
}
private static final class DeviceStateListenerWrapper {
@@ -176,4 +324,43 @@ public final class DeviceStateManagerGlobal {
mExecutor.execute(() -> mDeviceStateListener.onDeviceStateChanged(newDeviceState));
}
}
+
+ private static final class DeviceStateRequestWrapper {
+ private final DeviceStateRequest mRequest;
+ @Nullable
+ private final DeviceStateRequest.Callback mCallback;
+ @Nullable
+ private final Executor mExecutor;
+
+ DeviceStateRequestWrapper(@NonNull DeviceStateRequest request,
+ @Nullable DeviceStateRequest.Callback callback, @Nullable Executor executor) {
+ mRequest = request;
+ mCallback = callback;
+ mExecutor = executor;
+ }
+
+ void notifyRequestActive() {
+ if (mCallback == null) {
+ return;
+ }
+
+ mExecutor.execute(() -> mCallback.onRequestActivated(mRequest));
+ }
+
+ void notifyRequestSuspended() {
+ if (mCallback == null) {
+ return;
+ }
+
+ mExecutor.execute(() -> mCallback.onRequestSuspended(mRequest));
+ }
+
+ void notifyRequestCanceled() {
+ if (mCallback == null) {
+ return;
+ }
+
+ mExecutor.execute(() -> mCallback.onRequestSuspended(mRequest));
+ }
+ }
}
diff --git a/core/java/android/hardware/devicestate/DeviceStateRequest.java b/core/java/android/hardware/devicestate/DeviceStateRequest.java
new file mode 100644
index 000000000000..70f7002597ed
--- /dev/null
+++ b/core/java/android/hardware/devicestate/DeviceStateRequest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.devicestate;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.TestApi;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.Executor;
+
+/**
+ * A request to alter the state of the device managed by {@link DeviceStateManager}.
+ * <p>
+ * Once constructed, a {@link DeviceStateRequest request} can be submitted with a call to
+ * {@link DeviceStateManager#requestState(DeviceStateRequest, Executor,
+ * DeviceStateRequest.Callback)}.
+ * <p>
+ * By default, the request is kept active until a call to
+ * {@link DeviceStateManager#cancelRequest(DeviceStateRequest)} or until one of the following
+ * occurs:
+ * <ul>
+ * <li>Another processes submits a request succeeding this request in which case the request
+ * will be suspended until the interrupting request is canceled.
+ * <li>The requested state has become unsupported.
+ * <li>The process submitting the request dies.
+ * </ul>
+ * However, this behavior can be changed by setting flags on the request. For example, the
+ * {@link #FLAG_CANCEL_WHEN_BASE_CHANGES} flag will extend this behavior to also cancel the
+ * request whenever the base (non-override) device state changes.
+ *
+ * @see DeviceStateManager
+ *
+ * @hide
+ */
+@TestApi
+public final class DeviceStateRequest {
+ /**
+ * Flag that indicates the request should be canceled automatically when the base
+ * (non-override) device state changes. Useful when the requestor only wants the request to
+ * remain active while the base state remains constant and automatically cancel when the user
+ * manipulates the device into a different state.
+ */
+ public static final int FLAG_CANCEL_WHEN_BASE_CHANGES = 1 << 0;
+
+ /** @hide */
+ @IntDef(prefix = {"FLAG_"}, flag = true, value = {
+ FLAG_CANCEL_WHEN_BASE_CHANGES,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RequestFlags {}
+
+ /**
+ * Creates a new {@link Builder} for a {@link DeviceStateRequest}. Must be one of the supported
+ * states for the device which can be queried with a call to
+ * {@link DeviceStateManager#getSupportedStates()}.
+ *
+ * @param requestedState the device state being requested.
+ */
+ @NonNull
+ public static Builder newBuilder(int requestedState) {
+ return new Builder(requestedState);
+ }
+
+ /**
+ * Builder for {@link DeviceStateRequest}. An instance can be obtained through
+ * {@link #newBuilder(int)}.
+ */
+ public static final class Builder {
+ private final int mRequestedState;
+ private int mFlags;
+
+ private Builder(int requestedState) {
+ mRequestedState = requestedState;
+ }
+
+ /**
+ * Sets the flag bits provided within {@code flags} with all other bits remaining
+ * unchanged.
+ */
+ @NonNull
+ public Builder setFlags(@RequestFlags int flags) {
+ mFlags |= flags;
+ return this;
+ }
+
+ /**
+ * Returns a new {@link DeviceStateRequest} object whose state matches the state set on the
+ * builder.
+ */
+ @NonNull
+ public DeviceStateRequest build() {
+ return new DeviceStateRequest(mRequestedState, mFlags);
+ }
+ }
+
+ /** Callback to track the status of a request. */
+ public interface Callback {
+ /**
+ * Called to indicate the request has become active and the device state will match the
+ * requested state.
+ * <p>
+ * Guaranteed to be called after a call to
+ * {@link DeviceStateManager.DeviceStateListener#onDeviceStateChanged(int)} with a state
+ * matching the requested state.
+ */
+ default void onRequestActivated(@NonNull DeviceStateRequest request) {}
+
+ /**
+ * Called to indicate the request has been temporarily suspended.
+ * <p>
+ * Guaranteed to be called before a call to
+ * {@link DeviceStateManager.DeviceStateListener#onDeviceStateChanged(int)}.
+ */
+ default void onRequestSuspended(@NonNull DeviceStateRequest request) {}
+
+ /**
+ * Called to indicate the request has been canceled. The request can be resubmitted with
+ * another call to {@link DeviceStateManager#requestState(DeviceStateRequest, Executor,
+ * DeviceStateRequest.Callback)}.
+ * <p>
+ * Guaranteed to be called before a call to
+ * {@link DeviceStateManager.DeviceStateListener#onDeviceStateChanged(int)}.
+ * <p>
+ * Note: A call to {@link #onRequestSuspended(DeviceStateRequest)} is not guaranteed to
+ * occur before this method.
+ */
+ default void onRequestCanceled(@NonNull DeviceStateRequest request) {}
+ }
+
+ private final int mRequestedState;
+ @RequestFlags
+ private final int mFlags;
+
+ private DeviceStateRequest(int requestedState, @RequestFlags int flags) {
+ mRequestedState = requestedState;
+ mFlags = flags;
+ }
+
+ public int getState() {
+ return mRequestedState;
+ }
+
+ @RequestFlags
+ public int getFlags() {
+ return mFlags;
+ }
+}
diff --git a/core/java/android/hardware/devicestate/IDeviceStateManager.aidl b/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
index a157b3311ca5..323ad21e4884 100644
--- a/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
+++ b/core/java/android/hardware/devicestate/IDeviceStateManager.aidl
@@ -20,5 +20,45 @@ import android.hardware.devicestate.IDeviceStateManagerCallback;
/** @hide */
interface IDeviceStateManager {
+ /**
+ * Registers a callback to receive notifications from the device state manager. Only one
+ * callback can be registered per-process.
+ * <p>
+ * As the callback mechanism is used to alert the caller of changes to request status a callback
+ * <b>MUST</b> be registered before calling {@link #requestState(IBinder, int, int)} or
+ * {@link #cancelRequest(IBinder)}. Otherwise an exception will be thrown.
+ *
+ * @throws SecurityException if a callback is already registered for the calling process.
+ */
void registerCallback(in IDeviceStateManagerCallback callback);
+
+ /** Returns the array of supported device state identifiers. */
+ int[] getSupportedDeviceStates();
+
+ /**
+ * Requests that the device enter the supplied {@code state}. A callback <b>MUST</b> have been
+ * previously registered with {@link #registerCallback(IDeviceStateManagerCallback)} before a
+ * call to this method.
+ *
+ * @param token the request token previously registered with
+ * {@link #requestState(IBinder, int, int)}
+ *
+ * @throws IllegalStateException if a callback has not yet been registered for the calling
+ * process.
+ * @throws IllegalStateException if the supplied {@code token} has already been registered.
+ * @throws IllegalArgumentException if the supplied {@code state} is not supported.
+ */
+ void requestState(IBinder token, int state, int flags);
+
+ /**
+ * Cancels a request previously submitted with a call to
+ * {@link #requestState(IBinder, int, int)}.
+ *
+ * @param token the request token previously registered with
+ * {@link #requestState(IBinder, int, int)}
+ *
+ * @throws IllegalStateException if the supplied {@code token} has not been previously
+ * requested.
+ */
+ void cancelRequest(IBinder token);
}
diff --git a/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl b/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl
index d1c581361b62..ee2a071741ef 100644
--- a/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl
+++ b/core/java/android/hardware/devicestate/IDeviceStateManagerCallback.aidl
@@ -18,5 +18,42 @@ package android.hardware.devicestate;
/** @hide */
interface IDeviceStateManagerCallback {
+ /**
+ * Called in response to a change in device state. Guaranteed to be called once with the initial
+ * value on registration of the callback.
+ *
+ * @param deviceState the new state of the device.
+ */
oneway void onDeviceStateChanged(int deviceState);
+
+ /**
+ * Called to notify the callback that a request has become active. Guaranteed to be called
+ * after a subsequent call to {@link #onDeviceStateChanged(int)} if the request becoming active
+ * resulted in a device state change.
+ *
+ * @param token the request token previously registered with
+ * {@link IDeviceStateManager#requestState(IBinder, int, int)}
+ */
+ oneway void onRequestActive(IBinder token);
+
+ /**
+ * Called to notify the callback that a request has become suspended. Guaranteed to be called
+ * before a subsequent call to {@link #onDeviceStateChanged(int)} if the request becoming
+ * suspended resulted in a device state change.
+ *
+ * @param token the request token previously registered with
+ * {@link IDeviceStateManager#requestState(IBinder, int, int)}
+ */
+ oneway void onRequestSuspended(IBinder token);
+
+ /**
+ * Called to notify the callback that a request has become canceled. No further callbacks will
+ * be triggered for this request. Guaranteed to be called before a subsequent call to
+ * {@link #onDeviceStateChanged(int)} if the request becoming canceled resulted in a device
+ * state change.
+ *
+ * @param token the request token previously registered with
+ * {@link IDeviceStateManager#requestState(IBinder, int, int)}
+ */
+ oneway void onRequestCanceled(IBinder token);
}
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index d93286531465..188a2a47fca0 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -93,17 +93,26 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
private static final int MSG_UDFPS_POINTER_UP = 109;
/**
- * Request authentication with any single sensor.
* @hide
*/
- public static final int SENSOR_ID_ANY = -1;
+ public static final int ENROLL_FIND_SENSOR = 1;
+ /**
+ * @hide
+ */
+ public static final int ENROLL_ENROLL = 2;
/**
* @hide
*/
- @IntDef({SENSOR_ID_ANY})
+ @IntDef({ENROLL_FIND_SENSOR, ENROLL_ENROLL})
@Retention(RetentionPolicy.SOURCE)
- public @interface SensorId {}
+ public @interface EnrollReason {}
+
+ /**
+ * Request authentication with any single sensor.
+ * @hide
+ */
+ public static final int SENSOR_ID_ANY = -1;
private IFingerprintService mService;
private Context mContext;
@@ -508,8 +517,8 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
*/
@RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})
public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,
- @NonNull AuthenticationCallback callback, Handler handler, @SensorId int sensorId,
- int userId) {
+ @NonNull AuthenticationCallback callback, Handler handler, int sensorId, int userId) {
+
if (callback == null) {
throw new IllegalArgumentException("Must supply an authentication callback");
}
@@ -590,7 +599,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
*/
@RequiresPermission(MANAGE_FINGERPRINT)
public void enroll(byte [] hardwareAuthToken, CancellationSignal cancel, int userId,
- EnrollmentCallback callback, boolean shouldLogMetrics) {
+ EnrollmentCallback callback, @EnrollReason int enrollReason) {
if (userId == UserHandle.USER_CURRENT) {
userId = getCurrentUserId();
}
@@ -611,7 +620,7 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
try {
mEnrollmentCallback = callback;
mService.enroll(mToken, hardwareAuthToken, userId, mServiceReceiver,
- mContext.getOpPackageName(), shouldLogMetrics);
+ mContext.getOpPackageName(), enrollReason);
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception in enroll: ", e);
// Though this may not be a hardware issue, it will cause apps to give up or try
@@ -653,15 +662,12 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
*/
@RequiresPermission(MANAGE_FINGERPRINT)
public void generateChallenge(int userId, GenerateChallengeCallback callback) {
- final List<FingerprintSensorPropertiesInternal> fingerprintSensorProperties =
- getSensorPropertiesInternal();
- if (fingerprintSensorProperties.isEmpty()) {
+ final FingerprintSensorPropertiesInternal sensorProps = getFirstFingerprintSensor();
+ if (sensorProps == null) {
Slog.e(TAG, "No sensors");
return;
}
-
- final int sensorId = fingerprintSensorProperties.get(0).sensorId;
- generateChallenge(sensorId, userId, callback);
+ generateChallenge(sensorProps.sensorId, userId, callback);
}
/**
@@ -681,18 +687,18 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
*/
@RequiresPermission(MANAGE_FINGERPRINT)
public void revokeChallenge(int userId, long challenge) {
- if (mService != null) try {
- final List<FingerprintSensorPropertiesInternal> fingerprintSensorProperties =
- getSensorPropertiesInternal();
- if (fingerprintSensorProperties.isEmpty()) {
- Slog.e(TAG, "No sensors");
- return;
+ if (mService != null) {
+ try {
+ final FingerprintSensorPropertiesInternal sensorProps = getFirstFingerprintSensor();
+ if (sensorProps == null) {
+ Slog.e(TAG, "No sensors");
+ return;
+ }
+ mService.revokeChallenge(mToken, sensorProps.sensorId, userId,
+ mContext.getOpPackageName(), challenge);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- final int sensorId = fingerprintSensorProperties.get(0).sensorId;
- mService.revokeChallenge(mToken, sensorId, userId, mContext.getOpPackageName(),
- challenge);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
}
}
@@ -1161,6 +1167,12 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing
}
}
+ @Nullable
+ private FingerprintSensorPropertiesInternal getFirstFingerprintSensor() {
+ final List<FingerprintSensorPropertiesInternal> allSensors = getSensorPropertiesInternal();
+ return allSensors.isEmpty() ? null : allSensors.get(0);
+ }
+
private void cancelEnrollment() {
if (mService != null) try {
mService.cancelEnrollment(mToken);
diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
index f097651e1894..663a70452b24 100644
--- a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
+++ b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
@@ -109,9 +109,10 @@ public class FingerprintSensorPropertiesInternal extends SensorPropertiesInterna
this.sensorLocationY = props[1];
this.sensorRadius = props[2];
} else {
- this.sensorLocationX = 0;
- this.sensorLocationY = 0;
- this.sensorRadius = 0;
+ // Fake coordinates that could be used for the fake UDFPS mode.
+ this.sensorLocationX = 540;
+ this.sensorLocationY = 1636;
+ this.sensorRadius = 130;
}
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 3657a83039ad..8888247e2823 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -78,7 +78,7 @@ interface IFingerprintService {
// Start fingerprint enrollment
void enroll(IBinder token, in byte [] hardwareAuthToken, int userId, IFingerprintServiceReceiver receiver,
- String opPackageName, boolean shouldLogMetrics);
+ String opPackageName, int enrollReason);
// Cancel enrollment in progress
void cancelEnrollment(IBinder token);
diff --git a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
index c093489d4494..81c7d894ee09 100644
--- a/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
+++ b/core/java/android/hardware/fingerprint/IUdfpsOverlayController.aidl
@@ -21,10 +21,11 @@ package android.hardware.fingerprint;
*/
oneway interface IUdfpsOverlayController {
const int REASON_UNKNOWN = 0;
- const int REASON_ENROLL = 1;
- const int REASON_AUTH_BP = 2; // BiometricPrompt
- const int REASON_AUTH_FPM_KEYGUARD = 3; // FingerprintManager usage from Keyguard
- const int REASON_AUTH_FPM_OTHER = 4; // Other FingerprintManager usage
+ const int REASON_ENROLL_FIND_SENSOR = 1;
+ const int REASON_ENROLL_ENROLLING = 2;
+ const int REASON_AUTH_BP = 3; // BiometricPrompt
+ const int REASON_AUTH_FPM_KEYGUARD = 4; // FingerprintManager usage from Keyguard
+ const int REASON_AUTH_FPM_OTHER = 5; // Other FingerprintManager usage
// Shows the overlay.
void showUdfpsOverlay(int sensorId, int reason);
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 44a2e97e6f04..7e2be01feb01 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1732,7 +1732,7 @@ public class InputMethodService extends AbstractInputMethodService {
// If app window has portrait orientation, regardless of what display orientation
// is, IME shouldn't use fullscreen-mode.
|| (mInputEditorInfo.internalImeOptions
- & EditorInfo.IME_FLAG_APP_WINDOW_PORTRAIT) != 0) {
+ & EditorInfo.IME_INTERNAL_FLAG_APP_WINDOW_PORTRAIT) != 0) {
return false;
}
return true;
diff --git a/core/java/android/net/OemNetworkPreferences.java b/core/java/android/net/OemNetworkPreferences.java
index 6a8e3f9c01f2..5e56164cc82c 100644
--- a/core/java/android/net/OemNetworkPreferences.java
+++ b/core/java/android/net/OemNetworkPreferences.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,14 +18,14 @@ package android.net;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.os.Bundle;
import android.os.Parcelable;
-import android.util.SparseArray;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
import java.util.Collections;
-import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Objects;
/** @hide */
@@ -60,16 +60,16 @@ public final class OemNetworkPreferences implements Parcelable {
public static final int OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY = 4;
@NonNull
- private final SparseArray<List<String>> mNetworkMappings;
+ private final Bundle mNetworkMappings;
@NonNull
- public SparseArray<List<String>> getNetworkPreferences() {
- return mNetworkMappings.clone();
+ public Map<String, Integer> getNetworkPreferences() {
+ return convertToUnmodifiableMap(mNetworkMappings);
}
- private OemNetworkPreferences(@NonNull SparseArray<List<String>> networkMappings) {
+ private OemNetworkPreferences(@NonNull final Bundle networkMappings) {
Objects.requireNonNull(networkMappings);
- mNetworkMappings = networkMappings.clone();
+ mNetworkMappings = (Bundle) networkMappings.clone();
}
@Override
@@ -99,26 +99,45 @@ public final class OemNetworkPreferences implements Parcelable {
* @hide
*/
public static final class Builder {
- private final SparseArray<List<String>> mNetworkMappings;
+ private final Bundle mNetworkMappings;
public Builder() {
- mNetworkMappings = new SparseArray<>();
+ mNetworkMappings = new Bundle();
+ }
+
+ public Builder(@NonNull final OemNetworkPreferences preferences) {
+ Objects.requireNonNull(preferences);
+ mNetworkMappings = (Bundle) preferences.mNetworkMappings.clone();
}
/**
- * Add a network preference for a list of packages.
+ * Add a network preference for a given package. Previously stored values for the given
+ * package will be overwritten.
*
- * @param preference the desired network preference to use
- * @param packages full package names (e.g.: "com.google.apps.contacts") for apps to use
- * the given preference
+ * @param packageName full package name (e.g.: "com.google.apps.contacts") of the app
+ * to use the given preference
+ * @param preference the desired network preference to use
* @return The builder to facilitate chaining.
*/
@NonNull
- public Builder addNetworkPreference(@OemNetworkPreference final int preference,
- @NonNull List<String> packages) {
- Objects.requireNonNull(packages);
- mNetworkMappings.put(preference,
- Collections.unmodifiableList(new ArrayList<>(packages)));
+ public Builder addNetworkPreference(@NonNull final String packageName,
+ @OemNetworkPreference final int preference) {
+ Objects.requireNonNull(packageName);
+ mNetworkMappings.putInt(packageName, preference);
+ return this;
+ }
+
+ /**
+ * Remove a network preference for a given package.
+ *
+ * @param packageName full package name (e.g.: "com.google.apps.contacts") of the app to
+ * remove a preference for.
+ * @return The builder to facilitate chaining.
+ */
+ @NonNull
+ public Builder removeNetworkPreference(@NonNull final String packageName) {
+ Objects.requireNonNull(packageName);
+ mNetworkMappings.remove(packageName);
return this;
}
@@ -131,6 +150,14 @@ public final class OemNetworkPreferences implements Parcelable {
}
}
+ private static Map<String, Integer> convertToUnmodifiableMap(@NonNull final Bundle bundle) {
+ final Map<String, Integer> networkPreferences = new HashMap<>();
+ for (final String key : bundle.keySet()) {
+ networkPreferences.put(key, bundle.getInt(key));
+ }
+ return Collections.unmodifiableMap(networkPreferences);
+ }
+
/** @hide */
@IntDef(prefix = "OEM_NETWORK_PREFERENCE_", value = {
OEM_NETWORK_PREFERENCE_DEFAULT,
@@ -168,7 +195,7 @@ public final class OemNetworkPreferences implements Parcelable {
@Override
public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
- dest.writeSparseArray(mNetworkMappings);
+ dest.writeBundle(mNetworkMappings);
}
@Override
@@ -187,7 +214,7 @@ public final class OemNetworkPreferences implements Parcelable {
@Override
public OemNetworkPreferences createFromParcel(@NonNull android.os.Parcel in) {
return new OemNetworkPreferences(
- in.readSparseArray(getClass().getClassLoader()));
+ in.readBundle(getClass().getClassLoader()));
}
};
}
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 7e50ebc419dd..2119e7b951cd 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -326,6 +326,19 @@ public final class UserHandle implements Parcelable {
}
/**
+ * Returns the uid that is composed from the userHandle and the appId.
+ *
+ * @param userHandle the UserHandle to compose the uid
+ * @param appId the AppId to compose the uid
+ * @return the uid that is composed from the userHandle and the appId
+ * @hide
+ */
+ @SystemApi
+ public static int getUid(@NonNull UserHandle userHandle, @AppIdInt int appId) {
+ return getUid(userHandle.getIdentifier(), appId);
+ }
+
+ /**
* Returns the app id (or base uid) for a given uid, stripping out the user id from it.
* @hide
*/
diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java
index 7e7057fe56cb..0ff68fc582d8 100644
--- a/core/java/android/os/incremental/IncrementalManager.java
+++ b/core/java/android/os/incremental/IncrementalManager.java
@@ -304,20 +304,16 @@ public final class IncrementalManager {
}
/**
- * Called when a callback wants to stop listen to the loading progress of an installed package.
- * Decrease the count of the callbacks on the associated to the corresponding storage.
- * If the count becomes zero, unregister the storage listener.
+ * Called to stop all listeners from listening to loading progress of an installed package.
* @param codePath Path of the installed package
- * @return True if the package name and associated storage id are valid. False otherwise.
*/
- public boolean unregisterLoadingProgressCallback(@NonNull String codePath,
- @NonNull IPackageLoadingProgressCallback callback) {
+ public void unregisterLoadingProgressCallbacks(@NonNull String codePath) {
final IncrementalStorage storage = openStorage(codePath);
if (storage == null) {
// storage does not exist, package not installed
- return false;
+ return;
}
- return mLoadingProgressCallbacks.unregisterCallback(storage, callback);
+ mLoadingProgressCallbacks.cleanUpCallbacks(storage);
}
private static class LoadingProgressCallbacks extends IStorageLoadingProgressListener.Stub {
@@ -325,7 +321,6 @@ public final class IncrementalManager {
private final SparseArray<RemoteCallbackList<IPackageLoadingProgressCallback>> mCallbacks =
new SparseArray<>();
- // TODO(b/165841827): disable callbacks when app state changes to fully loaded
public void cleanUpCallbacks(@NonNull IncrementalStorage storage) {
final int storageId = storage.getId();
final RemoteCallbackList<IPackageLoadingProgressCallback> callbacksForStorage;
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index c39b8c5eb6d1..a79b197d3faa 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -130,6 +130,15 @@ public final class KeymasterDefs {
public static final int KM_TAG_ASSOCIATED_DATA = Tag.ASSOCIATED_DATA; // KM_BYTES | 1000;
public static final int KM_TAG_NONCE = Tag.NONCE; // KM_BYTES | 1001;
public static final int KM_TAG_MAC_LENGTH = Tag.MAC_LENGTH; // KM_UINT | 1003;
+ public static final int KM_TAG_RESET_SINCE_ID_ROTATION =
+ Tag.RESET_SINCE_ID_ROTATION; // KM_BOOL | 1004
+ public static final int KM_TAG_CONFIRMATION_TOKEN = Tag.CONFIRMATION_TOKEN; // KM_BYTES | 1005;
+ public static final int KM_TAG_CERTIFICATE_SERIAL = Tag.CERTIFICATE_SERIAL; // KM_UINT | 1006;
+ public static final int KM_TAG_CERTIFICATE_SUBJECT = Tag.CERTIFICATE_SUBJECT; // KM_UINT | 1007;
+ public static final int KM_TAG_CERTIFICATE_NOT_BEFORE =
+ Tag.CERTIFICATE_NOT_BEFORE; // KM_DATE | 1008;
+ public static final int KM_TAG_CERTIFICATE_NOT_AFTER =
+ Tag.CERTIFICATE_NOT_AFTER; // KM_DATE | 1009;
// Algorithm values.
public static final int KM_ALGORITHM_RSA = Algorithm.RSA;
@@ -317,6 +326,10 @@ public final class KeymasterDefs {
ErrorCode.HARDWARE_TYPE_UNAVAILABLE; // -68;
public static final int KM_ERROR_DEVICE_LOCKED =
ErrorCode.DEVICE_LOCKED; // -72;
+ public static final int KM_ERROR_MISSING_NOT_BEFORE =
+ ErrorCode.MISSING_NOT_BEFORE; // -80;
+ public static final int KM_ERROR_MISSING_NOT_AFTER =
+ ErrorCode.MISSING_NOT_AFTER; // -80;
public static final int KM_ERROR_UNIMPLEMENTED =
ErrorCode.UNIMPLEMENTED; // -100;
public static final int KM_ERROR_VERSION_MISMATCH =
diff --git a/core/java/android/service/rotationresolver/RotationResolutionRequest.java b/core/java/android/service/rotationresolver/RotationResolutionRequest.java
index 94a6052c246d..8e76e2fc9202 100644
--- a/core/java/android/service/rotationresolver/RotationResolutionRequest.java
+++ b/core/java/android/service/rotationresolver/RotationResolutionRequest.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import android.view.Surface;
/**
* This class represents a request to an {@link RotationResolverService}. The request contains
@@ -54,7 +55,7 @@ public final class RotationResolutionRequest implements Parcelable {
mTimeoutMillis = timeoutMillis;
}
- public int getProposedRotation() {
+ @Surface.Rotation public int getProposedRotation() {
return mProposedRotation;
}
diff --git a/core/java/android/service/rotationresolver/RotationResolverService.java b/core/java/android/service/rotationresolver/RotationResolverService.java
index 593a642b4a38..604dd0ac8298 100644
--- a/core/java/android/service/rotationresolver/RotationResolverService.java
+++ b/core/java/android/service/rotationresolver/RotationResolverService.java
@@ -146,11 +146,8 @@ public abstract class RotationResolverService extends Service {
}
mPendingCallback = new RotationResolverCallbackWrapper(callback, this);
mCancellationSignal = CancellationSignal.fromTransport(transport);
- try {
- onResolveRotation(request, mCancellationSignal, mPendingCallback);
- } catch (UnsupportedOperationException e) {
- reportFailures(callback, ROTATION_RESULT_FAILURE_CANCELLED);
- }
+
+ onResolveRotation(request, mCancellationSignal, mPendingCallback);
}
@MainThread
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 16b45c30b69f..7f45b384ca5f 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -475,9 +475,8 @@ public class DynamicLayout extends Layout {
mObjects.insertAt(0, dirs);
- final int baseLength = mBase.length();
- // Update from 0 characters to whatever the real text is
- reflow(mBase, 0, 0, baseLength);
+ // Update from 0 characters to whatever the displayed text is
+ reflow(mBase, 0, 0, mDisplay.length());
if (mBase instanceof Spannable) {
if (mWatcher == null)
@@ -485,6 +484,7 @@ public class DynamicLayout extends Layout {
// Strip out any watchers for other DynamicLayouts.
final Spannable sp = (Spannable) mBase;
+ final int baseLength = mBase.length();
final ChangeWatcher[] spans = sp.getSpans(0, baseLength, ChangeWatcher.class);
for (int i = 0; i < spans.length; i++) {
sp.removeSpan(spans[i]);
diff --git a/core/java/android/uwb/RangingManager.java b/core/java/android/uwb/RangingManager.java
index 5ac95d49c1bb..c0d818774ba0 100644
--- a/core/java/android/uwb/RangingManager.java
+++ b/core/java/android/uwb/RangingManager.java
@@ -94,7 +94,8 @@ public class RangingManager extends android.uwb.IUwbRangingCallbacks.Stub {
synchronized (this) {
if (!hasSession(sessionHandle)) {
Log.w(TAG,
- "onRangingOpened - received unexpected SessionHandle: " + sessionHandle);
+ "onRangingOpenedFailed - received unexpected SessionHandle: "
+ + sessionHandle);
return;
}
@@ -124,7 +125,7 @@ public class RangingManager extends android.uwb.IUwbRangingCallbacks.Stub {
@RangingChangeReason int reason, PersistableBundle params) {
synchronized (this) {
if (!hasSession(sessionHandle)) {
- Log.w(TAG, "onRangingStartFailed - received unexpected SessionHandle: "
+ Log.w(TAG, "onRangingReconfigureFailed - received unexpected SessionHandle: "
+ sessionHandle);
return;
}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index ae8afca9b5c5..62f4b864c7a8 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -124,16 +124,10 @@ interface IWindowManager
*
* @param token Token to be registered.
* @param type Window type to be used with this token.
- * @param options A bundle used to pass window-related options.
* @param displayId The ID of the display where this token should be added.
- * @param packageName The name of package to request to add window token. Could be {@code null}
- * if callers holds the MANAGE_APP_TOKENS permission.
- * @return {@link WindowManagerGlobal#ADD_OKAY} if the addition was successful, an error code
- * otherwise.
+ * @param options A bundle used to pass window-related options.
*/
- int addWindowTokenWithOptions(IBinder token, int type, int displayId, in Bundle options,
- String packageName);
- void addWindowToken(IBinder token, int type, int displayId);
+ void addWindowToken(IBinder token, int type, int displayId, in Bundle options);
/**
* Remove window token on a specific display.
*
@@ -784,6 +778,10 @@ interface IWindowManager
/**
* Registers a listener for a {@link android.app.WindowContext} to handle configuration changes
* from the server side.
+ * <p>
+ * Note that this API should be invoked after calling
+ * {@link android.app.WindowTokenClient#attachContext(WindowContext)}
+ * </p>
*
* @param clientToken the window context's token
* @param type Window type of the window context
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 749c0dfbaaaa..e1ccc51c71e1 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8740,14 +8740,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Populates a {@link ViewStructure} for content capture.
*
- * <p>This method is called after a view is that is eligible for content capture
- * (for example, if it {@link #isImportantForAutofill()}, an intelligence service is enabled for
- * the user, and the activity rendering the view is enabled for content capture) is laid out and
- * is visible.
- *
- * <p>The populated structure is then passed to the service through
+ * <p>This method is called after a view that is eligible for content capture
+ * (for example, if it {@link #isImportantForContentCapture()}, an intelligence service is
+ * enabled for the user, and the activity rendering the view is enabled for content capture)
+ * is laid out and is visible. The populated structure is then passed to the service through
* {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}.
*
+ * <p>The default implementation of this method sets the most relevant properties based on
+ * related {@link View} methods, and views in the standard Android widgets library also
+ * override it to set their relevant properties. Therefore, if overriding this method, it
+ * is recommended to call {@code super.onProvideContentCaptureStructure()}.
+ *
* <p><b>Note: </b>views that manage a virtual structure under this view must populate just
* the node representing this view and return right away, then asynchronously report (not
* necessarily in the UI thread) when the children nodes appear, disappear or have their text
@@ -8755,7 +8758,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)},
* {@link ContentCaptureSession#notifyViewDisappeared(AutofillId)}, and
* {@link ContentCaptureSession#notifyViewTextChanged(AutofillId, CharSequence)}
- * respectively. The structure for the a child must be created using
+ * respectively. The structure for a child must be created using
* {@link ContentCaptureSession#newVirtualViewStructure(AutofillId, long)}, and the
* {@code autofillId} for a child can be obtained either through
* {@code childStructure.getAutofillId()} or
@@ -8900,7 +8903,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
/**
* Called when assist structure is being retrieved from a view as part of
* {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to
- * generate additional virtual structure under this view. The defaullt implementation
+ * generate additional virtual structure under this view. The default implementation
* uses {@link #getAccessibilityNodeProvider()} to try to generate this from the
* view's virtual accessibility nodes, if any. You can override this for a more
* optimal implementation providing this data.
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 170124e348c9..47ac1ee5b339 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -139,7 +139,6 @@ public final class WindowManagerGlobal {
public static final int ADD_INVALID_DISPLAY = -9;
public static final int ADD_INVALID_TYPE = -10;
public static final int ADD_INVALID_USER = -11;
- public static final int ADD_TOO_MANY_TOKENS = -12;
@UnsupportedAppUsage
private static WindowManagerGlobal sDefaultWindowManager;
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 415b3a766d16..37220fe6870b 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -164,12 +164,12 @@ public class BaseInputConnection implements InputConnection {
/**
* Default implementation calls {@link #finishComposingText()} and
- * {@code setImeTemporarilyConsumesInput(false)}.
+ * {@code setImeConsumesInput(false)}.
*/
@CallSuper
public void closeConnection() {
finishComposingText();
- setImeTemporarilyConsumesInput(false);
+ setImeConsumesInput(false);
}
/**
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index 2df75f6570db..bde4cb7c4fc3 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -299,7 +299,7 @@ public class EditorInfo implements InputType, Parcelable {
* {@link EditorInfo} is using {@link Configuration#ORIENTATION_PORTRAIT} mode.
* @hide
*/
- public static final int IME_FLAG_APP_WINDOW_PORTRAIT = 0x80000000;
+ public static final int IME_INTERNAL_FLAG_APP_WINDOW_PORTRAIT = 0x00000001;
/**
* Generic unspecified type for {@link #imeOptions}.
@@ -321,7 +321,6 @@ public class EditorInfo implements InputType, Parcelable {
* 1 1 IME_ACTION_NEXT
* 11 IME_ACTION_DONE
* 111 IME_ACTION_PREVIOUS
- * 1 IME_FLAG_APP_WINDOW_PORTRAIT
* 1 IME_FLAG_NO_PERSONALIZED_LEARNING
* 1 IME_FLAG_NO_FULLSCREEN
* 1 IME_FLAG_NAVIGATE_PREVIOUS
@@ -356,7 +355,7 @@ public class EditorInfo implements InputType, Parcelable {
* Masks for {@link internalImeOptions}
*
* <pre>
- * 1 IME_FLAG_APP_WINDOW_PORTRAIT
+ * 1 IME_INTERNAL_FLAG_APP_WINDOW_PORTRAIT
* |-------|-------|-------|-------|</pre>
*/
@@ -984,6 +983,7 @@ public class EditorInfo implements InputType, Parcelable {
dest.writeInt(inputType);
dest.writeInt(imeOptions);
dest.writeString(privateImeOptions);
+ dest.writeInt(internalImeOptions);
TextUtils.writeToParcel(actionLabel, dest, flags);
dest.writeInt(actionId);
dest.writeInt(initialSelStart);
@@ -1019,6 +1019,7 @@ public class EditorInfo implements InputType, Parcelable {
res.inputType = source.readInt();
res.imeOptions = source.readInt();
res.privateImeOptions = source.readString();
+ res.internalImeOptions = source.readInt();
res.actionLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
res.actionId = source.readInt();
res.initialSelStart = source.readInt();
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index f3111bdc7471..34a60bbe7642 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -1004,20 +1004,19 @@ public interface InputConnection {
@Nullable Bundle opts);
/**
- * Called by the input method to indicate that it temporarily consumes all input for itself,
- * or no longer does so.
+ * Called by the input method to indicate that it consumes all input for itself, or no longer
+ * does so.
*
- * <p>Editors should reflect that they are temporarily not receiving input by hiding the
- * cursor if {@code imeTemporarilyConsumesInput} is {@code true}, and resume showing the
- * cursor if it is {@code false}.
+ * <p>Editors should reflect that they are not receiving input by hiding the cursor if
+ * {@code imeConsumesInput} is {@code true}, and resume showing the cursor if it is
+ * {@code false}.
*
- * @param imeTemporarilyConsumesInput {@code true} when the IME is temporarily consuming input
- * and the cursor should be hidden, {@code false} when input to the editor resumes and the
- * cursor should be shown again.
+ * @param imeConsumesInput {@code true} when the IME is consuming input and the cursor should be
+ * hidden, {@code false} when input to the editor resumes and the cursor should be shown again.
* @return {@code true} on success, {@code false} if the input connection is no longer valid, or
* the protocol is not supported.
*/
- default boolean setImeTemporarilyConsumesInput(boolean imeTemporarilyConsumesInput) {
+ default boolean setImeConsumesInput(boolean imeConsumesInput) {
return false;
}
}
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index b29149fc1fa0..b1501a4c035c 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -341,7 +341,7 @@ public class InputConnectionWrapper implements InputConnection {
* @throws NullPointerException if the target is {@code null}.
*/
@Override
- public boolean setImeTemporarilyConsumesInput(boolean imeTemporarilyConsumesInput) {
- return mTarget.setImeTemporarilyConsumesInput(imeTemporarilyConsumesInput);
+ public boolean setImeConsumesInput(boolean imeConsumesInput) {
+ return mTarget.setImeConsumesInput(imeConsumesInput);
}
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 8cfbca88c596..fe37c5350511 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -497,9 +497,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private TextUtils.TruncateAt mEllipsize;
// A flag to indicate the cursor was hidden by IME.
- private boolean mImeTemporarilyConsumesInput;
+ private boolean mImeIsConsumingInput;
- // Whether cursor is visible without regard to {@link mImeTemporarilyConsumesInput}.
+ // Whether cursor is visible without regard to {@link mImeConsumesInput}.
// {code true} is the default value.
private boolean mCursorVisibleFromAttr = true;
@@ -8750,7 +8750,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
if (getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT) {
- outAttrs.internalImeOptions |= EditorInfo.IME_FLAG_APP_WINDOW_PORTRAIT;
+ outAttrs.internalImeOptions |= EditorInfo.IME_INTERNAL_FLAG_APP_WINDOW_PORTRAIT;
}
if (isMultilineInputType(outAttrs.inputType)) {
// Multi-line text editors should always show an enter key.
@@ -10506,8 +10506,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
/**
* Set whether the cursor is visible. The default is true. Note that this property only
- * makes sense for editable TextView. If IME is temporarily consuming the input, the cursor will
- * be always invisible, visibility will be updated as the last state when IME does not consume
+ * makes sense for editable TextView. If IME is consuming the input, the cursor will always be
+ * invisible, visibility will be updated as the last state when IME does not consume
* the input anymore.
*
* @see #isCursorVisible()
@@ -10521,20 +10521,20 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
/**
- * Sets the IME is temporarily consuming the input and make the cursor invisible if
- * {@code imeTemporarilyConsumesInput} is {@code true}. Otherwise, make the cursor visible.
+ * Sets the IME is consuming the input and make the cursor invisible if {@code imeConsumesInput}
+ * is {@code true}. Otherwise, make the cursor visible.
*
- * @param imeTemporarilyConsumesInput {@code true} if IME is temporarily consuming the input
+ * @param imeConsumesInput {@code true} if IME is consuming the input
*
* @hide
*/
- public void setImeTemporarilyConsumesInput(boolean imeTemporarilyConsumesInput) {
- mImeTemporarilyConsumesInput = imeTemporarilyConsumesInput;
+ public void setImeConsumesInput(boolean imeConsumesInput) {
+ mImeIsConsumingInput = imeConsumesInput;
updateCursorVisibleInternal();
}
private void updateCursorVisibleInternal() {
- boolean visible = mCursorVisibleFromAttr && !mImeTemporarilyConsumesInput;
+ boolean visible = mCursorVisibleFromAttr && !mImeIsConsumingInput;
if (visible && mEditor == null) return; // visible is the default value with no edit data
createEditorIfNeeded();
if (mEditor.mCursorVisible != visible) {
@@ -10550,7 +10550,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
/**
* @return whether or not the cursor is visible (assuming this TextView is editable). This
- * method may return {@code false} when the IME is temporarily consuming the input even if the
+ * method may return {@code false} when the IME is consuming the input even if the
* {@code mEditor.mCursorVisible} attribute is {@code true} or {@code #setCursorVisible(true)}
* is called.
*
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index a5eb5f607c12..7aca36af919d 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -179,9 +179,10 @@ interface IPlatformCompat {
*
* @param changeId the ID of the change that was overridden
* @param packageName the app package name that was overridden
+ * @return {@code true} if an override existed
* @throws SecurityException if overriding changes is not permitted
*/
- void clearOverrideForTest(long changeId, String packageName);
+ boolean clearOverrideForTest(long changeId, String packageName);
/**
* Enables all compatibility changes that have enabledSinceTargetSdk ==
diff --git a/core/java/com/android/internal/os/KernelCpuTotalBpfMapReader.java b/core/java/com/android/internal/os/KernelCpuTotalBpfMapReader.java
index fa552e3603c6..50331e3338dc 100644
--- a/core/java/com/android/internal/os/KernelCpuTotalBpfMapReader.java
+++ b/core/java/com/android/internal/os/KernelCpuTotalBpfMapReader.java
@@ -24,10 +24,7 @@ public final class KernelCpuTotalBpfMapReader {
}
/** Returns whether total CPU time is measured. */
- public static boolean isSupported() {
- // TODO(b/174245730): Implement this check.
- return true;
- }
+ public static native boolean isSupported();
/** Reads total CPU time from bpf map. */
public static native boolean read(Callback callback);
diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java
index a4ce027501b8..585ddf6ddf98 100644
--- a/core/java/com/android/internal/os/ZygoteServer.java
+++ b/core/java/com/android/internal/os/ZygoteServer.java
@@ -492,10 +492,12 @@ class ZygoteServer {
long elapsedTimeMs = System.currentTimeMillis() - mUsapPoolRefillTriggerTimestamp;
if (elapsedTimeMs >= mUsapPoolRefillDelayMs) {
- // Normalize the poll timeout value when the time between one poll event and the
- // next pushes us over the delay value. This prevents poll receiving a 0
- // timeout value, which would result in it returning immediately.
- pollTimeoutMs = -1;
+ // The refill delay has elapsed during the period between poll invocations.
+ // We will now check for any currently ready file descriptors before refilling
+ // the USAP pool.
+ pollTimeoutMs = 0;
+ mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
+ mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED;
} else if (elapsedTimeMs <= 0) {
// This can occur if the clock used by currentTimeMillis is reset, which is
@@ -517,9 +519,11 @@ class ZygoteServer {
}
if (pollReturnValue == 0) {
- // The poll timeout has been exceeded. This only occurs when we have finished the
- // USAP pool refill delay period.
-
+ // The poll returned zero results either when the timeout value has been exceeded
+ // or when a non-blocking poll is issued and no FDs are ready. In either case it
+ // is time to refill the pool. This will result in a duplicate assignment when
+ // the non-blocking poll returns zero results, but it avoids an additional
+ // conditional in the else branch.
mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP;
mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED;
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index e7b7bf4a5b52..19506a325d9a 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -79,7 +79,7 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
private static final int DO_CLOSE_CONNECTION = 150;
private static final int DO_COMMIT_CONTENT = 160;
private static final int DO_GET_SURROUNDING_TEXT = 41;
- private static final int DO_SET_IME_TEMPORARILY_CONSUMES_INPUT = 170;
+ private static final int DO_SET_IME_CONSUMES_INPUT = 170;
@GuardedBy("mLock")
@@ -268,13 +268,12 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
}
/**
- * Dispatches the request for setting ime temporarily consumes input.
+ * Dispatches the request for setting ime consumes input.
*
- * <p>See {@link InputConnection#setImeTemporarilyConsumesInput(boolean)}.
+ * <p>See {@link InputConnection#setImeConsumesInput(boolean)}.
*/
- public void setImeTemporarilyConsumesInput(boolean imeTemporarilyConsumesInput) {
- dispatchMessage(obtainMessageB(DO_SET_IME_TEMPORARILY_CONSUMES_INPUT,
- imeTemporarilyConsumesInput));
+ public void setImeConsumesInput(boolean imeConsumesInput) {
+ dispatchMessage(obtainMessageB(DO_SET_IME_CONSUMES_INPUT, imeConsumesInput));
}
void dispatchMessage(Message msg) {
@@ -822,17 +821,17 @@ public abstract class IInputConnectionWrapper extends IInputContext.Stub {
}
return;
}
- case DO_SET_IME_TEMPORARILY_CONSUMES_INPUT: {
+ case DO_SET_IME_CONSUMES_INPUT: {
Trace.traceBegin(Trace.TRACE_TAG_INPUT,
- "InputConnection#setImeTemporarilyConsumesInput");
+ "InputConnection#setImeConsumesInput");
try {
InputConnection ic = getInputConnection();
if (ic == null || !isActive()) {
Log.w(TAG,
- "setImeTemporarilyConsumesInput on inactive InputConnection");
+ "setImeConsumesInput on inactive InputConnection");
return;
}
- ic.setImeTemporarilyConsumesInput(msg.arg1 == 1);
+ ic.setImeConsumesInput(msg.arg1 == 1);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl
index 586404c53f18..b06b4e5351c2 100644
--- a/core/java/com/android/internal/view/IInputContext.aidl
+++ b/core/java/com/android/internal/view/IInputContext.aidl
@@ -86,5 +86,5 @@ import com.android.internal.inputmethod.ISurroundingTextResultCallback;
void getSurroundingText(int beforeLength, int afterLength, int flags,
ISurroundingTextResultCallback callback);
- void setImeTemporarilyConsumesInput(boolean imeTemporarilyConsumesInput);
+ void setImeConsumesInput(boolean imeConsumesInput);
}
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index 84c92ca83f36..0e9d13595124 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -525,12 +525,12 @@ public class InputConnectionWrapper implements InputConnection {
}
/**
- * See {@link InputConnection#setImeTemporarilyConsumesInput(boolean)}.
+ * See {@link InputConnection#setImeConsumesInput(boolean)}.
*/
@AnyThread
- public boolean setImeTemporarilyConsumesInput(boolean imeTemporarilyConsumesInput) {
+ public boolean setImeConsumesInput(boolean imeConsumesInput) {
try {
- mIInputContext.setImeTemporarilyConsumesInput(imeTemporarilyConsumesInput);
+ mIInputContext.setImeConsumesInput(imeConsumesInput);
return true;
} catch (RemoteException e) {
return false;
diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java
index 4ccf9ce91f27..3d054a5e773c 100644
--- a/core/java/com/android/internal/widget/EditableInputConnection.java
+++ b/core/java/com/android/internal/widget/EditableInputConnection.java
@@ -245,11 +245,11 @@ public class EditableInputConnection extends BaseInputConnection
}
@Override
- public boolean setImeTemporarilyConsumesInput(boolean imeTemporarilyConsumesInput) {
+ public boolean setImeConsumesInput(boolean imeConsumesInput) {
if (mTextView == null) {
- return super.setImeTemporarilyConsumesInput(imeTemporarilyConsumesInput);
+ return super.setImeConsumesInput(imeConsumesInput);
}
- mTextView.setImeTemporarilyConsumesInput(imeTemporarilyConsumesInput);
+ mTextView.setImeConsumesInput(imeConsumesInput);
return true;
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 0b48e72a4acd..8edc8a186c59 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -207,9 +207,9 @@ cc_library_shared {
],
shared_libs: [
- "audioclient-types-aidl-unstable-cpp",
- "audioflinger-aidl-unstable-cpp",
- "av-types-aidl-unstable-cpp",
+ "audioclient-types-aidl-cpp",
+ "audioflinger-aidl-cpp",
+ "av-types-aidl-cpp",
"libandroidicu",
"libbpf_android",
"libnetdbpf",
diff --git a/core/jni/com_android_internal_os_KernelCpuTotalBpfMapReader.cpp b/core/jni/com_android_internal_os_KernelCpuTotalBpfMapReader.cpp
index 72492381e31a..d8446ca2881d 100644
--- a/core/jni/com_android_internal_os_KernelCpuTotalBpfMapReader.cpp
+++ b/core/jni/com_android_internal_os_KernelCpuTotalBpfMapReader.cpp
@@ -20,6 +20,10 @@
namespace android {
+static jboolean KernelCpuTotalBpfMapReader_isSupported(JNIEnv *, jobject) {
+ return android::bpf::isTrackingUidTimesSupported() ? JNI_TRUE : JNI_FALSE;
+}
+
static jboolean KernelCpuTotalBpfMapReader_read(JNIEnv *env, jobject, jobject callback) {
jclass callbackClass = env->GetObjectClass(callback);
jmethodID callbackMethod = env->GetMethodID(callbackClass, "accept", "(IIJ)V");
@@ -47,6 +51,7 @@ static jboolean KernelCpuTotalBpfMapReader_read(JNIEnv *env, jobject, jobject ca
static const JNINativeMethod methods[] = {
{"read", "(Lcom/android/internal/os/KernelCpuTotalBpfMapReader$Callback;)Z",
(void *)KernelCpuTotalBpfMapReader_read},
+ {"isSupported", "()Z", (void *)KernelCpuTotalBpfMapReader_isSupported},
};
int register_com_android_internal_os_KernelCpuTotalBpfMapReader(JNIEnv *env) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index dc81bc9d449d..827bf7b70cbc 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -5427,7 +5427,7 @@
<permission android:name="android.permission.INPUT_CONSUMER"
android:protectionLevel="signature" />
- <!-- @hide Allows an application to control the system's device state managed by the
+ <!-- @hide @TestApi Allows an application to control the system's device state managed by the
{@link android.service.devicestate.DeviceStateManagerService}. For example, on foldable
devices this would grant access to toggle between the folded and unfolded states. -->
<permission android:name="android.permission.CONTROL_DEVICE_STATE"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 98b36c5c9cbf..f6d1b7da78f0 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1585,6 +1585,8 @@
<!-- Template to be used to name enrolled fingerprints by default. -->
<string name="fingerprint_name_template">Finger <xliff:g id="fingerId" example="1">%d</xliff:g></string>
+ <!-- Subtitle shown on the system-provided biometric dialog, asking the user to authenticate with their fingerprint. [CHAR LIMIT=70] -->
+ <string name="fingerprint_dialog_default_subtitle">Use your fingerprint to continue</string>
<!-- Array containing custom error messages from vendor. Vendor is expected to add and translate these strings -->
<string-array name="fingerprint_error_vendor">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 80163b16ada0..ae5e2f597952 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2488,6 +2488,7 @@
<java-symbol type="string" name="fingerprint_error_lockout" />
<java-symbol type="string" name="fingerprint_error_lockout_permanent" />
<java-symbol type="string" name="fingerprint_name_template" />
+ <java-symbol type="string" name="fingerprint_dialog_default_subtitle" />
<java-symbol type="string" name="fingerprint_authenticated" />
<java-symbol type="string" name="fingerprint_error_no_fingerprints" />
<java-symbol type="string" name="fingerprint_error_hw_not_present" />
diff --git a/core/tests/coretests/src/android/app/WindowContextTest.java b/core/tests/coretests/src/android/app/WindowContextTest.java
index da7304efbd3d..48b58c6c0a1c 100644
--- a/core/tests/coretests/src/android/app/WindowContextTest.java
+++ b/core/tests/coretests/src/android/app/WindowContextTest.java
@@ -184,7 +184,8 @@ public class WindowContextTest {
final IBinder token = windowContext.getWindowContextToken();
final IBinder existingToken = new Binder();
- mWms.addWindowToken(existingToken, TYPE_INPUT_METHOD, windowContext.getDisplayId());
+ mWms.addWindowToken(existingToken, TYPE_INPUT_METHOD, windowContext.getDisplayId(),
+ null /* options */);
final WindowManager.LayoutParams params =
new WindowManager.LayoutParams(TYPE_INPUT_METHOD);
diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java
index a4284a04310e..47ce2d87e69f 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -278,29 +278,29 @@ public class TextViewTest {
@Test
@UiThreadTest
- public void setSetImeTemporarilyConsumesInput_recoveryToVisible() {
+ public void setSetImeConsumesInput_recoveryToVisible() {
mTextView = new TextView(mActivity);
mTextView.setCursorVisible(true);
assertTrue(mTextView.isCursorVisible());
- mTextView.setImeTemporarilyConsumesInput(true);
+ mTextView.setImeConsumesInput(true);
assertFalse(mTextView.isCursorVisible());
- mTextView.setImeTemporarilyConsumesInput(false);
+ mTextView.setImeConsumesInput(false);
assertTrue(mTextView.isCursorVisible());
}
@Test
@UiThreadTest
- public void setSetImeTemporarilyConsumesInput_recoveryToInvisible() {
+ public void setSetImeConsumesInput_recoveryToInvisible() {
mTextView = new TextView(mActivity);
mTextView.setCursorVisible(false);
assertFalse(mTextView.isCursorVisible());
- mTextView.setImeTemporarilyConsumesInput(true);
+ mTextView.setImeConsumesInput(true);
assertFalse(mTextView.isCursorVisible());
- mTextView.setImeTemporarilyConsumesInput(false);
+ mTextView.setImeConsumesInput(false);
assertFalse(mTextView.isCursorVisible());
}
diff --git a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
index 36f01f9a951d..e7fdfb8c19e9 100644
--- a/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
+++ b/core/tests/devicestatetests/src/android/hardware/devicestate/DeviceStateManagerGlobalTest.java
@@ -17,8 +17,11 @@
package android.hardware.devicestate;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
import android.annotation.Nullable;
+import android.os.IBinder;
import android.os.RemoteException;
import androidx.test.filters.SmallTest;
@@ -30,6 +33,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
+import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
@@ -41,6 +45,9 @@ import java.util.Set;
@RunWith(JUnit4.class)
@SmallTest
public final class DeviceStateManagerGlobalTest {
+ private static final int DEFAULT_DEVICE_STATE = 0;
+ private static final int OTHER_DEVICE_STATE = 1;
+
private TestDeviceStateManagerService mService;
private DeviceStateManagerGlobal mDeviceStateManagerGlobal;
@@ -52,7 +59,7 @@ public final class DeviceStateManagerGlobalTest {
@Test
public void registerListener() {
- mService.setDeviceState(0);
+ mService.setBaseState(DEFAULT_DEVICE_STATE);
TestDeviceStateListener listener1 = new TestDeviceStateListener();
TestDeviceStateListener listener2 = new TestDeviceStateListener();
@@ -61,28 +68,58 @@ public final class DeviceStateManagerGlobalTest {
ConcurrentUtils.DIRECT_EXECUTOR);
mDeviceStateManagerGlobal.registerDeviceStateListener(listener2,
ConcurrentUtils.DIRECT_EXECUTOR);
- assertEquals(0, listener1.getLastReportedState().intValue());
- assertEquals(0, listener2.getLastReportedState().intValue());
+ assertEquals(DEFAULT_DEVICE_STATE, listener1.getLastReportedState().intValue());
+ assertEquals(DEFAULT_DEVICE_STATE, listener2.getLastReportedState().intValue());
- mService.setDeviceState(1);
- assertEquals(1, listener1.getLastReportedState().intValue());
- assertEquals(1, listener2.getLastReportedState().intValue());
+ mService.setBaseState(OTHER_DEVICE_STATE);
+ assertEquals(OTHER_DEVICE_STATE, listener1.getLastReportedState().intValue());
+ assertEquals(OTHER_DEVICE_STATE, listener2.getLastReportedState().intValue());
}
@Test
public void unregisterListener() {
- mService.setDeviceState(0);
+ mService.setBaseState(DEFAULT_DEVICE_STATE);
TestDeviceStateListener listener = new TestDeviceStateListener();
mDeviceStateManagerGlobal.registerDeviceStateListener(listener,
ConcurrentUtils.DIRECT_EXECUTOR);
- assertEquals(0, listener.getLastReportedState().intValue());
+ assertEquals(DEFAULT_DEVICE_STATE, listener.getLastReportedState().intValue());
mDeviceStateManagerGlobal.unregisterDeviceStateListener(listener);
- mService.setDeviceState(1);
- assertEquals(0, listener.getLastReportedState().intValue());
+ mService.setBaseState(OTHER_DEVICE_STATE);
+ assertEquals(DEFAULT_DEVICE_STATE, listener.getLastReportedState().intValue());
+ }
+
+ @Test
+ public void submittingRequestRegisteredCallback() {
+ assertTrue(mService.mCallbacks.isEmpty());
+
+ DeviceStateRequest request = DeviceStateRequest.newBuilder(DEFAULT_DEVICE_STATE).build();
+ mDeviceStateManagerGlobal.requestState(request, null /* executor */, null /* callback */);
+
+ assertFalse(mService.mCallbacks.isEmpty());
+ }
+
+ @Test
+ public void submitRequest() {
+ mService.setBaseState(DEFAULT_DEVICE_STATE);
+
+ TestDeviceStateListener listener = new TestDeviceStateListener();
+ mDeviceStateManagerGlobal.registerDeviceStateListener(listener,
+ ConcurrentUtils.DIRECT_EXECUTOR);
+
+ assertEquals(DEFAULT_DEVICE_STATE, listener.getLastReportedState().intValue());
+
+ DeviceStateRequest request = DeviceStateRequest.newBuilder(OTHER_DEVICE_STATE).build();
+ mDeviceStateManagerGlobal.requestState(request, null /* executor */, null /* callback */);
+
+ assertEquals(OTHER_DEVICE_STATE, listener.getLastReportedState().intValue());
+
+ mDeviceStateManagerGlobal.cancelRequest(request);
+
+ assertEquals(DEFAULT_DEVICE_STATE, listener.getLastReportedState().intValue());
}
private final class TestDeviceStateListener implements DeviceStateManager.DeviceStateListener {
@@ -100,8 +137,23 @@ public final class DeviceStateManagerGlobalTest {
}
}
- private final class TestDeviceStateManagerService extends IDeviceStateManager.Stub {
- private int mDeviceState = DeviceStateManager.INVALID_DEVICE_STATE;
+ private static final class TestDeviceStateManagerService extends IDeviceStateManager.Stub {
+ public static final class Request {
+ public final IBinder token;
+ public final int state;
+ public final int flags;
+
+ private Request(IBinder token, int state, int flags) {
+ this.token = token;
+ this.state = state;
+ this.flags = flags;
+ }
+ }
+
+ private int mBaseState = DEFAULT_DEVICE_STATE;
+ private int mMergedState = DEFAULT_DEVICE_STATE;
+ private ArrayList<Request> mRequests = new ArrayList<>();
+
private Set<IDeviceStateManagerCallback> mCallbacks = new HashSet<>();
@Override
@@ -112,19 +164,86 @@ public final class DeviceStateManagerGlobalTest {
mCallbacks.add(callback);
try {
- callback.onDeviceStateChanged(mDeviceState);
+ callback.onDeviceStateChanged(mMergedState);
} catch (RemoteException e) {
// Do nothing. Should never happen.
}
}
- public void setDeviceState(int deviceState) {
- boolean stateChanged = mDeviceState != deviceState;
- mDeviceState = deviceState;
- if (stateChanged) {
+ @Override
+ public int[] getSupportedDeviceStates() {
+ return new int[] { DEFAULT_DEVICE_STATE, OTHER_DEVICE_STATE };
+ }
+
+ @Override
+ public void requestState(IBinder token, int state, int flags) {
+ if (!mRequests.isEmpty()) {
+ final Request topRequest = mRequests.get(mRequests.size() - 1);
+ for (IDeviceStateManagerCallback callback : mCallbacks) {
+ try {
+ callback.onRequestSuspended(topRequest.token);
+ } catch (RemoteException e) {
+ // Do nothing. Should never happen.
+ }
+ }
+ }
+
+ final Request request = new Request(token, state, flags);
+ mRequests.add(request);
+ notifyStateChangedIfNeeded();
+
+ for (IDeviceStateManagerCallback callback : mCallbacks) {
+ try {
+ callback.onRequestActive(token);
+ } catch (RemoteException e) {
+ // Do nothing. Should never happen.
+ }
+ }
+ }
+
+ @Override
+ public void cancelRequest(IBinder token) {
+ int index = -1;
+ for (int i = 0; i < mRequests.size(); i++) {
+ if (mRequests.get(i).token.equals(token)) {
+ index = i;
+ break;
+ }
+ }
+
+ if (index == -1) {
+ throw new IllegalArgumentException("Unknown request: " + token);
+ }
+
+ mRequests.remove(index);
+ for (IDeviceStateManagerCallback callback : mCallbacks) {
+ try {
+ callback.onRequestCanceled(token);
+ } catch (RemoteException e) {
+ // Do nothing. Should never happen.
+ }
+ }
+ notifyStateChangedIfNeeded();
+ }
+
+ public void setBaseState(int state) {
+ mBaseState = state;
+ notifyStateChangedIfNeeded();
+ }
+
+ private void notifyStateChangedIfNeeded() {
+ final int originalMergedState = mMergedState;
+
+ if (!mRequests.isEmpty()) {
+ mMergedState = mRequests.get(mRequests.size() - 1).state;
+ } else {
+ mMergedState = mBaseState;
+ }
+
+ if (mMergedState != originalMergedState) {
for (IDeviceStateManagerCallback callback : mCallbacks) {
try {
- callback.onDeviceStateChanged(mDeviceState);
+ callback.onDeviceStateChanged(mMergedState);
} catch (RemoteException e) {
// Do nothing. Should never happen.
}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index b0ae9b98e7f5..ea42246e8262 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -165,6 +165,7 @@
<assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="audioserver" />
<assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="audioserver" />
<assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="audioserver" />
+ <assign-permission name="android.permission.INTERACT_ACROSS_USERS" uid="audioserver" />
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="cameraserver" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="cameraserver" />
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index cdc61a1c5752..bab36e61393a 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -469,6 +469,9 @@ applications that come with the platform
<permission name="com.android.voicemail.permission.READ_VOICEMAIL"/>
<permission name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS"/>
<permission name="android.permission.MODIFY_QUIET_MODE" />
+ <!-- Permission required for GTS test - GtsAssistIntentTestCases -->
+ <permission name="android.permission.MANAGE_SOUND_TRIGGER" />
+ <permission name="android.permission.CAPTURE_AUDIO_HOTWORD" />
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java
index fa4f8b1674d1..3ebca6ad302d 100644
--- a/keystore/java/android/security/keystore/KeyProperties.java
+++ b/keystore/java/android/security/keystore/KeyProperties.java
@@ -20,6 +20,8 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
+import android.annotation.SystemApi;
+import android.os.Process;
import android.security.KeyStore;
import android.security.keymaster.KeymasterDefs;
@@ -874,9 +876,18 @@ public abstract class KeyProperties {
* which it must be configured in SEPolicy.
* @hide
*/
+ @SystemApi
public static final int NAMESPACE_APPLICATION = -1;
/**
+ * The namespace identifier for the WIFI Keystore namespace.
+ * This must be kept in sync with system/sepolicy/private/keystore2_key_contexts
+ * @hide
+ */
+ @SystemApi
+ public static final int NAMESPACE_WIFI = 102;
+
+ /**
* For legacy support, translate namespaces into known UIDs.
* @hide
*/
@@ -884,6 +895,8 @@ public abstract class KeyProperties {
switch (namespace) {
case NAMESPACE_APPLICATION:
return KeyStore.UID_SELF;
+ case NAMESPACE_WIFI:
+ return Process.WIFI_UID;
// TODO Translate WIFI and VPN UIDs once the namespaces are defined.
// b/171305388 and b/171305607
default:
@@ -900,6 +913,8 @@ public abstract class KeyProperties {
switch (uid) {
case KeyStore.UID_SELF:
return NAMESPACE_APPLICATION;
+ case Process.WIFI_UID:
+ return NAMESPACE_WIFI;
// TODO Translate WIFI and VPN UIDs once the namespaces are defined.
// b/171305388 and b/171305607
default:
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index 6a92980de37c..70e30d2de5a1 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -585,6 +585,30 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
mSpec.getKeyValidityForConsumptionEnd()
));
}
+ if (mSpec.getCertificateNotAfter() != null) {
+ params.add(KeyStore2ParameterUtils.makeDate(
+ KeymasterDefs.KM_TAG_CERTIFICATE_NOT_AFTER,
+ mSpec.getCertificateNotAfter()
+ ));
+ }
+ if (mSpec.getCertificateNotBefore() != null) {
+ params.add(KeyStore2ParameterUtils.makeDate(
+ KeymasterDefs.KM_TAG_CERTIFICATE_NOT_BEFORE,
+ mSpec.getCertificateNotBefore()
+ ));
+ }
+ if (mSpec.getCertificateSerialNumber() != null) {
+ params.add(KeyStore2ParameterUtils.makeBignum(
+ KeymasterDefs.KM_TAG_CERTIFICATE_SERIAL,
+ mSpec.getCertificateSerialNumber()
+ ));
+ }
+ if (mSpec.getCertificateSubject() != null) {
+ params.add(KeyStore2ParameterUtils.makeBytes(
+ KeymasterDefs.KM_TAG_CERTIFICATE_SUBJECT,
+ mSpec.getCertificateSubject().getEncoded()
+ ));
+ }
if (mSpec.getMaxUsageCount() != KeyProperties.UNRESTRICTED_USAGE_COUNT) {
params.add(KeyStore2ParameterUtils.makeInt(
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index 75ac61a22cab..e1011155248e 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -352,14 +352,17 @@ public class AndroidKeyStoreProvider extends Provider {
try {
response = keyStore.getKeyEntry(descriptor);
} catch (android.security.KeyStoreException e) {
- if (e.getErrorCode() == ResponseCode.KEY_PERMANENTLY_INVALIDATED) {
- throw new KeyPermanentlyInvalidatedException(
- "User changed or deleted their auth credentials",
- e);
- } else {
- throw (UnrecoverableKeyException)
- new UnrecoverableKeyException("Failed to obtain information about key")
- .initCause(e);
+ switch (e.getErrorCode()) {
+ case ResponseCode.KEY_NOT_FOUND:
+ return null;
+ case ResponseCode.KEY_PERMANENTLY_INVALIDATED:
+ throw new KeyPermanentlyInvalidatedException(
+ "User changed or deleted their auth credentials",
+ e);
+ default:
+ throw (UnrecoverableKeyException)
+ new UnrecoverableKeyException("Failed to obtain information about key")
+ .initCause(e);
}
}
diff --git a/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java b/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java
index 4c8ab8d6c713..dcdd7defd752 100644
--- a/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java
+++ b/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java
@@ -28,6 +28,7 @@ import android.security.keystore.KeyProperties;
import android.security.keystore.UserAuthArgs;
import android.system.keystore2.Authorization;
+import java.math.BigInteger;
import java.security.ProviderException;
import java.util.ArrayList;
import java.util.Date;
@@ -154,6 +155,23 @@ public abstract class KeyStore2ParameterUtils {
}
/**
+ * This function constructs a {@link KeyParameter} expressing a Bignum.
+ * @param tag Must be KeyMint tag with the associated type BIGNUM.
+ * @param b A BitInteger to be stored in the new key parameter.
+ * @return An instance of {@link KeyParameter}.
+ * @hide
+ */
+ static @NonNull KeyParameter makeBignum(int tag, @NonNull BigInteger b) {
+ if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_BIGNUM) {
+ throw new IllegalArgumentException("Not a bignum tag: " + tag);
+ }
+ KeyParameter p = new KeyParameter();
+ p.tag = tag;
+ p.value = KeyParameterValue.blob(b.toByteArray());
+ return p;
+ }
+
+ /**
* This function constructs a {@link KeyParameter} expressing date.
* @param tag Must be KeyMint tag with the associated type DATE.
* @param date A date
@@ -167,10 +185,6 @@ public abstract class KeyStore2ParameterUtils {
KeyParameter p = new KeyParameter();
p.tag = tag;
p.value = KeyParameterValue.dateTime(date.getTime());
- if (p.value.getDateTime() < 0) {
- throw new IllegalArgumentException("Date tag value out of range: "
- + p.value.getDateTime());
- }
return p;
}
/**
diff --git a/libs/hwui/jni/fonts/FontFamily.cpp b/libs/hwui/jni/fonts/FontFamily.cpp
index a07723f39b0c..8fe6da3183f4 100644
--- a/libs/hwui/jni/fonts/FontFamily.cpp
+++ b/libs/hwui/jni/fonts/FontFamily.cpp
@@ -95,7 +95,7 @@ static jstring FontFamily_getLangTags(JNIEnv* env, jobject, jlong familyPtr) {
}
// CriticalNative
-static jint FontFamily_getVariant(jlong familyPtr) {
+static jint FontFamily_getVariant(CRITICAL_JNI_PARAMS_COMMA jlong familyPtr) {
FontFamilyWrapper* family = reinterpret_cast<FontFamilyWrapper*>(familyPtr);
return static_cast<jint>(family->family->variant());
}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 08deb156a6cf..8d090f824e71 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1,5 +1,4 @@
/*
-/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java
index 812dac97bcd3..27f72687ccbe 100644
--- a/media/java/android/media/AudioPlaybackConfiguration.java
+++ b/media/java/android/media/AudioPlaybackConfiguration.java
@@ -20,6 +20,7 @@ import static android.media.AudioAttributes.ALLOW_CAPTURE_BY_ALL;
import static android.media.AudioAttributes.ALLOW_CAPTURE_BY_NONE;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -195,6 +196,8 @@ public final class AudioPlaybackConfiguration implements Parcelable {
private int mDeviceId;
+ private int mSessionId;
+
/**
* Never use without initializing parameters afterwards
*/
@@ -207,7 +210,10 @@ public final class AudioPlaybackConfiguration implements Parcelable {
* @hide
*/
public AudioPlaybackConfiguration(PlayerBase.PlayerIdCard pic, int piid, int uid, int pid) {
- if (DEBUG) { Log.d(TAG, "new: piid=" + piid + " iplayer=" + pic.mIPlayer); }
+ if (DEBUG) {
+ Log.d(TAG, "new: piid=" + piid + " iplayer=" + pic.mIPlayer
+ + " sessionId=" + pic.mSessionId);
+ }
mPlayerIId = piid;
mPlayerType = pic.mPlayerType;
mClientUid = uid;
@@ -220,6 +226,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
} else {
mIPlayerShell = null;
}
+ mSessionId = pic.mSessionId;
}
/**
@@ -259,6 +266,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
anonymCopy.mClientUid = PLAYER_UPID_INVALID;
anonymCopy.mClientPid = PLAYER_UPID_INVALID;
anonymCopy.mIPlayerShell = null;
+ anonymCopy.mSessionId = AudioSystem.AUDIO_SESSION_ALLOCATE;
return anonymCopy;
}
@@ -303,6 +311,17 @@ public final class AudioPlaybackConfiguration implements Parcelable {
/**
* @hide
+ * Return the audio session ID associated with this player.
+ * See {@link AudioManager#generateAudioSessionId()}.
+ * @return an audio session ID
+ */
+ @SystemApi
+ public @IntRange(from = 0) int getSessionId() {
+ return mSessionId;
+ }
+
+ /**
+ * @hide
* Return the type of player linked to this configuration.
* <br>Note that player types not exposed in the system API will be represented as
* {@link #PLAYER_TYPE_UNKNOWN}.
@@ -381,6 +400,17 @@ public final class AudioPlaybackConfiguration implements Parcelable {
/**
* @hide
+ * Handle a change of audio session Id
+ * @param sessionId the audio session ID
+ */
+ public boolean handleSessionIdEvent(int sessionId) {
+ final boolean changed = sessionId != mSessionId;
+ mSessionId = sessionId;
+ return changed;
+ }
+
+ /**
+ * @hide
* Handle a player state change
* @param event
* @param deviceId active device id or {@Code PLAYER_DEVICEID_INVALID}
@@ -476,7 +506,8 @@ public final class AudioPlaybackConfiguration implements Parcelable {
@Override
public int hashCode() {
- return Objects.hash(mPlayerIId, mDeviceId, mPlayerType, mClientUid, mClientPid);
+ return Objects.hash(mPlayerIId, mDeviceId, mPlayerType, mClientUid, mClientPid,
+ mSessionId);
}
@Override
@@ -498,6 +529,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
ips = mIPlayerShell;
}
dest.writeStrongInterface(ips == null ? null : ips.getIPlayer());
+ dest.writeInt(mSessionId);
}
private AudioPlaybackConfiguration(Parcel in) {
@@ -510,6 +542,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
mPlayerAttr = AudioAttributes.CREATOR.createFromParcel(in);
final IPlayer p = IPlayer.Stub.asInterface(in.readStrongBinder());
mIPlayerShell = (p == null) ? null : new IPlayerShell(null, p);
+ mSessionId = in.readInt();
}
@Override
@@ -523,7 +556,8 @@ public final class AudioPlaybackConfiguration implements Parcelable {
&& (mDeviceId == that.mDeviceId)
&& (mPlayerType == that.mPlayerType)
&& (mClientUid == that.mClientUid)
- && (mClientPid == that.mClientPid));
+ && (mClientPid == that.mClientPid))
+ && (mSessionId == that.mSessionId);
}
@Override
@@ -533,7 +567,8 @@ public final class AudioPlaybackConfiguration implements Parcelable {
+ " type:" + toLogFriendlyPlayerType(mPlayerType)
+ " u/pid:" + mClientUid + "/" + mClientPid
+ " state:" + toLogFriendlyPlayerState(mPlayerState)
- + " attr:" + mPlayerAttr;
+ + " attr:" + mPlayerAttr
+ + " sessionId:" + mSessionId;
}
//=====================================================================
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 175d36fedb1f..e056d435198a 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -836,7 +836,7 @@ public class AudioTrack extends PlayerBase
mState = STATE_INITIALIZED;
}
- baseRegisterPlayer();
+ baseRegisterPlayer(mSessionId);
}
/**
@@ -866,7 +866,7 @@ public class AudioTrack extends PlayerBase
// other initialization...
if (nativeTrackInJavaObj != 0) {
- baseRegisterPlayer();
+ baseRegisterPlayer(AudioSystem.AUDIO_SESSION_ALLOCATE);
deferred_connect(nativeTrackInJavaObj);
} else {
mState = STATE_UNINITIALIZED;
diff --git a/media/java/android/media/HwAudioSource.java b/media/java/android/media/HwAudioSource.java
index bbf632a406ec..e339ae8ef706 100644
--- a/media/java/android/media/HwAudioSource.java
+++ b/media/java/android/media/HwAudioSource.java
@@ -54,7 +54,7 @@ public class HwAudioSource extends PlayerBase {
Preconditions.checkArgument(device.isSource(), "Requires a source device");
mAudioDeviceInfo = device;
mAudioAttributes = attributes;
- baseRegisterPlayer();
+ baseRegisterPlayer(AudioSystem.AUDIO_SESSION_ALLOCATE);
}
/**
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index dd42aab67c65..71ee57e3d471 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -73,6 +73,8 @@ interface IAudioService {
oneway void releaseRecorder(in int riid);
+ oneway void playerSessionId(in int piid, in int sessionId);
+
// Java-only methods below.
oneway void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index dd0bc61c4225..ca0d29f2f47f 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -663,6 +663,10 @@ public class MediaPlayer extends PlayerBase
* result in an exception.</p>
*/
public MediaPlayer() {
+ this(AudioSystem.AUDIO_SESSION_ALLOCATE);
+ }
+
+ private MediaPlayer(int sessionId) {
super(new AudioAttributes.Builder().build(),
AudioPlaybackConfiguration.PLAYER_TYPE_JAM_MEDIAPLAYER);
@@ -684,7 +688,7 @@ public class MediaPlayer extends PlayerBase
native_setup(new WeakReference<MediaPlayer>(this),
getCurrentOpPackageName());
- baseRegisterPlayer();
+ baseRegisterPlayer(sessionId);
}
/*
@@ -913,7 +917,7 @@ public class MediaPlayer extends PlayerBase
AudioAttributes audioAttributes, int audioSessionId) {
try {
- MediaPlayer mp = new MediaPlayer();
+ MediaPlayer mp = new MediaPlayer(audioSessionId);
final AudioAttributes aa = audioAttributes != null ? audioAttributes :
new AudioAttributes.Builder().build();
mp.setAudioAttributes(aa);
@@ -978,7 +982,7 @@ public class MediaPlayer extends PlayerBase
AssetFileDescriptor afd = context.getResources().openRawResourceFd(resid);
if (afd == null) return null;
- MediaPlayer mp = new MediaPlayer();
+ MediaPlayer mp = new MediaPlayer(audioSessionId);
final AudioAttributes aa = audioAttributes != null ? audioAttributes :
new AudioAttributes.Builder().build();
@@ -2365,7 +2369,13 @@ public class MediaPlayer extends PlayerBase
* This method must be called before one of the overloaded <code> setDataSource </code> methods.
* @throws IllegalStateException if it is called in an invalid state
*/
- public native void setAudioSessionId(int sessionId) throws IllegalArgumentException, IllegalStateException;
+ public void setAudioSessionId(int sessionId)
+ throws IllegalArgumentException, IllegalStateException {
+ native_setAudioSessionId(sessionId);
+ baseUpdateSessionId(sessionId);
+ }
+
+ private native void native_setAudioSessionId(int sessionId);
/**
* Returns the audio session ID.
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index 58ae279d4df1..4407efad6052 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -97,6 +97,7 @@ public abstract class PlayerBase {
* Constructor. Must be given audio attributes, as they are required for AppOps.
* @param attr non-null audio attributes
* @param class non-null class of the implementation of this abstract class
+ * @param sessionId the audio session Id
*/
PlayerBase(@NonNull AudioAttributes attr, int implType) {
if (attr == null) {
@@ -110,7 +111,7 @@ public abstract class PlayerBase {
/**
* Call from derived class when instantiation / initialization is successful
*/
- protected void baseRegisterPlayer() {
+ protected void baseRegisterPlayer(int sessionId) {
if (!USE_AUDIOFLINGER_MUTING_FOR_OP) {
IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
mAppOps = IAppOpsService.Stub.asInterface(b);
@@ -128,7 +129,8 @@ public abstract class PlayerBase {
}
try {
mPlayerIId = getService().trackPlayer(
- new PlayerIdCard(mImplType, mAttributes, new IPlayerWrapper(this)));
+ new PlayerIdCard(mImplType, mAttributes, new IPlayerWrapper(this),
+ sessionId));
} catch (RemoteException e) {
Log.e(TAG, "Error talking to audio service, player will not be tracked", e);
}
@@ -145,7 +147,7 @@ public abstract class PlayerBase {
try {
getService().playerAttributes(mPlayerIId, attr);
} catch (RemoteException e) {
- Log.e(TAG, "Error talking to audio service, STARTED state will not be tracked", e);
+ Log.e(TAG, "Error talking to audio service, audio attributes will not be updated", e);
}
synchronized (mLock) {
boolean attributesChanged = (mAttributes != attr);
@@ -154,6 +156,18 @@ public abstract class PlayerBase {
}
}
+ /**
+ * To be called whenever the session ID of the player changes
+ * @param sessionId, the new session Id
+ */
+ void baseUpdateSessionId(int sessionId) {
+ try {
+ getService().playerSessionId(mPlayerIId, sessionId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error talking to audio service, the session ID will not be updated", e);
+ }
+ }
+
void baseUpdateDeviceId(@Nullable AudioDeviceInfo deviceInfo) {
int deviceId = 0;
if (deviceInfo != null) {
@@ -566,16 +580,19 @@ public abstract class PlayerBase {
public static final int AUDIO_ATTRIBUTES_DEFINED = 1;
public final AudioAttributes mAttributes;
public final IPlayer mIPlayer;
+ public final int mSessionId;
- PlayerIdCard(int type, @NonNull AudioAttributes attr, @NonNull IPlayer iplayer) {
+ PlayerIdCard(int type, @NonNull AudioAttributes attr, @NonNull IPlayer iplayer,
+ int sessionId) {
mPlayerType = type;
mAttributes = attr;
mIPlayer = iplayer;
+ mSessionId = sessionId;
}
@Override
public int hashCode() {
- return Objects.hash(mPlayerType);
+ return Objects.hash(mPlayerType, mSessionId);
}
@Override
@@ -588,6 +605,7 @@ public abstract class PlayerBase {
dest.writeInt(mPlayerType);
mAttributes.writeToParcel(dest, 0);
dest.writeStrongBinder(mIPlayer == null ? null : mIPlayer.asBinder());
+ dest.writeInt(mSessionId);
}
public static final @android.annotation.NonNull Parcelable.Creator<PlayerIdCard> CREATOR
@@ -611,6 +629,7 @@ public abstract class PlayerBase {
// IPlayer can be null if unmarshalling a Parcel coming from who knows where
final IBinder b = in.readStrongBinder();
mIPlayer = (b == null ? null : IPlayer.Stub.asInterface(b));
+ mSessionId = in.readInt();
}
@Override
@@ -621,7 +640,8 @@ public abstract class PlayerBase {
PlayerIdCard that = (PlayerIdCard) o;
// FIXME change to the binder player interface once supported as a member
- return ((mPlayerType == that.mPlayerType) && mAttributes.equals(that.mAttributes));
+ return ((mPlayerType == that.mPlayerType) && mAttributes.equals(that.mAttributes)
+ && (mSessionId == that.mSessionId));
}
}
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index 797caf36203b..32413dc6e841 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -155,7 +155,8 @@ public class SoundPool extends PlayerBase {
}
mAttributes = attributes;
- baseRegisterPlayer();
+ // FIXME: b/174876164 implement session id for soundpool
+ baseRegisterPlayer(AudioSystem.AUDIO_SESSION_ALLOCATE);
}
/**
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 8525e9979aef..ee0be010c233 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -65,6 +65,7 @@ import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -245,6 +246,8 @@ public class Tuner implements AutoCloseable {
private static final int MSG_ON_FILTER_STATUS = 3;
private static final int MSG_ON_LNB_EVENT = 4;
+ private static final int FILTER_CLEANUP_THRESHOLD = 256;
+
/** @hide */
@IntDef(prefix = "DVR_TYPE_", value = {DVR_TYPE_RECORD, DVR_TYPE_PLAYBACK})
@Retention(RetentionPolicy.SOURCE)
@@ -1208,6 +1211,15 @@ public class Tuner implements AutoCloseable {
synchronized (mFilters) {
WeakReference<Filter> weakFilter = new WeakReference<Filter>(filter);
mFilters.add(weakFilter);
+ if (mFilters.size() > FILTER_CLEANUP_THRESHOLD) {
+ Iterator<WeakReference<Filter>> iterator = mFilters.iterator();
+ while (iterator.hasNext()) {
+ WeakReference<Filter> wFilter = iterator.next();
+ if (wFilter.get() == null) {
+ iterator.remove();
+ }
+ }
+ }
}
}
return filter;
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 67a2c49e5746..65b64d7e8df3 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -31,8 +31,8 @@ cc_library_shared {
],
shared_libs: [
- "audioclient-types-aidl-unstable-cpp",
- "av-types-aidl-unstable-cpp",
+ "audioclient-types-aidl-cpp",
+ "av-types-aidl-cpp",
"libandroid_runtime",
"libaudioclient",
"libnativehelper",
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index bd8d2e9f77a4..98ac5b983098 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -1409,7 +1409,7 @@ static const JNINativeMethod gMethods[] = {
{"native_setup", "(Ljava/lang/Object;Ljava/lang/String;)V",(void *)android_media_MediaPlayer_native_setup},
{"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize},
{"getAudioSessionId", "()I", (void *)android_media_MediaPlayer_get_audio_session_id},
- {"setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id},
+ {"native_setAudioSessionId", "(I)V", (void *)android_media_MediaPlayer_set_audio_session_id},
{"_setAuxEffectSendLevel", "(F)V", (void *)android_media_MediaPlayer_setAuxEffectSendLevel},
{"attachAuxEffect", "(I)V", (void *)android_media_MediaPlayer_attachAuxEffect},
{"native_pullBatteryData", "(Landroid/os/Parcel;)I", (void *)android_media_MediaPlayer_pullBatteryData},
diff --git a/native/android/system_fonts.cpp b/native/android/system_fonts.cpp
index 45f42f1b5dc6..48d738039696 100644
--- a/native/android/system_fonts.cpp
+++ b/native/android/system_fonts.cpp
@@ -264,7 +264,7 @@ AFont* _Nonnull AFontMatcher_match(
static_cast<minikin::FamilyVariant>(matcher->mFamilyVariant),
1 /* maxRun */);
- const minikin::Font* font = runs[0].fakedFont.font;
+ const std::shared_ptr<minikin::Font>& font = runs[0].fakedFont.font;
std::unique_ptr<AFont> result = std::make_unique<AFont>();
const android::MinikinFontSkia* minikinFontSkia =
reinterpret_cast<android::MinikinFontSkia*>(font->typeface().get());
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index fa3213d54281..3b054e942178 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -4845,9 +4845,13 @@ public class ConnectivityManager {
}
}
- private void setOemNetworkPreference(@NonNull OemNetworkPreferences preference) {
- Log.d(TAG, "setOemNetworkPreference called with preference: "
- + preference.toString());
+ private void setOemNetworkPreference(@NonNull final OemNetworkPreferences preference) {
+ try {
+ mService.setOemNetworkPreference(preference);
+ } catch (RemoteException e) {
+ Log.e(TAG, "setOemNetworkPreference() failed for preference: " + preference.toString());
+ throw e.rethrowFromSystemServer();
+ }
}
@NonNull
diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
index db8b7ed3b177..e2672c480c10 100644
--- a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
+++ b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
@@ -29,6 +29,7 @@ import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.net.NetworkState;
+import android.net.OemNetworkPreferences;
import android.net.ProxyInfo;
import android.net.UidRange;
import android.net.QosSocketInfo;
@@ -240,4 +241,6 @@ interface IConnectivityManager
void registerQosSocketCallback(in QosSocketInfo socketInfo, in IQosCallback callback);
void unregisterQosCallback(in IQosCallback callback);
+
+ void setOemNetworkPreference(in OemNetworkPreferences preference);
}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
index c4d1b09a5c20..b9ef4c21ef6f 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
@@ -435,25 +435,7 @@ public class NetworkRequest implements Parcelable {
* @hide
*/
public boolean isRequest() {
- return isForegroundRequest() || isBackgroundRequest();
- }
-
- /**
- * Returns true iff. the contained NetworkRequest is one that:
- *
- * - should be associated with at most one satisfying network
- * at a time;
- *
- * - should cause a network to be kept up and in the foreground if
- * it is the best network which can satisfy the NetworkRequest.
- *
- * For full detail of how isRequest() is used for pairing Networks with
- * NetworkRequests read rematchNetworkAndRequests().
- *
- * @hide
- */
- public boolean isForegroundRequest() {
- return type == Type.TRACK_DEFAULT || type == Type.REQUEST;
+ return type == Type.REQUEST || type == Type.BACKGROUND_REQUEST;
}
/**
diff --git a/packages/Connectivity/framework/src/android/net/Proxy.java b/packages/Connectivity/framework/src/android/net/Proxy.java
index 03cfbbb4a22d..77c8a4f4579b 100644
--- a/packages/Connectivity/framework/src/android/net/Proxy.java
+++ b/packages/Connectivity/framework/src/android/net/Proxy.java
@@ -32,8 +32,6 @@ import java.net.InetSocketAddress;
import java.net.ProxySelector;
import java.net.URI;
import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
/**
* A convenience class for accessing the user and default proxy
@@ -66,40 +64,9 @@ public final class Proxy {
@Deprecated
public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO";
- /** @hide */
- public static final int PROXY_VALID = 0;
- /** @hide */
- public static final int PROXY_HOSTNAME_EMPTY = 1;
- /** @hide */
- public static final int PROXY_HOSTNAME_INVALID = 2;
- /** @hide */
- public static final int PROXY_PORT_EMPTY = 3;
- /** @hide */
- public static final int PROXY_PORT_INVALID = 4;
- /** @hide */
- public static final int PROXY_EXCLLIST_INVALID = 5;
-
private static ConnectivityManager sConnectivityManager = null;
- // Hostname / IP REGEX validation
- // Matches blank input, ips, and domain names
- private static final String NAME_IP_REGEX =
- "[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*(\\.[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*)*";
-
- private static final String HOSTNAME_REGEXP = "^$|^" + NAME_IP_REGEX + "$";
-
- private static final Pattern HOSTNAME_PATTERN;
-
- private static final String EXCL_REGEX =
- "[a-zA-Z0-9*]+(\\-[a-zA-Z0-9*]+)*(\\.[a-zA-Z0-9*]+(\\-[a-zA-Z0-9*]+)*)*";
-
- private static final String EXCLLIST_REGEXP = "^$|^" + EXCL_REGEX + "(," + EXCL_REGEX + ")*$";
-
- private static final Pattern EXCLLIST_PATTERN;
-
static {
- HOSTNAME_PATTERN = Pattern.compile(HOSTNAME_REGEXP);
- EXCLLIST_PATTERN = Pattern.compile(EXCLLIST_REGEXP);
sDefaultProxySelector = ProxySelector.getDefault();
}
@@ -218,33 +185,6 @@ public final class Proxy {
return false;
}
- /**
- * Validate syntax of hostname, port and exclusion list entries
- * {@hide}
- */
- public static int validate(String hostname, String port, String exclList) {
- Matcher match = HOSTNAME_PATTERN.matcher(hostname);
- Matcher listMatch = EXCLLIST_PATTERN.matcher(exclList);
-
- if (!match.matches()) return PROXY_HOSTNAME_INVALID;
-
- if (!listMatch.matches()) return PROXY_EXCLLIST_INVALID;
-
- if (hostname.length() > 0 && port.length() == 0) return PROXY_PORT_EMPTY;
-
- if (port.length() > 0) {
- if (hostname.length() == 0) return PROXY_HOSTNAME_EMPTY;
- int portVal = -1;
- try {
- portVal = Integer.parseInt(port);
- } catch (NumberFormatException ex) {
- return PROXY_PORT_INVALID;
- }
- if (portVal <= 0 || portVal > 0xFFFF) return PROXY_PORT_INVALID;
- }
- return PROXY_VALID;
- }
-
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@Deprecated
diff --git a/packages/Connectivity/framework/src/android/net/ProxyInfo.java b/packages/Connectivity/framework/src/android/net/ProxyInfo.java
index 9c9fed102828..229db0d717cd 100644
--- a/packages/Connectivity/framework/src/android/net/ProxyInfo.java
+++ b/packages/Connectivity/framework/src/android/net/ProxyInfo.java
@@ -23,6 +23,8 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import com.android.net.module.util.ProxyUtils;
+
import java.net.InetSocketAddress;
import java.net.URLConnection;
import java.util.List;
@@ -233,7 +235,7 @@ public class ProxyInfo implements Parcelable {
*/
public boolean isValid() {
if (!Uri.EMPTY.equals(mPacFileUrl)) return true;
- return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost,
+ return ProxyUtils.PROXY_VALID == ProxyUtils.validate(mHost == null ? "" : mHost,
mPort == 0 ? "" : Integer.toString(mPort),
mExclusionList == null ? "" : mExclusionList);
}
diff --git a/packages/Connectivity/framework/src/android/net/VpnManager.java b/packages/Connectivity/framework/src/android/net/VpnManager.java
index c87b8279c4d6..1812509ba6d2 100644
--- a/packages/Connectivity/framework/src/android/net/VpnManager.java
+++ b/packages/Connectivity/framework/src/android/net/VpnManager.java
@@ -21,6 +21,7 @@ import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
@@ -28,6 +29,8 @@ import android.content.Intent;
import android.content.res.Resources;
import android.os.RemoteException;
+import com.android.internal.net.LegacyVpnInfo;
+import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
import java.io.IOException;
@@ -161,4 +164,104 @@ public class VpnManager {
throw e.rethrowFromSystemServer();
}
}
-}
+
+ /**
+ * Return the VPN configuration for the given user ID.
+ * @hide
+ */
+ @Nullable
+ public VpnConfig getVpnConfig(@UserIdInt int userId) {
+ try {
+ return mService.getVpnConfig(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Prepare for a VPN application.
+ * VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId},
+ * {@link android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
+ *
+ * @param oldPackage Package name of the application which currently controls VPN, which will
+ * be replaced. If there is no such application, this should should either be
+ * {@code null} or {@link VpnConfig.LEGACY_VPN}.
+ * @param newPackage Package name of the application which should gain control of VPN, or
+ * {@code null} to disable.
+ * @param userId User for whom to prepare the new VPN.
+ *
+ * @hide
+ */
+ public boolean prepareVpn(@Nullable String oldPackage, @Nullable String newPackage,
+ int userId) {
+ try {
+ return mService.prepareVpn(oldPackage, newPackage, userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Set whether the VPN package has the ability to launch VPNs without user intervention. This
+ * method is used by system-privileged apps. VPN permissions are checked in the {@link Vpn}
+ * class. If the caller is not {@code userId}, {@link
+ * android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
+ *
+ * @param packageName The package for which authorization state should change.
+ * @param userId User for whom {@code packageName} is installed.
+ * @param vpnType The {@link VpnManager.VpnType} constant representing what class of VPN
+ * permissions should be granted. When unauthorizing an app, {@link
+ * VpnManager.TYPE_VPN_NONE} should be used.
+ * @hide
+ */
+ public void setVpnPackageAuthorization(
+ String packageName, int userId, @VpnManager.VpnType int vpnType) {
+ try {
+ mService.setVpnPackageAuthorization(packageName, userId, vpnType);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Return the legacy VPN information for the specified user ID.
+ * @hide
+ */
+ public LegacyVpnInfo getLegacyVpnInfo(@UserIdInt int userId) {
+ try {
+ return mService.getLegacyVpnInfo(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Starts a legacy VPN.
+ * @hide
+ */
+ public void startLegacyVpn(VpnProfile profile) {
+ try {
+ mService.startLegacyVpn(profile);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Informs the service that legacy lockdown VPN state should be updated (e.g., if its keystore
+ * entry has been updated). If the LockdownVpn mechanism is enabled, updates the vpn
+ * with a reload of its profile.
+ *
+ * <p>This method can only be called by the system UID
+ * @return a boolean indicating success
+ *
+ * @hide
+ */
+ public boolean updateLockdownVpn() {
+ try {
+ return mService.updateLockdownVpn();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 3837743a0ff8..889980a05bfa 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Sal nie outomaties koppel nie"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Geen internettoegang nie"</string>
<string name="saved_network" msgid="7143698034077223645">"Gestoor deur <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Gekoppel aan beperkte netwerk"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Outomaties deur %1$s gekoppel"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Outomaties deur netwerkgraderingverskaffer gekoppel"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Gekoppel via %1$s"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 4ce01d68a5ae..c41e4d5d5869 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"በራስ-ሰር አይገናኝም"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"ምንም የበይነመረብ መዳረሻ ያለም"</string>
<string name="saved_network" msgid="7143698034077223645">"የተቀመጠው በ<xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"ከሚለካ አውታረ መረብ ጋር ተገናኝቷል"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"በ%1$s በኩል በራስ-ሰር ተገናኝቷል"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"በአውታረ መረብ ደረጃ ሰጪ አቅራቢ በኩል በራስ-ሰር ተገናኝቷል"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"በ%1$s በኩል መገናኘት"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 2580d0fc82cc..f8d1d576c759 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"لن يتم الاتصال تلقائيًا"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"لا يتوفّر اتصال بالإنترنت"</string>
<string name="saved_network" msgid="7143698034077223645">"تم الحفظ بواسطة <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"تم الاتصال بشبكة تفرض تكلفة استخدام."</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"‏تم الاتصال تلقائيًا عبر %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"تم الاتصال تلقائيًا عبر مقدم خدمة تقييم الشبكة"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"‏تم الاتصال عبر %1$s"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index b61ff508cfe7..c6078f898c3e 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"স্বয়ংক্ৰিয়ভাৱে সংযোগ নহ’ব"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"ইণ্টাৰনেট সংযোগ নাই"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g>এ ছেভ কৰিছে"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"নিৰিখ-নিৰ্দিষ্ট নেটৱৰ্কৰ সৈতে সংযোগ কৰা হৈছে"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s মাধ্যমেদি স্বয়ংক্ৰিয়ভাৱে সংযোগ কৰা হৈছে"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"নেটৱৰ্ক ৰেটিং প্ৰদানকাৰীৰ জৰিয়তে স্বয়ং সংয়োগ কৰা হ’ল"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s-ৰ মাধ্যমেদি সংযোগ কৰা হৈছে"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index d06377677a50..d3e0a25593e4 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Avtomatik qoşulmayacaq"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"İnternet girişi yoxdur"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> tərəfindən saxlandı"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Ölçülən şəbəkəyə qoşulub"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s üzərindən avtomatik qoşuldu"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Avtomatik olaraq şəbəkə reytinq provayderi ilə qoşuludur"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s vasitəsilə qoşuludur"</string>
@@ -313,7 +312,7 @@
<string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"Adsız Bluetooth cihazları (yalnız MAC ünvanları) göstəriləcək"</string>
<string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"Uzaqdan idarə olunan cihazlarda dözülməz yüksək səs həcmi və ya nəzarət çatışmazlığı kimi səs problemləri olduqda Bluetooth mütləq səs həcmi xüsusiyyətini deaktiv edir."</string>
<string name="bluetooth_enable_gabeldorsche_summary" msgid="2054730331770712629">"Bluetooth Gabeldorsche funksiyasını aktiv edir."</string>
- <string name="enhanced_connectivity_summary" msgid="1576414159820676330">"Təkmilləşdirilmiş Bağlantı funksiyasını aktiv edir."</string>
+ <string name="enhanced_connectivity_summary" msgid="1576414159820676330">"Qabaqcıl məlumat mübadiləsini aktiv edir."</string>
<string name="enable_terminal_title" msgid="3834790541986303654">"Yerli terminal"</string>
<string name="enable_terminal_summary" msgid="2481074834856064500">"Yerli örtük girişini təklif edən terminal tətbiqi aktiv edin"</string>
<string name="hdcp_checking_title" msgid="3155692785074095986">"HDCP yoxlanılır"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 2976bb5893b6..85412224e995 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Automatsko povezivanje nije uspelo"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Nema pristupa internetu"</string>
<string name="saved_network" msgid="7143698034077223645">"Sačuvao/la je <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Povezani ste na mrežu sa ograničenjem"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatski povezano preko %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatski povezano preko dobavljača ocene mreže"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Veza je uspostavljena preko pristupne tačke %1$s"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 7af9e9323e05..aab600f3330e 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Не будзе аўтаматычна падключацца"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Няма доступу да інтэрнэту"</string>
<string name="saved_network" msgid="7143698034077223645">"Захавана праз: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Падключана да сеткі з падлікам трафіка"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Аўтаматычна падключана праз %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Аўтаматычна падключана праз пастаўшчыка паслугі ацэнкі сеткі"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Падключана праз %1$s"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 77b6493931f7..92f293599f97 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Няма да се свърже автоматично"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Няма достъп до интернет"</string>
<string name="saved_network" msgid="7143698034077223645">"Запазено от <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Установена е връзка с мрежа с отчитане"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Автоматично е установена връзка чрез %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Автоматично е установена връзка чрез доставчик на услуги за оценяване на мрежите"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Установена е връзка през „%1$s“"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 819625b67725..b40e24e3a672 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"অটোমেটিক কানেক্ট করবে না"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"ইন্টারনেট অ্যাক্সেস নেই"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> দ্বারা সেভ করা"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"মিটার্ড নেটওয়ার্কের সঙ্গে কানেক্ট করা"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"স্বয়ংক্রিয়ভাবে %1$s এর মাধ্যমে কানেক্ট হয়েছে"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"নেটওয়ার্কের রেটিং প্রদানকারীর মাধ্যমে অটোমেটিক কানেক্ট"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s মাধ্যমে কানেক্ট হয়েছে"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 193ac6066e40..cec2e4533878 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Neće se automatski povezati"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Nema pristupa internetu"</string>
<string name="saved_network" msgid="7143698034077223645">"Sačuvano: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Povezani ste s mrežom s naplatom"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatski povezano koristeći %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatski povezano putem ocjenjivača mreže"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Povezani preko %1$s"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index fef9bfb5c8c2..6134da873a0e 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"No es connectarà automàticament"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"No hi ha accés a Internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Desada per <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Connectat a una xarxa d\'ús mesurat"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Connectada automàticament a través de: %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Connectada automàticament a través d\'un proveïdor de valoració de xarxes"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Connectada mitjançant %1$s"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 281a78850e00..f29a3dd54ff8 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Připojení nebude automaticky navázáno"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Nebyl zjištěn žádný přístup k internetu"</string>
<string name="saved_network" msgid="7143698034077223645">"Uloženo uživatelem <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Připojeno k měřené síti"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automaticky připojeno přes poskytovatele %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automaticky připojeno přes poskytovatele hodnocení sítí"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Připojeno prostřednictvím %1$s"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 69cc8d805091..d92d41d536bc 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Der oprettes ikke automatisk forbindelse"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Ingen internetadgang"</string>
<string name="saved_network" msgid="7143698034077223645">"Gemt af <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Der er oprettet forbindelse til det forbrugsbaserede netværk"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatisk tilsluttet via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatisk forbundet via udbyder af netværksvurdering"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Tilsluttet via %1$s"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 737ea167a8c9..ac05b620539c 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Kein automatischer Verbindungsaufbau"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Kein Internetzugriff"</string>
<string name="saved_network" msgid="7143698034077223645">"Gespeichert von <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Mit kostenpflichtigem Netzwerk verbunden"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatisch über %1$s verbunden"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatisch über Anbieter von Netzwerkbewertungen verbunden"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Über %1$s verbunden"</string>
@@ -287,7 +286,7 @@
<string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Verringert den Akkuverbrauch und verbessert die Netzwerkleistung"</string>
<string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Wenn dieser Modus aktiviert ist, kann sich die MAC-Adresse dieses Geräts bei jeder Verbindung mit einem Netzwerk ändern, bei dem die MAC-Adressen randomisiert werden."</string>
<string name="wifi_metered_label" msgid="8737187690304098638">"Kostenpflichtig"</string>
- <string name="wifi_unmetered_label" msgid="6174142840934095093">"Kostenlos"</string>
+ <string name="wifi_unmetered_label" msgid="6174142840934095093">"Ohne Datenlimit"</string>
<string name="select_logd_size_title" msgid="1604578195914595173">"Logger-Puffergrößen"</string>
<string name="select_logd_size_dialog_title" msgid="2105401994681013578">"Größe pro Protokollpuffer wählen"</string>
<string name="dev_logpersist_clear_warning_title" msgid="8631859265777337991">"Speicher der dauerhaften Protokollierung löschen?"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 8e1d5e3d1b18..0b11d69132c5 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Δεν θα συνδεθεί αυτόματα"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Δεν υπάρχει πρόσβαση στο διαδίκτυο"</string>
<string name="saved_network" msgid="7143698034077223645">"Αποθηκεύτηκε από <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Σύνδεση σε δίκτυο με ογκοχρέωση"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Συνδέθηκε αυτόματα μέσω %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Συνδέθηκε αυτόματα μέσω παρόχου αξιολόγησης δικτύου"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Συνδέθηκε μέσω %1$s"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index f79072fff1e9..1da8e37186c6 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"No se conectará automáticamente"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"No hay acceso a Internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Guardada por <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Conectado a la red de uso medido"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Conexión automática mediante %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Conectado automáticamente mediante proveedor de calificación de red"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Conexión a través de %1$s"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index f99a3f12307b..54226ce0fe5c 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"No se establecerá conexión automáticamente"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"No se ha detectado ningún acceso a Internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Guardada por <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Conectado a una red de uso medido"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Conectada automáticamente a través de %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Conectado automáticamente a través de un proveedor de valoración de redes"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Conectado a través de %1$s"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index fa2aa467d0c5..4c747e36ef52 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Automaatselt ei ühendata"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Juurdepääs Internetile puudub"</string>
<string name="saved_network" msgid="7143698034077223645">"Salvestas: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Ühendatud mahupõhise võrguga"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Ühendus loodi automaatselt teenusega %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Ühendus loodi automaatselt võrgukvaliteedi hinnangute pakkuja kaudu"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Ühendatud üksuse %1$s kaudu"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 2c4a8ee09f5e..6016cd20ff37 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Ez da konektatuko automatikoki"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Ezin da konektatu Internetera"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> aplikazioak gorde du"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Sare neurtu batera konektatuta"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s bidez automatikoki konektatuta"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatikoki konektatuta sare-balorazioen hornitzailearen bidez"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s bidez konektatuta"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 1c6ca763197a..e85557000a61 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -36,10 +36,9 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"اتصال به‌صورت خودکار انجام نمی‌شود"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"دسترسی به اینترنت ندارد"</string>
<string name="saved_network" msgid="7143698034077223645">"ذخیره‌شده توسط <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"اتصال به شبکه محدود برقرار شد"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"‏اتصال خودکار ازطریق %1$s"</string>
- <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"اتصال خودکار ازطریق ارائه‌دهنده رتبه‌بندی شبکه"</string>
+ <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"اتصال خودکار ازطریق ارائه‌دهنده رده‌بندی شبکه"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"‏متصل از طریق %1$s"</string>
<string name="connected_via_app" msgid="3532267661404276584">"متصل شده ازطریق <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"‏در دسترس از طریق %1$s"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 04c9130ec31f..724e52a95927 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Yhteyttä ei muodosteta automaattisesti"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Ei internetyhteyttä"</string>
<string name="saved_network" msgid="7143698034077223645">"Tallentaja: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Yhdistetty maksulliseen verkkoon"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automaattinen yhteys muodostettu palvelun %1$s kautta"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Yhdistetty automaattisesti verkon arviointipalvelun kautta"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Yhdistetty seuraavan kautta: %1$s"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index aa0cd2a684c7..74c3005b0228 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Reconnexion automatique impossible"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Aucun accès à Internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Enregistrés par <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Appareil connecté à un réseau mesuré"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatiquement connecté par %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Connecté automatiquement par le fournisseur d\'avis sur le réseau"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Connecté par %1$s"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index dbdc160030fa..c9651ce570c5 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Reconnexion automatique impossible"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Aucun accès à Internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Enregistré lors de : <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Connecté au réseau facturé à l\'usage"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Connecté automatiquement via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Connecté automatiquement via un fournisseur d\'évaluation de l\'état du réseau"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Connecté via %1$s"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 90c130301a8f..f499f587a850 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Non se conectará automaticamente"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Sen acceso a Internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Gardada por <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Estableceuse conexión coa rede de pago por consumo"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Conectouse automaticamente a través de %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Conectada automaticamente a través dun provedor de valoración de redes"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Conectado a través de %1$s"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 4caeda279849..23ee1de46484 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"ઑટોમૅટિક રીતે કનેક્ટ કરશે નહીં"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"કોઈ ઇન્ટરનેટ ઍક્સેસ નથી"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા સચવાયું"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"મીટર્ડ (ડેટા નિયંત્રણ) નેટવર્ક સાથે કનેક્ટેડ છે"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s દ્વારા સ્વત: કનેક્ટ થયેલ"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"નેટવર્ક રેટિંગ પ્રદાતા દ્વારા ઑટોમૅટિક રીતે કનેક્ટ થયું"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s દ્વારા કનેક્ટ થયેલ"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 468808be918a..a2fc43c250cc 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"अपने आप कनेक्ट नहीं होगा"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"इंटरनेट नहीं है"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> के द्वारा सहेजा गया"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"सीमित डेटा वाले नेटवर्क से कनेक्ट किया गया"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s के ज़रिए ऑटोमैटिक रूप से कनेक्ट है"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"नेटवर्क रेटिंग कंपनी के ज़रिए अपने आप कनेक्ट है"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s के द्वारा उपलब्ध"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 932c2560f2d9..396051d51a09 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Neće se povezati automatski"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Nema pristupa internetu"</string>
<string name="saved_network" msgid="7143698034077223645">"Spremila aplik. <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Povezano s mrežom s ograničenim prometom"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatski povezan putem %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatski povezan putem ocjenjivača mreže"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Povezano putem %1$s"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index fbaffac6b083..0c9bc54c0861 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Nem csatlakozik automatikusan"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Nincs internet-hozzáférés"</string>
<string name="saved_network" msgid="7143698034077223645">"Mentette: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Forgalomkorlátos hálózathoz csatlakozva"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatikusan csatlakozott a következőn keresztül: %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatikusan csatlakozott a hálózatértékelés szolgáltatóján keresztül"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Csatlakozva a következőn keresztül: %1$s"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 224d6418b5d5..56c93b635e20 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Չի միանա ավտոմատ"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Ինտերնետ կապ չկա"</string>
<string name="saved_network" msgid="7143698034077223645">"Ով է պահել՝ <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Միացած է վճարովի թրաֆիկով ցանցի"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Ավտոմատ կերպով կապակցվել է %1$s-ի միջոցով"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Ավտոմատ միացել է ցանցերի վարկանիշի մատակարարի միջոցով"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Միացված է %1$s-ի միջոցով"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 8cf13cde6a42..0440f4796143 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Tidak akan tersambung otomatis"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Tidak ada akses internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Disimpan oleh <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Terhubung ke jaringan berbayar"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Tersambung otomatis melalui %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Otomatis tersambung melalui penyedia rating jaringan"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Terhubung melalui %1$s"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index aa8893e4783a..0bb294f5869b 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Mun ekki tengjast sjálfkrafa"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Enginn netaðgangur"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> vistaði"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Tengdist neti með mældri notkun"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Sjálfkrafa tengt um %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Sjálfkrafa tengt um netgæðaveitu"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Tengt í gegnum %1$s"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 0199f549d099..54049d79a76b 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Non verrà eseguita la connessione automatica"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Nessun accesso a Internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Salvata da <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Connessione a rete a consumo effettuata"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Collegato automaticamente tramite %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Collegato automaticamente tramite fornitore di servizi di valutazione rete"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Collegato tramite %1$s"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index a50a22d2d08d..6cc4347946f4 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"לא יתבצע חיבור באופן אוטומטי"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"אין גישה לאינטרנט"</string>
<string name="saved_network" msgid="7143698034077223645">"נשמר על ידי <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"יש חיבור לרשת המבוססת על חיוב לפי שימוש בנתונים"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"‏מחובר אוטומטית דרך %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"מחובר אוטומטית דרך ספק של דירוג רשת"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"‏מחובר דרך %1$s"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index a1d1b70d607e..ec674adb75d0 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"自動的に接続されません"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"インターネット接続なし"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g>で保存"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"従量制ネットワークに接続しました"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s 経由で自動的に接続しています"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"ネットワーク評価プロバイダ経由で自動的に接続しています"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s経由で接続"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 77fd4b156024..30ab3b49afdd 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"ავტომატურად დაკავშირება ვერ მოხერხდება"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"ინტერნეტ-კავშირი არ არის"</string>
<string name="saved_network" msgid="7143698034077223645">"შენახული <xliff:g id="NAME">%1$s</xliff:g>-ის მიერ"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"დაკავშირებულია ფასიან ქსელთან"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"ავტომატურად დაკავშირდა %1$s-ის მეშვეობით"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"ავტომატურად დაკავშირდა ქსელის ხარისხის შეფასების პროვაიდერის მეშვეობით"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s-ით დაკავშირებული"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index eb5cd54e4f19..ef7852710af4 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Автоматты қосылмайды"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Интернетпен байланыс жоқ"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> сақтаған"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Трафик саналатын желіге қосылды."</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s арқылы автоматты қосылды"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Желі рейтингі провайдері арқылы автоматты түрде қосылған"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s арқылы қосылған"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 38abb805cb10..ed59c747f8fd 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"នឹងមិនភ្ជាប់ដោយស្វ័យប្រវត្តិទេ"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"មិនមាន​ការតភ្ជាប់​អ៊ីនធឺណិតទេ"</string>
<string name="saved_network" msgid="7143698034077223645">"បានរក្សាទុកដោយ <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"បានភ្ជាប់ទៅ​បណ្ដាញដែលផ្អែកតាមទិន្នន័យដែលប្រើ"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"បានភ្ជាប់ដោយស្វ័យប្រវត្តិតាមរយៈ %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"បានភ្ជាប់​ដោយស្វ័យប្រវត្តិ​តាម​រយៈក្រុមហ៊ុនផ្តល់​ការ​វាយ​តម្លៃលើ​បណ្តាញ"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"បានភ្ជាប់តាមរយៈ %1$s"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 560fba15bbad..995dc8632e5c 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶವಿಲ್ಲ"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> ನಿಂದ ಉಳಿಸಲಾಗಿದೆ"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"ಮಾಪನ ಮಾಡಲಾದ ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s ಮೂಲಕ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"ನೆಟ್‌ವರ್ಕ್ ರೇಟಿಂಗ್ ಒದಗಿಸುವವರ ಮೂಲಕ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s ಮೂಲಕ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index f43ce16368cb..7863d481295e 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"자동으로 연결되지 않습니다."</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"인터넷에 연결되어 있지 않음"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g>(으)로 저장됨"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"데이터 전송량 제한이 있는 네트워크에 연결됨"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s을(를) 통해 자동으로 연결됨"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"네트워크 평가 제공업체를 통해 자동으로 연결됨"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s을(를) 통해 연결됨"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 35b1ecacd505..45d05c6372ce 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Автоматтык түрдө туташпайт"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Интернетке туташпай турат"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> тарабынан сакталды"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Чектелген трафикке туташтырылды"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s аркылуу автоматтык түрдө туташты"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Тармактар рейтингинин булагы аркылуу автоматтык түрдө туташты"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s аркылуу жеткиликтүү"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index f60fe7f8affc..ca6e06c13892 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"ຈະບໍ່ເຊື່ອມຕໍ່ອັດຕະໂນມັດ"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ"</string>
<string name="saved_network" msgid="7143698034077223645">"ບັນທຶກ​​​ໂດຍ <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"ເຊື່ອມຕໍ່ຫາເຄືອຂ່າຍທີ່ມີການວັດແທກແລ້ວ"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"ເຊື່ອມຕໍ່ຜ່ານທາງ %1$s ໂດຍອັດຕະໂນມັດ"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"ເຊື່ອມຕໍ່ກັບອັດຕະໂນມັດແລ້ວຜ່ານຜູ້ໃຫ້ບໍລິການຄະແນນເຄືອຂ່າຍ"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"​ເຊື່ອມຕໍ່​ຜ່ານ %1$s ​ແລ້ວ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index e66e3c5a9944..173b57eaba57 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Nebus automatiškai prisijungiama"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Nėra interneto ryšio"</string>
<string name="saved_network" msgid="7143698034077223645">"Išsaugojo <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Prisijungta prie matuojamo tinklo"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatiškai prisijungta naudojant „%1$s“"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatiškai prisijungta naudojant tinklo įvertinimo paslaugos teikėjo paslaugomis"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Prisijungta naudojant „%1$s“"</string>
@@ -208,7 +207,7 @@
<string name="enable_adb" msgid="8072776357237289039">"USB perkrova"</string>
<string name="enable_adb_summary" msgid="3711526030096574316">"Derinimo režimas, kai prijungtas USB"</string>
<string name="clear_adb_keys" msgid="3010148733140369917">"Panaikinti USB derinimo prieigos teises"</string>
- <string name="enable_adb_wireless" msgid="6973226350963971018">"Belaidžio ryšio derinimas"</string>
+ <string name="enable_adb_wireless" msgid="6973226350963971018">"Belaidžio ryšio derin."</string>
<string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Derinimo režimas, kai prisijungta prie „Wi‑Fi“"</string>
<string name="adb_wireless_error" msgid="721958772149779856">"Klaida"</string>
<string name="adb_wireless_settings" msgid="2295017847215680229">"Belaidžio ryšio derinimas"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 90bcc04d1212..0ef3f0eee6b5 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Не може да се поврзе автоматски"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Нема пристап до интернет"</string>
<string name="saved_network" msgid="7143698034077223645">"Зачувано од <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Поврзано на мрежа со ограничен интернет"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Автоматски поврзано преку %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Автоматски поврзано преку оценувач на мрежа"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Поврзано преку %1$s"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index ba1987bc1d88..e6289ae3591e 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"സ്വയമേവ കണക്‌റ്റുചെയ്യില്ല"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"ഇന്റർനെറ്റ് ആക്‌സസ് ഇല്ല"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> സംരക്ഷിച്ചത്"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"മീറ്റർ ചെയ്ത നെറ്റ്‌വർക്കിലേക്ക് കണക്റ്റ് ചെയ്തു"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s വഴി സ്വയമേവ ബന്ധിപ്പിച്ചു"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"നെറ്റ്‌വർക്ക് റേറ്റിംഗ് ദാതാവുമായി സ്വയം കണക്‌റ്റുചെയ്‌തു"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s വഴി ബന്ധിപ്പിച്ചു"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 45a831daee14..ead712c30b89 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Автоматаар холбогдохгүй"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Интернет хандалт алга"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> хадгалсан"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Хязгаартай сүлжээнд холбогдсон"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s-р автоматаар холбогдсон"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Сүлжээний үнэлгээ үзүүлэгчээр автоматаар холбогдох"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s-р холбогдсон"</string>
@@ -398,8 +397,8 @@
<item msgid="1282170165150762976">"Дижитал агуулгад зориулан тааруулсан өнгө"</item>
</string-array>
<string name="inactive_apps_title" msgid="5372523625297212320">"Зогсолтын горимын апп"</string>
- <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"Идэвхгүй байна. Унтраах/асаахын тулд дарна уу."</string>
- <string name="inactive_app_active_summary" msgid="8047630990208722344">"Идэвхтэй байна. Унтраах/асаахын тулд дарна уу."</string>
+ <string name="inactive_app_inactive_summary" msgid="3161222402614236260">"Идэвхгүй байна. Асаах/унтраахын тулд дарна уу."</string>
+ <string name="inactive_app_active_summary" msgid="8047630990208722344">"Идэвхтэй байна. Асаах/унтраахын тулд дарна уу."</string>
<string name="standby_bucket_summary" msgid="5128193447550429600">"Апп зогсолтын горимын төлөв:<xliff:g id="BUCKET"> %s</xliff:g>"</string>
<string name="transcode_settings_title" msgid="2581975870429850549">"Медиа хөрвүүлгийн тохиргоо"</string>
<string name="transcode_user_control" msgid="6176368544817731314">"Хөрвүүлгийн өгөгдмөлийг дарах"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 1e69b28fa4de..edcc71b17e8a 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"स्वयंचलितपणे कनेक्ट करणार नाही"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"इंटरनेट अ‍ॅक्सेस नाही"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> द्वारे सेव्ह केले"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"मर्यादित नेटवर्कशी कनेक्ट केले आहे"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s द्वारे स्वयंचलितपणे कनेक्ट केले"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"नेटवर्क रेटिंग प्रदात्याद्वारे स्वयंचलितपणे कनेक्ट केले"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s द्वारे कनेक्‍ट केले"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 71c9eeafc594..8a14437e3647 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Tidak akan menyambung secara automatik"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Tiada akses Internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Diselamatkan oleh <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Disambungkan kepada rangkaian bermeter"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Disambungkan secara automatik melalui %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Disambungkan secara automatik melalui pembekal penilaian rangkaian"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Disambungkan melalui %1$s"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 3b3983e5164e..377c8b241144 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"အလိုအလျောက်ချိတ်ဆက်မည်မဟုတ်ပါ"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"အင်တာနက် ချိတ်ဆက်မှု မရှိပါ"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> က သိမ်းဆည်းခဲ့သည်"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"အခမဲ့မဟုတ်သော ကွန်ရက်သို့ ချိတ်ဆက်ထားသည်"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s မှတစ်ဆင့် အလိုအလျောက် ချိတ်ဆက်ထားပါသည်"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"ကွန်ရက်အဆင့်သတ်မှတ်ပေးသူ မှတစ်ဆင့် အလိုအလျောက် ချိတ်ဆက်ထားပါသည်"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s မှတစ်ဆင့် ချိတ်ဆက်ထားသည်"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index a8c01b3db73c..f0e773b1833d 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Kobler ikke til automatisk"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Ingen internettilgang"</string>
<string name="saved_network" msgid="7143698034077223645">"Lagret av <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Koble til et nettverk med datamåling"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatisk tilkoblet via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatisk tilkoblet via leverandør av nettverksvurdering"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Tilkoblet via %1$s"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index c28563764a2d..0bde70fe209d 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"स्वतः जडान हुने छैन"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"इन्टरनेटमाथिको पहुँच छैन"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> द्वारा सुरक्षित गरियो"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"प्रयोगसम्बन्धी सीमा तोकिएको नेटवर्कमा कनेक्ट गरियो"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s मार्फत् स्वतः जडान गरिएको"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"नेटवर्कको दर्जा प्रदायक मार्फत स्वत: जडान गरिएको"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s मार्फत जडित"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 9f4ea68f4c64..2bc1e8c0f7f0 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Er wordt niet automatisch verbinding gemaakt"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Geen internettoegang"</string>
<string name="saved_network" msgid="7143698034077223645">"Opgeslagen door \'<xliff:g id="NAME">%1$s</xliff:g>\'"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Verbonden met netwerk met datalimiet"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatisch verbonden via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatisch verbonden via provider van netwerkbeoordelingen"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Verbonden via %1$s"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 31bd7af804e0..787c87182cd7 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"ସ୍ୱଚାଳିତ ଭାବେ ସଂଯୁକ୍ତ ହେବନାହିଁ"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"ଇଣ୍ଟରନେଟ୍‌ର କୌଣସି ଆକ୍‌ସେସ୍‌ ନାହିଁ"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> ଦ୍ୱାରା ସେଭ କରାଯାଇଛି"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"ମିଟରଯୁକ୍ତ ନେଟୱାର୍କ ସହ ସଂଯୋଗ କରାଯାଇଛି"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s ମାଧ୍ୟମରେ ଅଟୋମେଟିକାଲୀ ସଂଯୁକ୍ତ"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"ନେଟୱର୍କ ମୂଲ୍ୟାୟନ ପ୍ରଦାତାଙ୍କ ମାଧ୍ୟମରେ ଅଟୋମେଟିକାଲ୍ୟ ସଂଯୁକ୍ତ"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s ମାଧ୍ୟମରେ ସଂଯୁକ୍ତ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index f21c4cedfb71..9483e060081c 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾਵੇਗਾ"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"ਕੋਈ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> ਵੱਲੋਂ ਰੱਖਿਅਤ ਕੀਤਾ ਗਿਆ"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"ਮੀਟਰਬੱਧ ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਹੈ"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s ਰਾਹੀਂ ਆਪਣੇ-ਆਪ ਕਨੈਕਟ ਹੋਇਆ"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"ਨੈੱਟਵਰਕ ਰੇਟਿੰਗ ਪ੍ਰਦਾਨਕ ਰਾਹੀਂ ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਕਨੈਕਟ ਹੋਇਆ"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤਾ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index c9c4a6c31f49..c7f1595c86d0 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Nie można połączyć automatycznie"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Brak dostępu do internetu"</string>
<string name="saved_network" msgid="7143698034077223645">"Zapisane przez: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Połączono z siecią z pomiarem użycia danych"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatycznie połączono przez: %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatycznie połączono przez dostawcę ocen jakości sieci"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Połączono przez %1$s"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 4b710853f329..63d8b8f53f7f 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Nu se va conecta automat"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Nu există acces la internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Salvată de <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"S-a conectat la o rețea contorizată"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Conectată automat prin %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Conectată automat prin furnizor de evaluări ale rețelei"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Conectată prin %1$s"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 4aeb9855ff2b..ac43e493d73b 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Подключение не будет выполняться автоматически"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Без доступа к Интернету"</string>
<string name="saved_network" msgid="7143698034077223645">"Кто сохранил: <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Подключено к сети с ограниченным трафиком"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Автоматически подключено к %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Автоматически подключено через автора рейтинга сетей"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Подключено к %1$s"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index 525d4231eb4c..08fd9a03d7c4 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"ස්වයංක්‍රිය නැවත සම්බන්ධ නොවනු ඇත"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"අන්තර්ජාල ප්‍රවේශය නැත"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> විසින් සුරකින ලදී"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"මනුගත ජාලයට සම්බන්ධ කර ඇත"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s හරහා ස්වයංක්‍රියව සම්බන්ධ විය"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"ජාල ශ්‍රේණිගත සපයන්නා හරහා ස්වයංක්‍රියව සම්බන්ධ විය"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s හරහා සම්බන්ධ විය"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index ee9ae6a47d2f..8f05684e6de9 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Nedôjde k automatickému pripojeniu"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Žiadny prístup k internetu"</string>
<string name="saved_network" msgid="7143698034077223645">"Uložila aplikácia <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Pripojené k meranej sieti"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automaticky pripojené prostredníctvom %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automaticky pripojené prostredníctvom poskytovateľa hodnotenia siete"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Pripojené prostredníctvom %1$s"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index ff60a322dc1d..3dccf3b53f9c 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Samodejna vnovična vzpostavitev povezave se ne bo izvedla"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Ni dostopa do interneta"</string>
<string name="saved_network" msgid="7143698034077223645">"Shranil(-a): <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Povezano z omrežjem z omejenim prenosom podatkov"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Samodejno vzpostavljena povezava prek: %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Samodejno vzpostavljena povezava prek ponudnika ocenjevanja omrežij"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Vzpostavljena povezava prek: %1$s"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 78e6ed60c176..c09ad4c42fa4 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Nuk do të lidhet automatikisht"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Nuk ka qasje në internet"</string>
<string name="saved_network" msgid="7143698034077223645">"E ruajtur nga <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Lidhur me një rrjet me matje"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Lidhur automatikisht përmes %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Lidhur automatikisht nëpërmjet ofruesit të vlerësimit të rrjetit"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"E lidhur përmes %1$s"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 8bb9277ba42b..b5a91bfed1d0 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Аутоматско повезивање није успело"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Нема приступа интернету"</string>
<string name="saved_network" msgid="7143698034077223645">"Сачувао/ла је <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Повезани сте на мрежу са ограничењем"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Аутоматски повезано преко %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Аутоматски повезано преко добављача оцене мреже"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Веза је успостављена преко приступне тачке %1$s"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 03fb2238989c..16a1be606707 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Det går inte att ansluta automatiskt"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Ingen internetåtkomst"</string>
<string name="saved_network" msgid="7143698034077223645">"Sparades av <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Ansluten till nätverk med datapriser"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Automatiskt ansluten via %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Automatiskt ansluten via leverantör av nätverksbetyg"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Anslutet via %1$s"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 631a41346282..58896c87baaa 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Haiwezi kuunganisha kiotomatiki"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Hakuna muunganisho wa intaneti"</string>
<string name="saved_network" msgid="7143698034077223645">"Ilihifadhiwa na <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Imeunganishwa kwenye mtandao unaopima data"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Imeunganishwa kiotomatiki kupitia %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Imeunganishwa kiotomatiki kupitia mtoa huduma wa ukadiriaji wa mtandao"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Imeunganishwa kupitia %1$s"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 5796603a761a..71cf7d41fcc4 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"தானாக இணைக்கப்படாது"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"இண்டர்நெட் அணுகல் இல்லை"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> சேமித்தது"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"கட்டண நெட்வொர்க்குடன் இணைக்கப்பட்டுள்ளது"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s மூலம் தானாக இணைக்கப்பட்டது"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"நெட்வொர்க் மதிப்பீடு வழங்குநரால் தானாக இணைக்கப்பட்டது"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s வழியாக இணைக்கப்பட்டது"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 9027ca18fc79..c3a65e702a28 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"స్వయంచాలకంగా కనెక్ట్ కాదు"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> ద్వారా సేవ్ చేయబడింది"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"డేటా నియంత్రణ నెట్‌వర్క్‌కు కనెక్ట్ చేయబడింది"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s ద్వారా స్వయంచాలకంగా కనెక్ట్ చేయబడింది"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"నెట్‌వర్క్ రేటింగ్ ప్రదాత ద్వారా స్వయంచాలకంగా కనెక్ట్ చేయబడింది"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s ద్వారా కనెక్ట్ చేయబడింది"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 8358dbbfafa5..903accbdc7ff 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"จะไม่เชื่อมต่อโดยอัตโนมัติ"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"เข้าถึงอินเทอร์เน็ตไม่ได้"</string>
<string name="saved_network" msgid="7143698034077223645">"บันทึกโดย<xliff:g id="NAME">%1$s</xliff:g> แล้ว"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"เชื่อมต่อกับเครือข่ายแบบจำกัดปริมาณแล้ว"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"เชื่อมต่ออัตโนมัติผ่าน %1$s แล้ว"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"เชื่อมต่ออัตโนมัติผ่านผู้ให้บริการการจัดอันดับเครือข่าย"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"เชื่อมต่อผ่าน %1$s แล้ว"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index d5250a4581db..b259201fe029 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Hindi awtomatikong kokonekta"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Walang access sa internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Na-save ng <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Nakakonekta sa nakametrong network"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Awtomatikong nakakonekta sa pamamagitan ng %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Awtomatikong nakakonekta sa pamamagitan ng provider ng rating ng network"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Nakakonekta sa pamamagitan ng %1$s"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 8e0b889f5191..a0bc3626d086 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Otomatik olarak bağlanma"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"İnternet erişimi yok"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> tarafından kaydedildi"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Sayaçlı ağa bağlı"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s üzerinden otomatik olarak bağlı"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Ağ derecelendirme sağlayıcı aracılığıyla otomatik olarak bağlandı"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s üzerinden bağlı"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index c2f71c38d83e..509c8a602794 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Не під’єднуватиметься автоматично"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Немає доступу до Інтернету"</string>
<string name="saved_network" msgid="7143698034077223645">"Збережено додатком <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Установлено з\'єднання з мережею з тарифікацією трафіку"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Автоматично під’єднано через %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Автоматично під’єднано через постачальника оцінки якості мережі"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Під’єднано через %1$s"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index a0c5f94a2845..e097ab2f5789 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"خودکار طور پر منسلک نہیں ہو گا"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"انٹرنیٹ تک کوئی رسائی نہیں"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> کی جانب سے محفوظ کردہ"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"میٹرڈ نیٹ ورک سے منسلک ہے"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"‏‎%1$s کے ذریعے از خود منسلک کردہ"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"نیٹ ورک درجہ بندی کے فراہم کنندہ کے ذریعے از خود منسلک"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"‏منسلک بذریعہ ‎%1$s"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index 1fb610bad36e..8c2a95d5c316 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Avtomatik ravishda ulanilmaydi"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Internet aloqasi yo‘q"</string>
<string name="saved_network" msgid="7143698034077223645">"<xliff:g id="NAME">%1$s</xliff:g> tomonidan saqlangan"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Trafik hisoblanadigan tarmoqqa ulandi"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"%1$s orqali avtomatik ulandi"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Tarmoqlar reytingi muallifi orqali avtomatik ulandi"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"%1$s orqali ulangan"</string>
@@ -156,7 +155,7 @@
<string name="running_process_item_user_label" msgid="3988506293099805796">"Foydalanuvchi: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
<string name="launch_defaults_some" msgid="3631650616557252926">"Ba’zi birlamchi sozlamalar o‘rnatilgan"</string>
<string name="launch_defaults_none" msgid="8049374306261262709">"Birlamchi sozlamalar belgilanmagan"</string>
- <string name="tts_settings" msgid="8130616705989351312">"Nutq sintezi sozlamalari"</string>
+ <string name="tts_settings" msgid="8130616705989351312">"Matnni nutqqa aylantirish sozlamalari"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"Nutq sintezi"</string>
<string name="tts_default_rate_title" msgid="3964187817364304022">"Nutq tezligi"</string>
<string name="tts_default_rate_summary" msgid="3781937042151716987">"Matnni o‘qish tezligi"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 1f3ea486bd08..7a4d89bd4f22 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Sẽ không tự động kết nối"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Không có quyền truy cập Internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Do <xliff:g id="NAME">%1$s</xliff:g> lưu"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Đã kết nối với mạng có đo lượng dữ liệu"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Tự động được kết nối qua %1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Tự động được kết nối qua nhà cung cấp dịch vụ xếp hạng mạng"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Được kết nối qua %1$s"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 828d25fbe71b..7cd61fc5491c 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"无法自动连接"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"无法访问互联网"</string>
<string name="saved_network" msgid="7143698034077223645">"由“<xliff:g id="NAME">%1$s</xliff:g>”保存"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"已连接到按流量计费的网络"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"已通过%1$s自动连接"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"已自动连接(通过网络评分服务提供方)"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"已通过%1$s连接"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 54e1f41e9ed8..458071cd8cb2 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"不會自動連線"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"無法連接互聯網"</string>
<string name="saved_network" msgid="7143698034077223645">"由「<xliff:g id="NAME">%1$s</xliff:g>」儲存"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"已連結至按用量收費的網絡"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"已透過 %1$s 自動連線"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"已透過網絡評分供應商自動連線"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"已透過 %1$s 連線"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index b8f1f58b5691..867ed8b61c17 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"無法自動連線"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"沒有可用的網際網路連線"</string>
<string name="saved_network" msgid="7143698034077223645">"由「<xliff:g id="NAME">%1$s</xliff:g>」儲存"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"已連線到計量付費網路"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"已透過 %1$s 自動連線"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"已透過網路評分供應商自動連線"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"已透過 %1$s 連線"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index d680b66b56fa..e64dbd30dc82 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -36,8 +36,7 @@
<string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Ngeke ize ixhumeke ngokuzenzakalela"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Akukho ukufinyelela kwe-inthanethi"</string>
<string name="saved_network" msgid="7143698034077223645">"Kulondolozwe ngu-<xliff:g id="NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for connected_to_metered_access_point (9179693207918156341) -->
- <skip />
+ <string name="connected_to_metered_access_point" msgid="9179693207918156341">"Kuxhunywe kunethiwekhi eyenziwe imitha"</string>
<string name="connected_via_network_scorer" msgid="7665725527352893558">"Ixhumeke ngokuzenzakalela nge-%1$s"</string>
<string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Kuxhunywe ngokuzenzakalelayo ngomhlinzeki wesilinganiso wenethiwekhi"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Kuxhumeke nge-%1$s"</string>
diff --git a/packages/SystemUI/res/drawable/controls_dialog_bg.xml b/packages/SystemUI/res/drawable/controls_dialog_bg.xml
new file mode 100644
index 000000000000..cb4686dd04a7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/controls_dialog_bg.xml
@@ -0,0 +1,21 @@
+<?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
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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:attr/colorBackgroundFloating" />
+ <corners android:radius="@dimen/notification_corner_radius" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/udfps_progress_bar.xml b/packages/SystemUI/res/drawable/udfps_progress_bar.xml
new file mode 100644
index 000000000000..e5389f3b99ef
--- /dev/null
+++ b/packages/SystemUI/res/drawable/udfps_progress_bar.xml
@@ -0,0 +1,44 @@
+<?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
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@android:id/background">
+ <shape
+ android:innerRadiusRatio="2.2"
+ android:shape="ring"
+ android:thickness="@dimen/udfps_enroll_progress_thickness"
+ android:useLevel="false"
+ android:tint="?android:colorControlNormal">
+ <solid android:color="@*android:color/white_disabled_material" />
+ </shape>
+ </item>
+ <item android:id="@android:id/progress">
+ <rotate
+ android:fromDegrees="270"
+ android:pivotX="50%"
+ android:pivotY="50%"
+ android:toDegrees="270">
+ <shape
+ android:innerRadiusRatio="2.2"
+ android:shape="ring"
+ android:thickness="@dimen/udfps_enroll_progress_thickness"
+ android:tint="?android:attr/colorControlActivated">
+ <solid android:color="@android:color/white" />
+ </shape>
+ </rotate>
+ </item>
+</layer-list> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/controls_in_dialog.xml b/packages/SystemUI/res/layout/controls_in_dialog.xml
new file mode 100644
index 000000000000..983999f9a5f8
--- /dev/null
+++ b/packages/SystemUI/res/layout/controls_in_dialog.xml
@@ -0,0 +1,45 @@
+<?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
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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/control_detail_root"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginVertical="@dimen/controls_activity_view_top_offset"
+ android:layout_marginHorizontal="@dimen/controls_activity_view_side_offset"
+ android:padding="8dp"
+ android:orientation="vertical"
+ android:background="@drawable/controls_dialog_bg">
+
+ <com.android.systemui.globalactions.MinHeightScrollView
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:scrollbars="none">
+
+ <LinearLayout
+ android:id="@+id/global_actions_controls"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:orientation="vertical"
+ android:clipToPadding="false" />
+
+ </com.android.systemui.globalactions.MinHeightScrollView>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 04de9784812f..862076b650b9 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -81,6 +81,17 @@
android:contentDescription="@string/accessibility_phone_button"
android:tint="?attr/wallpaperTextColor" />
+ <ImageView
+ android:id="@+id/alt_left_button"
+ android:layout_height="@dimen/keyguard_affordance_height"
+ android:layout_width="@dimen/keyguard_affordance_width"
+ android:layout_gravity="bottom|start"
+ android:scaleType="center"
+ android:tint="?attr/wallpaperTextColor"
+ android:layout_marginStart="24dp"
+ android:layout_marginBottom="48dp"
+ android:visibility="gone" />
+
<FrameLayout
android:id="@+id/overlay_container"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/long_screenshot.xml b/packages/SystemUI/res/layout/long_screenshot.xml
index 8f3345f9d85c..e2f3e2a306e3 100644
--- a/packages/SystemUI/res/layout/long_screenshot.xml
+++ b/packages/SystemUI/res/layout/long_screenshot.xml
@@ -74,7 +74,7 @@
android:id="@+id/preview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginBottom="24dp"
+ android:layout_marginBottom="42dp"
android:layout_marginHorizontal="48dp"
android:adjustViewBounds="true"
app:layout_constrainedHeight="true"
@@ -91,19 +91,33 @@
android:id="@+id/crop_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginBottom="24dp"
+ android:layout_marginBottom="42dp"
app:layout_constrainedHeight="true"
app:layout_constrainedWidth="true"
app:layout_constraintTop_toBottomOf="@id/guideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
- app:handleThickness="3dp"
+ app:handleThickness="@dimen/screenshot_crop_handle_thickness"
app:handleColor="@*android:color/accent_device_default"
- app:scrimColor="#9444"
+ app:scrimColor="@color/screenshot_crop_scrim"
tools:background="?android:colorBackground"
tools:minHeight="100dp"
tools:minWidth="100dp" />
+ <com.android.systemui.screenshot.MagnifierView
+ android:id="@+id/magnifier"
+ android:visibility="invisible"
+ android:layout_width="200dp"
+ android:layout_height="200dp"
+ app:layout_constraintTop_toBottomOf="@id/guideline"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:handleThickness="@dimen/screenshot_crop_handle_thickness"
+ app:handleColor="@*android:color/accent_device_default"
+ app:scrimColor="@color/screenshot_crop_scrim"
+ app:borderThickness="4dp"
+ app:borderColor="#fff"
+ />
+
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/packages/SystemUI/res/layout/udfps_view.xml b/packages/SystemUI/res/layout/udfps_view.xml
index c0788051efed..6ae306e17209 100644
--- a/packages/SystemUI/res/layout/udfps_view.xml
+++ b/packages/SystemUI/res/layout/udfps_view.xml
@@ -20,4 +20,17 @@
android:id="@+id/udfps_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- systemui:sensorTouchAreaCoefficient="0.5"/>
+ systemui:sensorTouchAreaCoefficient="0.5">
+
+ <!-- Enrollment progress bar-->
+ <com.android.systemui.biometrics.UdfpsProgressBar
+ android:id="@+id/progress_bar"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:max="100"
+ android:padding="@dimen/udfps_enroll_progress_thickness"
+ android:progress="0"
+ android:layout_gravity="center"
+ android:visibility="gone"/>
+
+</com.android.systemui.biometrics.UdfpsView>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 6c55fb62e638..8166e35d5b6a 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -178,6 +178,14 @@
<attr name="scrimColor" format="color" />
</declare-styleable>
+ <declare-styleable name="MagnifierView">
+ <attr name="handleThickness" format="dimension" />
+ <attr name="handleColor" format="color" />
+ <attr name="scrimColor" format="color" />
+ <attr name="borderThickness" format="dimension" />
+ <attr name="borderColor" format="color" />
+ </declare-styleable>
+
<declare-styleable name="RoundedCornerProgressDrawable">
<attr name="android:drawable" />
</declare-styleable>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index a7cf3e91dbba..5fb6de7bb588 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -197,6 +197,9 @@
<color name="global_screenshot_dismiss_foreground">@color/GM2_grey_500</color>
<color name="global_screenshot_background_protection_start">#40000000</color> <!-- 25% black -->
+ <!-- Long screenshot UI -->
+ <color name="screenshot_crop_scrim">#9444</color>
+
<!-- GM2 colors -->
<color name="GM2_grey_50">#F8F9FA</color>
<color name="GM2_grey_100">#F1F3F4</color>
@@ -261,6 +264,7 @@
<color name="control_enabled_cool_foreground">@color/GM2_blue_300</color>
<color name="control_thumbnail_tint">#33000000</color>
<color name="control_thumbnail_shadow_color">@*android:color/black</color>
+ <color name="controls_lockscreen_scrim">#AA000000</color>
<!-- Docked misalignment message -->
<color name="misalignment_text_color">#F28B82</color>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index d92f4ea65390..afa98b56a13c 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -345,6 +345,7 @@
<dimen name="screenshot_action_chip_padding_end">16dp</dimen>
<dimen name="screenshot_action_chip_text_size">14sp</dimen>
<dimen name="screenshot_dismissal_height_delta">80dp</dimen>
+ <dimen name="screenshot_crop_handle_thickness">3dp</dimen>
<!-- The width of the view containing navigation buttons -->
@@ -1116,6 +1117,9 @@
<!-- Y translation for credential contents when animating in -->
<dimen name="biometric_dialog_credential_translation_offset">60dp</dimen>
+ <!-- UDFPS enrollment progress bar thickness -->
+ <dimen name="udfps_enroll_progress_thickness">12dp</dimen>
+
<!-- Wireless Charging Animation values -->
<dimen name="wireless_charging_dots_radius_start">0dp</dimen>
<dimen name="wireless_charging_dots_radius_end">4dp</dimen>
@@ -1259,6 +1263,7 @@
<!-- Home Controls activity view detail panel-->
<dimen name="controls_activity_view_top_offset">100dp</dimen>
+ <dimen name="controls_activity_view_side_offset">12dp</dimen>
<dimen name="controls_activity_view_text_size">17sp</dimen>
<dimen name="controls_activity_view_corner_radius">@*android:dimen/config_bottomDialogCornerRadius</dimen>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 4b04eebfddf0..7c72548a7252 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -662,6 +662,19 @@
<item name="android:windowExitAnimation">@anim/bottomsheet_out</item>
</style>
+ <style name="Theme.SystemUI.Dialog.Control.LockScreen" parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar">
+ <item name="android:windowAnimationStyle">@style/Animation.Fade</item>
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:windowIsFloating">false</item>
+ <item name="android:windowBackground">@color/controls_lockscreen_scrim</item>
+ <item name="android:backgroundDimEnabled">true</item>
+ </style>
+
+ <style name="Animation.Fade">
+ <item name="android:windowEnterAnimation">@android:anim/fade_in</item>
+ <item name="android:windowExitAnimation">@android:anim/fade_out</item>
+ </style>
+
<style name="Control" />
<style name="Control.MenuItem">
@@ -752,4 +765,12 @@
<item name="android:textSize">14sp</item>
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
</style>
+
+ <style name="UdfpsProgressBarStyle"
+ parent="android:style/Widget.Material.ProgressBar.Horizontal">
+ <item name="android:indeterminate">false</item>
+ <item name="android:max">10000</item>
+ <item name="android:mirrorForRtl">false</item>
+ <item name="android:progressDrawable">@drawable/udfps_progress_bar</item>
+ </style>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 055270ddf0b8..7d06dd6ab085 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -23,7 +23,6 @@ import static android.hardware.biometrics.BiometricManager.Authenticators;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
-import android.app.IActivityTaskManager;
import android.app.TaskStackListener;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -137,7 +136,8 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
mActivityTaskManager.getTasks(1);
if (!runningTasks.isEmpty()) {
final String topPackage = runningTasks.get(0).topActivity.getPackageName();
- if (!topPackage.contentEquals(clientPackage)) {
+ if (!topPackage.contentEquals(clientPackage)
+ && !Utils.isSystem(mContext, clientPackage)) {
Log.w(TAG, "Evicting client due to: " + topPackage);
mCurrentDialog.dismissWithoutCallback(true /* animate */);
mCurrentDialog = null;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java
index e07c84034b31..5290986b2a1c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationEnroll.java
@@ -38,6 +38,7 @@ public class UdfpsAnimationEnroll extends UdfpsAnimation {
private static final String TAG = "UdfpsAnimationEnroll";
private static final float SHADOW_RADIUS = 5.f;
+ private static final float PROGRESS_BAR_RADIUS = 140.f;
@Nullable private RectF mSensorRect;
@NonNull private final Paint mSensorPaint;
@@ -81,12 +82,12 @@ public class UdfpsAnimationEnroll extends UdfpsAnimation {
@Override
public int getPaddingX() {
- return (int) Math.ceil(SHADOW_RADIUS);
+ return (int) Math.ceil(PROGRESS_BAR_RADIUS);
}
@Override
public int getPaddingY() {
- return (int) Math.ceil(SHADOW_RADIUS);
+ return (int) Math.ceil(PROGRESS_BAR_RADIUS);
}
@Override
@@ -104,12 +105,4 @@ public class UdfpsAnimationEnroll extends UdfpsAnimation {
public int getOpacity() {
return 0;
}
-
- public void onEnrollmentProgress(int remaining) {
- Log.d(TAG, "Remaining: " + remaining);
- }
-
- public void onEnrollmentHelp() {
- Log.d(TAG, "onEnrollmentHelp");
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
index 4e3419e1fab3..41ea4d66f575 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsAnimationView.java
@@ -103,18 +103,6 @@ public class UdfpsAnimationView extends View implements DozeReceiver,
postInvalidate();
}
- void onEnrollmentProgress(int remaining) {
- if (mUdfpsAnimation instanceof UdfpsAnimationEnroll) {
- ((UdfpsAnimationEnroll) mUdfpsAnimation).onEnrollmentProgress(remaining);
- }
- }
-
- void onEnrollmentHelp() {
- if (mUdfpsAnimation instanceof UdfpsAnimationEnroll) {
- ((UdfpsAnimationEnroll) mUdfpsAnimation).onEnrollmentHelp();
- }
- }
-
public int getPaddingX() {
if (mUdfpsAnimation == null) {
return 0;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index c088400f4057..e7b08e72877d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -84,6 +84,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
private boolean mIsOverlayRequested;
// Reason the overlay has been requested. See IUdfpsOverlayController for definitions.
private int mRequestReason;
+ @Nullable UdfpsEnrollHelper mEnrollHelper;
// The fingerprint AOD trigger doesn't provide an ACTION_UP/ACTION_CANCEL event to tell us when
// to turn off high brightness mode. To get around this limitation, the state of the AOD
@@ -95,6 +96,12 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
public class UdfpsOverlayController extends IUdfpsOverlayController.Stub {
@Override
public void showUdfpsOverlay(int sensorId, int reason) {
+ if (reason == IUdfpsOverlayController.REASON_ENROLL_FIND_SENSOR
+ || reason == IUdfpsOverlayController.REASON_ENROLL_ENROLLING) {
+ mEnrollHelper = new UdfpsEnrollHelper(reason);
+ } else {
+ mEnrollHelper = null;
+ }
UdfpsController.this.showOverlay(reason);
}
@@ -296,7 +303,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
try {
Log.v(TAG, "showUdfpsOverlay | adding window");
final UdfpsAnimation animation = getUdfpsAnimationForReason(reason);
- mView.setUdfpsAnimation(animation);
+ mView.setExtras(animation, mEnrollHelper);
mWindowManager.addView(mView, computeLayoutParams(animation));
mView.setOnTouchListener(mOnTouchListener);
mIsOverlayShowing = true;
@@ -313,7 +320,8 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
private UdfpsAnimation getUdfpsAnimationForReason(int reason) {
Log.d(TAG, "getUdfpsAnimationForReason: " + reason);
switch (reason) {
- case IUdfpsOverlayController.REASON_ENROLL:
+ case IUdfpsOverlayController.REASON_ENROLL_FIND_SENSOR:
+ case IUdfpsOverlayController.REASON_ENROLL_ENROLLING:
return new UdfpsAnimationEnroll(mContext);
case IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD:
return new UdfpsAnimationKeyguard(mView, mContext, mStatusBarStateController);
@@ -329,7 +337,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
mFgExecutor.execute(() -> {
if (mIsOverlayShowing) {
Log.v(TAG, "hideUdfpsOverlay | removing window");
- mView.setUdfpsAnimation(null);
+ mView.setExtras(null, null);
mView.setOnTouchListener(null);
// Reset the controller back to its starting state.
onFingerUp();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
new file mode 100644
index 000000000000..2442633a4a69
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
@@ -0,0 +1,60 @@
+/*
+ * 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.biometrics;
+
+import android.hardware.fingerprint.IUdfpsOverlayController;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Helps keep track of enrollment state and animates the progress bar accordingly.
+ */
+public class UdfpsEnrollHelper {
+ private static final String TAG = "UdfpsEnrollHelper";
+
+ // IUdfpsOverlayController reason
+ private final int mEnrollReason;
+
+ private int mTotalSteps = -1;
+ private int mCurrentProgress = 0;
+
+ public UdfpsEnrollHelper(int reason) {
+ mEnrollReason = reason;
+ }
+
+ boolean shouldShowProgressBar() {
+ return mEnrollReason == IUdfpsOverlayController.REASON_ENROLL_ENROLLING;
+ }
+
+ void onEnrollmentProgress(int remaining, @NonNull UdfpsProgressBar progressBar) {
+ if (mTotalSteps == -1) {
+ mTotalSteps = remaining;
+ }
+
+ mCurrentProgress = progressBar.getMax() * Math.max(0, mTotalSteps + 1 - remaining)
+ / (mTotalSteps + 1);
+ progressBar.setProgress(mCurrentProgress, true /* animate */);
+ }
+
+ void updateProgress(@NonNull UdfpsProgressBar progressBar) {
+ progressBar.setProgress(mCurrentProgress);
+ }
+
+ void onEnrollmentHelp() {
+
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsProgressBar.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsProgressBar.java
new file mode 100644
index 000000000000..84e2fab7bf6b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsProgressBar.java
@@ -0,0 +1,59 @@
+/*
+ * 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.biometrics;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ProgressBar;
+
+import com.android.systemui.R;
+
+/**
+ * A (determinate) progress bar in the form of a ring. The progress bar goes clockwise starting
+ * from the 12 o'clock position. This view maintain equal width and height using a strategy similar
+ * to "centerInside" for ImageView.
+ */
+public class UdfpsProgressBar extends ProgressBar {
+
+ public UdfpsProgressBar(Context context) {
+ this(context, null);
+ }
+
+ public UdfpsProgressBar(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public UdfpsProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, R.style.UdfpsProgressBarStyle);
+ }
+
+ public UdfpsProgressBar(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ final int measuredHeight = getMeasuredHeight();
+ final int measuredWidth = getMeasuredWidth();
+
+ final int length = Math.min(measuredHeight, measuredWidth);
+ setMeasuredDimension(length, length);
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
index 7e378d3c568e..00cb28b8b8fb 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.java
@@ -56,6 +56,8 @@ public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIllumin
@NonNull private final RectF mSensorRect;
@NonNull private final Paint mDebugTextPaint;
+ @Nullable private UdfpsProgressBar mProgressBar;
+
// Used to obtain the sensor location.
@NonNull private FingerprintSensorPropertiesInternal mSensorProps;
@@ -64,6 +66,7 @@ public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIllumin
private boolean mIlluminationRequested;
private int mStatusBarState;
private boolean mNotificationShadeExpanded;
+ @Nullable private UdfpsEnrollHelper mEnrollHelper;
public UdfpsView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -108,8 +111,17 @@ public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIllumin
mSensorProps = properties;
}
- void setUdfpsAnimation(@Nullable UdfpsAnimation animation) {
+ void setExtras(@Nullable UdfpsAnimation animation, @Nullable UdfpsEnrollHelper enrollHelper) {
mAnimationView.setAnimation(animation);
+ mEnrollHelper = enrollHelper;
+
+ if (enrollHelper != null) {
+ mEnrollHelper.updateProgress(mProgressBar);
+ mProgressBar.setVisibility(enrollHelper.shouldShowProgressBar()
+ ? View.VISIBLE : View.GONE);
+ } else {
+ mProgressBar.setVisibility(View.GONE);
+ }
}
@Override
@@ -138,6 +150,11 @@ public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIllumin
}
@Override
+ protected void onFinishInflate() {
+ mProgressBar = findViewById(R.id.progress_bar);
+ }
+
+ @Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mSensorRect.set(0 + mAnimationView.getPaddingX(),
@@ -233,10 +250,10 @@ public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIllumin
}
void onEnrollmentProgress(int remaining) {
- mAnimationView.onEnrollmentProgress(remaining);
+ mEnrollHelper.onEnrollmentProgress(remaining, mProgressBar);
}
void onEnrollmentHelp() {
- mAnimationView.onEnrollmentHelp();
+
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/Utils.java b/packages/SystemUI/src/com/android/systemui/biometrics/Utils.java
index fd5e85a953ad..076c7cbe3937 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/Utils.java
@@ -16,13 +16,16 @@
package com.android.systemui.biometrics;
+import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
import static android.hardware.biometrics.BiometricManager.Authenticators;
import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.hardware.biometrics.PromptInfo;
import android.hardware.biometrics.SensorPropertiesInternal;
import android.os.UserManager;
@@ -116,4 +119,10 @@ public class Utils {
return false;
}
+
+ static boolean isSystem(@NonNull Context context, @Nullable String clientPackage) {
+ final boolean hasPermission = context.checkCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL)
+ == PackageManager.PERMISSION_GRANTED;
+ return hasPermission && "android".equals(clientPackage);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsDialog.kt
new file mode 100644
index 000000000000..8e878cf76ad9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsDialog.kt
@@ -0,0 +1,90 @@
+/*
+ * 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.controls.ui
+
+import android.app.Dialog
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.view.View
+import android.view.ViewGroup
+import android.view.WindowManager
+
+import com.android.systemui.Interpolators
+import com.android.systemui.R
+import com.android.systemui.broadcast.BroadcastDispatcher
+
+/**
+ * Show the controls space inside a dialog, as from the lock screen.
+ */
+class ControlsDialog(
+ thisContext: Context,
+ val broadcastDispatcher: BroadcastDispatcher
+) : Dialog(thisContext, R.style.Theme_SystemUI_Dialog_Control_LockScreen) {
+
+ private val receiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ val action = intent.getAction()
+ if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
+ dismiss()
+ }
+ }
+ }
+
+ init {
+ window.setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG)
+ window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
+ or WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED)
+
+ setContentView(R.layout.controls_in_dialog)
+
+ requireViewById<ViewGroup>(R.id.control_detail_root).apply {
+ setOnClickListener { dismiss() }
+ (getParent() as View).setOnClickListener { dismiss() }
+ }
+ }
+
+ fun show(
+ controller: ControlsUiController
+ ): ControlsDialog {
+ super.show()
+
+ val vg = requireViewById<ViewGroup>(com.android.systemui.R.id.global_actions_controls)
+ vg.alpha = 0f
+ controller.show(vg, { /* do nothing */ })
+
+ vg.animate()
+ .alpha(1f)
+ .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
+ .setDuration(300)
+
+ val filter = IntentFilter()
+ filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
+ broadcastDispatcher.registerReceiver(receiver, filter)
+
+ return this
+ }
+
+ override fun dismiss() {
+ broadcastDispatcher.unregisterReceiver(receiver)
+
+ if (!isShowing()) return
+
+ super.dismiss()
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ContextualButton.java b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ContextualButton.java
index 453e85ae25c7..517f8e7f0dac 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ContextualButton.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/buttons/ContextualButton.java
@@ -51,7 +51,7 @@ public class ContextualButton extends ButtonDispatcher {
* Reload the drawable from resource id, should reapply the previous dark intensity.
*/
public void updateIcon(int lightIconColor, int darkIconColor) {
- if (getCurrentView() == null || !getCurrentView().isAttachedToWindow() || mIconResId == 0) {
+ if (mIconResId == 0) {
return;
}
final KeyButtonDrawable currentDrawable = getImageDrawable();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 6e28cd89d43a..56d06eb1b474 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -315,7 +315,8 @@ public class CustomTile extends QSTileImpl<State> implements TileChangeListener
}
try {
if (DEBUG) Log.d(TAG, "Adding token");
- mWindowManager.addWindowToken(mToken, TYPE_QS_DIALOG, DEFAULT_DISPLAY);
+ mWindowManager.addWindowToken(mToken, TYPE_QS_DIALOG, DEFAULT_DISPLAY,
+ null /* options */);
mIsTokenGranted = true;
} catch (RemoteException e) {
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
index 9037192e2ddc..543874325254 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
@@ -187,7 +187,7 @@ public class ScreenMediaRecorder {
* @param refreshRate Desired refresh rate
* @return array with supported width, height, and refresh rate
*/
- private int[] getSupportedSize(int screenWidth, int screenHeight, int refreshRate) {
+ private int[] getSupportedSize(final int screenWidth, final int screenHeight, int refreshRate) {
double maxScale = 0;
MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
@@ -207,25 +207,33 @@ public class ScreenMediaRecorder {
int width = vc.getSupportedWidths().getUpper();
int height = vc.getSupportedHeights().getUpper();
- if (width >= screenWidth && height >= screenHeight
- && vc.isSizeSupported(screenWidth, screenHeight)) {
+ int screenWidthAligned = screenWidth;
+ if (screenWidthAligned % vc.getWidthAlignment() != 0) {
+ screenWidthAligned -= (screenWidthAligned % vc.getWidthAlignment());
+ }
+ int screenHeightAligned = screenHeight;
+ if (screenHeightAligned % vc.getHeightAlignment() != 0) {
+ screenHeightAligned -= (screenHeightAligned % vc.getHeightAlignment());
+ }
+ if (width >= screenWidthAligned && height >= screenHeightAligned
+ && vc.isSizeSupported(screenWidthAligned, screenHeightAligned)) {
// Desired size is supported, now get the rate
- int maxRate = vc.getSupportedFrameRatesFor(screenWidth, screenHeight)
- .getUpper().intValue();
+ int maxRate = vc.getSupportedFrameRatesFor(screenWidthAligned,
+ screenHeightAligned).getUpper().intValue();
if (maxRate < refreshRate) {
refreshRate = maxRate;
}
Log.d(TAG, "Screen size supported at rate " + refreshRate);
- return new int[]{screenWidth, screenHeight, refreshRate};
+ return new int[]{screenWidthAligned, screenHeightAligned, refreshRate};
}
// Otherwise, continue searching
double scale = Math.min(((double) width / screenWidth),
((double) height / screenHeight));
if (scale > maxScale) {
- maxScale = scale;
+ maxScale = Math.min(1, scale);
maxInfo = vc;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java b/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java
index 8e182b415488..c8afd0b6cfe9 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/CropView.java
@@ -35,7 +35,7 @@ import com.android.systemui.R;
* cropped out.
*/
public class CropView extends View {
- private enum CropBoundary {
+ public enum CropBoundary {
NONE, TOP, BOTTOM
}
@@ -48,8 +48,14 @@ public class CropView extends View {
private float mTopCrop = 0f;
private float mBottomCrop = 1f;
+ // When the user is dragging a handle, these variables store the distance between the top/bottom
+ // crop values and
+ private float mTopDelta = 0f;
+ private float mBottomDelta = 0f;
+
private CropBoundary mCurrentDraggingBoundary = CropBoundary.NONE;
- private float mLastY;
+ private float mStartingY; // y coordinate of ACTION_DOWN
+ private CropInteractionListener mCropInteractionListener;
public CropView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
@@ -73,54 +79,84 @@ public class CropView extends View {
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
- drawShade(canvas, 0, mTopCrop);
- drawShade(canvas, mBottomCrop, 1f);
- drawHandle(canvas, mTopCrop);
- drawHandle(canvas, mBottomCrop);
+ float top = mTopCrop + mTopDelta;
+ float bottom = mBottomCrop + mBottomDelta;
+ drawShade(canvas, 0, top);
+ drawShade(canvas, bottom, 1f);
+ drawHandle(canvas, top);
+ drawHandle(canvas, bottom);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int topPx = fractionToPixels(mTopCrop);
int bottomPx = fractionToPixels(mBottomCrop);
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
- mCurrentDraggingBoundary = nearestBoundary(event, topPx, bottomPx);
- if (mCurrentDraggingBoundary != CropBoundary.NONE) {
- mLastY = event.getY();
- }
- return true;
- }
- if (event.getAction() == MotionEvent.ACTION_MOVE
- && mCurrentDraggingBoundary != CropBoundary.NONE) {
- float delta = event.getY() - mLastY;
- if (mCurrentDraggingBoundary == CropBoundary.TOP) {
- mTopCrop = pixelsToFraction((int) MathUtils.constrain(topPx + delta, 0,
- bottomPx - 2 * mCropTouchMargin));
- } else { // Bottom
- mBottomCrop = pixelsToFraction((int) MathUtils.constrain(bottomPx + delta,
- topPx + 2 * mCropTouchMargin, getMeasuredHeight()));
- }
- mLastY = event.getY();
- invalidate();
- return true;
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ mCurrentDraggingBoundary = nearestBoundary(event, topPx, bottomPx);
+ if (mCurrentDraggingBoundary != CropBoundary.NONE) {
+ mStartingY = event.getY();
+ updateListener(event);
+ }
+ return true;
+ case MotionEvent.ACTION_MOVE:
+ if (mCurrentDraggingBoundary != CropBoundary.NONE) {
+ float delta = event.getY() - mStartingY;
+ if (mCurrentDraggingBoundary == CropBoundary.TOP) {
+ mTopDelta = pixelsToFraction((int) MathUtils.constrain(delta, -topPx,
+ bottomPx - 2 * mCropTouchMargin - topPx));
+ } else { // Bottom
+ mBottomDelta = pixelsToFraction((int) MathUtils.constrain(delta,
+ topPx + 2 * mCropTouchMargin - bottomPx,
+ getMeasuredHeight() - bottomPx));
+ }
+ updateListener(event);
+ invalidate();
+ return true;
+ }
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ if (mCurrentDraggingBoundary != CropBoundary.NONE) {
+ // Commit the delta to the stored crop values.
+ mTopCrop += mTopDelta;
+ mBottomCrop += mBottomDelta;
+ mTopDelta = 0;
+ mBottomDelta = 0;
+ updateListener(event);
+ }
}
return super.onTouchEvent(event);
}
/**
- * @return value [0,1] representing the position of the top crop boundary.
+ * @return value [0,1] representing the position of the top crop boundary. Does not reflect
+ * changes from any in-progress touch input.
*/
public float getTopBoundary() {
return mTopCrop;
}
/**
- * @return value [0,1] representing the position of the bottom crop boundary.
+ * @return value [0,1] representing the position of the bottom crop boundary. Does not reflect
+ * changes from any in-progress touch input.
*/
public float getBottomBoundary() {
return mBottomCrop;
}
+ public void setCropInteractionListener(CropInteractionListener listener) {
+ mCropInteractionListener = listener;
+ }
+
+ private void updateListener(MotionEvent event) {
+ if (mCropInteractionListener != null) {
+ float boundaryPosition = (mCurrentDraggingBoundary == CropBoundary.TOP)
+ ? mTopCrop + mTopDelta : mBottomCrop + mBottomDelta;
+ mCropInteractionListener.onCropMotionEvent(event, mCurrentDraggingBoundary,
+ boundaryPosition, fractionToPixels(boundaryPosition));
+ }
+ }
+
private void drawShade(Canvas canvas, float fracStart, float fracEnd) {
canvas.drawRect(0, fractionToPixels(fracStart), getMeasuredWidth(),
fractionToPixels(fracEnd), mShadePaint);
@@ -148,4 +184,17 @@ public class CropView extends View {
}
return CropBoundary.NONE;
}
+
+ /**
+ * Listen for crop motion events and state.
+ */
+ public interface CropInteractionListener {
+ /**
+ * Called whenever CropView has a MotionEvent that can impact the position of the crop
+ * boundaries.
+ */
+ void onCropMotionEvent(MotionEvent event, CropBoundary boundary, float boundaryPosition,
+ int boundaryPositionPx);
+
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java b/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java
new file mode 100644
index 000000000000..f88715164bc7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/MagnifierView.java
@@ -0,0 +1,184 @@
+/*
+ * 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 android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+
+import com.android.systemui.R;
+
+/**
+ * MagnifierView shows a full-res cropped circular display of a given ImageTileSet, contents and
+ * positioning dereived from events from a CropView to which it listens.
+ *
+ * Not meant to be a general-purpose magnifier!
+ */
+public class MagnifierView extends View implements CropView.CropInteractionListener {
+ private Drawable mDrawable;
+
+ private final Paint mShadePaint;
+ private final Paint mHandlePaint;
+
+ private Path mOuterCircle;
+ private Path mInnerCircle;
+
+ private Path mCheckerboard;
+ private Paint mCheckerboardPaint;
+ private final float mBorderPx;
+ private final int mBorderColor;
+ private float mCheckerboardBoxSize = 40;
+
+ private float mLastCropPosition;
+ private CropView.CropBoundary mCropBoundary;
+
+ public MagnifierView(Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public MagnifierView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ TypedArray t = context.getTheme().obtainStyledAttributes(
+ attrs, R.styleable.MagnifierView, 0, 0);
+ mShadePaint = new Paint();
+ mShadePaint.setColor(t.getColor(R.styleable.MagnifierView_scrimColor, Color.TRANSPARENT));
+ mHandlePaint = new Paint();
+ mHandlePaint.setColor(t.getColor(R.styleable.MagnifierView_handleColor, Color.BLACK));
+ mHandlePaint.setStrokeWidth(
+ t.getDimensionPixelSize(R.styleable.MagnifierView_handleThickness, 20));
+ mBorderPx = t.getDimensionPixelSize(R.styleable.MagnifierView_borderThickness, 0);
+ mBorderColor = t.getColor(R.styleable.MagnifierView_borderColor, Color.WHITE);
+ t.recycle();
+ mCheckerboardPaint = new Paint();
+ mCheckerboardPaint.setColor(Color.GRAY);
+ }
+
+ public void setImageTileset(ImageTileSet tiles) {
+ if (tiles != null) {
+ mDrawable = tiles.getDrawable();
+ mDrawable.setBounds(0, 0, tiles.getWidth(), tiles.getHeight());
+ } else {
+ mDrawable = null;
+ }
+ invalidate();
+ }
+
+ @Override
+ public void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ int radius = getWidth() / 2;
+ mOuterCircle = new Path();
+ mOuterCircle.addCircle(radius, radius, radius, Path.Direction.CW);
+ mInnerCircle = new Path();
+ mInnerCircle.addCircle(radius, radius, radius - mBorderPx, Path.Direction.CW);
+ mCheckerboard = generateCheckerboard();
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ // TODO: just draw a circle at the end instead of clipping like this?
+ canvas.clipPath(mOuterCircle);
+ canvas.drawColor(mBorderColor);
+ canvas.clipPath(mInnerCircle);
+
+ // Draw a checkerboard pattern for out of bounds.
+ canvas.drawPath(mCheckerboard, mCheckerboardPaint);
+
+ if (mDrawable != null) {
+ canvas.save();
+ // Translate such that the center of this view represents the center of the crop
+ // boundary.
+ canvas.translate(-mDrawable.getBounds().width() / 2 + getWidth() / 2,
+ -mDrawable.getBounds().height() * mLastCropPosition + getHeight() / 2);
+ mDrawable.draw(canvas);
+ canvas.restore();
+ }
+
+ Rect scrimRect = new Rect(0, 0, getWidth(), getHeight() / 2);
+ if (mCropBoundary == CropView.CropBoundary.BOTTOM) {
+ scrimRect.offset(0, getHeight() / 2);
+ }
+ canvas.drawRect(scrimRect, mShadePaint);
+
+ canvas.drawLine(0, getHeight() / 2, getWidth(), getHeight() / 2, mHandlePaint);
+ }
+
+ @Override
+ public void onCropMotionEvent(MotionEvent event, CropView.CropBoundary boundary,
+ float cropPosition, int cropPositionPx) {
+ mCropBoundary = boundary;
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ mLastCropPosition = cropPosition;
+ setTranslationY(cropPositionPx - getHeight() / 2);
+ setPivotX(getWidth() / 2);
+ setPivotY(getHeight() / 2);
+ setScaleX(0.2f);
+ setScaleY(0.2f);
+ setAlpha(0f);
+ setTranslationX((getParentWidth() - getWidth()) / 2);
+ setVisibility(View.VISIBLE);
+ animate().alpha(1f).translationX(0).scaleX(1f).scaleY(1f).start();
+ break;
+ case MotionEvent.ACTION_MOVE:
+ mLastCropPosition = cropPosition;
+ setTranslationY(cropPositionPx - getHeight() / 2);
+ invalidate();
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ animate().alpha(0).translationX((getParentWidth() - getWidth()) / 2).scaleX(0.2f)
+ .scaleY(0.2f).withEndAction(() -> setVisibility(View.INVISIBLE)).start();
+ break;
+ }
+ }
+
+ private Path generateCheckerboard() {
+ Path path = new Path();
+ int checkerWidth = (int) Math.ceil(getWidth() / mCheckerboardBoxSize);
+ int checkerHeight = (int) Math.ceil(getHeight() / mCheckerboardBoxSize);
+
+ for (int row = 0; row < checkerHeight; row++) {
+ // Alternate starting on the first and second column;
+ int colStart = (row % 2 == 0) ? 0 : 1;
+ for (int col = colStart; col < checkerWidth; col += 2) {
+ path.addRect(col * mCheckerboardBoxSize,
+ row * mCheckerboardBoxSize,
+ (col + 1) * mCheckerboardBoxSize,
+ (row + 1) * mCheckerboardBoxSize,
+ Path.Direction.CW);
+ }
+ }
+ return path;
+ }
+
+ private int getParentWidth() {
+ return ((View) getParent()).getWidth();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
index 18c379a4650f..25438a6f57ba 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScrollCaptureController.java
@@ -81,6 +81,7 @@ public class ScrollCaptureController implements OnComputeInternalInsetsListener
private View mEdit;
private View mShare;
private CropView mCropView;
+ private MagnifierView mMagnifierView;
public ScrollCaptureController(Context context, Connection connection, Executor uiExecutor,
Executor bgExecutor, ImageExporter exporter, UiEventLogger uiEventLogger) {
@@ -120,13 +121,14 @@ public class ScrollCaptureController implements OnComputeInternalInsetsListener
mEdit = findViewById(R.id.edit);
mShare = findViewById(R.id.share);
mCropView = findViewById(R.id.crop_view);
+ mMagnifierView = findViewById(R.id.magnifier);
+ mCropView.setCropInteractionListener(mMagnifierView);
mSave.setOnClickListener(this::onClicked);
mCancel.setOnClickListener(this::onClicked);
mEdit.setOnClickListener(this::onClicked);
mShare.setOnClickListener(this::onClicked);
- //mPreview.setImageDrawable(mImageTileSet.getDrawable());
mConnection.start(this::startCapture);
}
@@ -164,6 +166,7 @@ public class ScrollCaptureController implements OnComputeInternalInsetsListener
private void doFinish() {
mPreview.setImageDrawable(null);
+ mMagnifierView.setImageTileset(null);
mImageTileSet.clear();
mCallback.onFinish();
mWindow.getDecorView().getViewTreeObserver()
@@ -273,6 +276,7 @@ public class ScrollCaptureController implements OnComputeInternalInsetsListener
session.end(mCallback::onFinish);
} else {
mPreview.setImageDrawable(mImageTileSet.getDrawable());
+ mMagnifierView.setImageTileset(mImageTileSet);
}
}
}
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 0a366c9bb380..dd1419f4ff42 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -48,6 +48,7 @@ import android.os.Messenger;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.MediaStore;
+import android.provider.Settings;
import android.service.media.CameraPrewarmService;
import android.telecom.TelecomManager;
import android.text.TextUtils;
@@ -60,6 +61,7 @@ import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
+import android.widget.ImageView;
import android.widget.TextView;
import com.android.internal.annotations.VisibleForTesting;
@@ -71,6 +73,10 @@ import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.assist.AssistManager;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.controls.dagger.ControlsComponent;
+import com.android.systemui.controls.ui.ControlsDialog;
+import com.android.systemui.controls.ui.ControlsUiController;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.IntentButtonProvider;
import com.android.systemui.plugins.IntentButtonProvider.IntentButton;
@@ -117,11 +123,13 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
private static final int DOZE_ANIMATION_STAGGER_DELAY = 48;
private static final int DOZE_ANIMATION_ELEMENT_DURATION = 250;
+ // TODO(b/179494051): May no longer be needed
private final boolean mShowLeftAffordance;
private final boolean mShowCameraAffordance;
private KeyguardAffordanceView mRightAffordanceView;
private KeyguardAffordanceView mLeftAffordanceView;
+ private ImageView mAltLeftButton;
private ViewGroup mIndicationArea;
private TextView mEnterpriseDisclosure;
private TextView mIndicationText;
@@ -171,6 +179,11 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
private int mBurnInYOffset;
private ActivityIntentHelper mActivityIntentHelper;
+ private ControlsDialog mControlsDialog;
+ private ControlsComponent mControlsComponent;
+ private int mLockScreenMode;
+ private BroadcastDispatcher mBroadcastDispatcher;
+
public KeyguardBottomAreaView(Context context) {
this(context, null);
}
@@ -236,6 +249,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
mOverlayContainer = findViewById(R.id.overlay_container);
mRightAffordanceView = findViewById(R.id.camera_button);
mLeftAffordanceView = findViewById(R.id.left_button);
+ mAltLeftButton = findViewById(R.id.alt_left_button);
mIndicationArea = findViewById(R.id.keyguard_indication_area);
mEnterpriseDisclosure = findViewById(
R.id.keyguard_indication_enterprise_disclosure);
@@ -334,6 +348,11 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_height);
mLeftAffordanceView.setLayoutParams(lp);
updateLeftAffordanceIcon();
+
+ lp = mAltLeftButton.getLayoutParams();
+ lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_width);
+ lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_height);
+ mAltLeftButton.setLayoutParams(lp);
}
private void updateRightAffordanceIcon() {
@@ -392,10 +411,17 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
}
private void updateLeftAffordanceIcon() {
+ if (mDozing) {
+ mAltLeftButton.setVisibility(GONE);
+ } else if (mAltLeftButton.getDrawable() != null) {
+ mAltLeftButton.setVisibility(VISIBLE);
+ }
+
if (!mShowLeftAffordance || mDozing) {
mLeftAffordanceView.setVisibility(GONE);
return;
}
+
IconState state = mLeftButton.getIcon();
mLeftAffordanceView.setVisibility(state.isVisible ? View.VISIBLE : View.GONE);
if (state.drawable != mLeftAffordanceView.getDrawable()
@@ -669,6 +695,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
public void startFinishDozeAnimation() {
long delay = 0;
+ if (mAltLeftButton.getVisibility() == View.VISIBLE) {
+ startFinishDozeAnimationElement(mAltLeftButton, delay);
+ }
if (mLeftAffordanceView.getVisibility() == View.VISIBLE) {
startFinishDozeAnimationElement(mLeftAffordanceView, delay);
delay += DOZE_ANIMATION_STAGGER_DELAY;
@@ -744,6 +773,10 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
if (dozing) {
mOverlayContainer.setVisibility(INVISIBLE);
+ if (mControlsDialog != null) {
+ mControlsDialog.dismiss();
+ mControlsDialog = null;
+ }
} else {
mOverlayContainer.setVisibility(VISIBLE);
if (animate) {
@@ -773,6 +806,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
mLeftAffordanceView.setAlpha(alpha);
mRightAffordanceView.setAlpha(alpha);
mIndicationArea.setAlpha(alpha);
+ mAltLeftButton.setAlpha(alpha);
}
private class DefaultLeftButton implements IntentButton {
@@ -844,4 +878,54 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
}
return insets;
}
+
+ /**
+ * Show or hide controls, depending on the lock screen mode and controls
+ * availability.
+ */
+ public void setupControls(ControlsComponent component, BroadcastDispatcher dispatcher) {
+ mControlsComponent = component;
+ mBroadcastDispatcher = dispatcher;
+ setupControls();
+ }
+
+ private void setupControls() {
+ if (mLockScreenMode == KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL) {
+ mAltLeftButton.setVisibility(View.GONE);
+ mAltLeftButton.setOnClickListener(null);
+ return;
+ }
+
+ if (Settings.Global.getInt(mContext.getContentResolver(), "controls_lockscreen", 0) == 0) {
+ return;
+ }
+
+ if (mControlsComponent.getControlsListingController().isPresent()) {
+ mControlsComponent.getControlsListingController().get()
+ .addCallback(list -> {
+ if (!list.isEmpty()) {
+ mAltLeftButton.setImageDrawable(list.get(0).loadIcon());
+ mAltLeftButton.setVisibility(View.VISIBLE);
+ mAltLeftButton.setOnClickListener((v) -> {
+ ControlsUiController ui = mControlsComponent
+ .getControlsUiController().get();
+ mControlsDialog = new ControlsDialog(mContext, mBroadcastDispatcher)
+ .show(ui);
+ });
+
+ } else {
+ mAltLeftButton.setVisibility(View.GONE);
+ mAltLeftButton.setOnClickListener(null);
+ }
+ });
+ }
+ }
+
+ /**
+ * Optionally add controls when in the new lockscreen mode
+ */
+ public void onLockScreenModeChanged(int mode) {
+ mLockScreenMode = mode;
+ setupControls();
+ }
}
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 3b4759464891..e0ef3b6483a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -80,8 +80,10 @@ import com.android.systemui.DejankUtils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.controls.dagger.ControlsComponent;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.doze.DozeLog;
@@ -229,6 +231,7 @@ public class NotificationPanelViewController extends PanelViewController {
public void onLockScreenModeChanged(int mode) {
mLockScreenMode = mode;
mClockPositionAlgorithm.onLockScreenModeChanged(mode);
+ mKeyguardBottomArea.onLockScreenModeChanged(mode);
}
@Override
@@ -295,6 +298,8 @@ public class NotificationPanelViewController extends PanelViewController {
private final QSDetailDisplayer mQSDetailDisplayer;
private final FeatureFlags mFeatureFlags;
private final ScrimController mScrimController;
+ private final ControlsComponent mControlsComponent;
+
// 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;
@@ -503,6 +508,7 @@ public class NotificationPanelViewController extends PanelViewController {
private NotificationShelfController mNotificationShelfController;
private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
+ private BroadcastDispatcher mBroadcastDispatcher;
private View.AccessibilityDelegate mAccessibilityDelegate = new View.AccessibilityDelegate() {
@Override
@@ -557,8 +563,9 @@ public class NotificationPanelViewController extends PanelViewController {
ScrimController scrimController,
MediaDataManager mediaDataManager,
AmbientState ambientState,
- FeatureFlags featureFlags
- ) {
+ FeatureFlags featureFlags,
+ ControlsComponent controlsComponent,
+ BroadcastDispatcher broadcastDispatcher) {
super(view, falsingManager, dozeLog, keyguardStateController,
(SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
latencyTracker, flingAnimationUtilsBuilder.get(), statusBarTouchableRegionManager,
@@ -592,6 +599,7 @@ public class NotificationPanelViewController extends PanelViewController {
mBiometricUnlockController = biometricUnlockController;
mScrimController = scrimController;
mMediaDataManager = mediaDataManager;
+ mControlsComponent = controlsComponent;
pulseExpansionHandler.setPulseExpandAbortListener(() -> {
if (mQs != null) {
mQs.animateHeaderSlidingOut();
@@ -630,6 +638,7 @@ public class NotificationPanelViewController extends PanelViewController {
mEntryManager = notificationEntryManager;
mConversationNotificationManager = conversationNotificationManager;
mAuthController = authController;
+ mBroadcastDispatcher = broadcastDispatcher;
mView.setBackgroundColor(Color.TRANSPARENT);
OnAttachStateChangeListener onAttachStateChangeListener = new OnAttachStateChangeListener();
@@ -838,6 +847,7 @@ public class NotificationPanelViewController extends PanelViewController {
mKeyguardBottomArea.setAffordanceHelper(mAffordanceHelper);
mKeyguardBottomArea.setStatusBar(mStatusBar);
mKeyguardBottomArea.setUserSetupComplete(mUserSetupComplete);
+ mKeyguardBottomArea.setupControls(mControlsComponent, mBroadcastDispatcher);
}
private void updateMaxDisplayedNotifications(boolean recompute) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index fa78ca6626e1..c07ba723ab43 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -61,8 +61,10 @@ import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
+import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.controls.dagger.ControlsComponent;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.MediaHierarchyManager;
@@ -207,6 +209,10 @@ public class NotificationPanelViewTest extends SysuiTestCase {
@Mock
private FeatureFlags mFeatureFlags;
@Mock
+ private ControlsComponent mControlsComponent;
+ @Mock
+ private BroadcastDispatcher mBroadcastDispatcher;
+ @Mock
private NotificationsQuickSettingsContainer mNotificationContainerParent;
@Mock
private AmbientState mAmbientState;
@@ -300,7 +306,9 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mScrimController,
mMediaDataManager,
mAmbientState,
- mFeatureFlags);
+ mFeatureFlags,
+ mControlsComponent,
+ mBroadcastDispatcher);
mNotificationPanelViewController.initDependencies(
mStatusBar,
mNotificationShelfController);
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/AlwaysOnDisconnectedDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/AlwaysOnDisconnectedDialog.java
index 4d95ef13a2a8..6dcad255eee4 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/AlwaysOnDisconnectedDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/AlwaysOnDisconnectedDialog.java
@@ -20,14 +20,11 @@ import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
-import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.net.IConnectivityManager;
+import android.net.ConnectivityManager;
import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.SpannableStringBuilder;
@@ -45,7 +42,7 @@ public class AlwaysOnDisconnectedDialog extends AlertActivity
private static final String TAG = "VpnDisconnected";
- private IConnectivityManager mService;
+ private ConnectivityManager mService;
private int mUserId;
private String mVpnPackage;
@@ -53,10 +50,9 @@ public class AlwaysOnDisconnectedDialog extends AlertActivity
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mService = IConnectivityManager.Stub.asInterface(
- ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
mUserId = UserHandle.myUserId();
- mVpnPackage = getAlwaysOnVpnPackage();
+ final ConnectivityManager cm = getSystemService(ConnectivityManager.class);
+ mVpnPackage = cm.getAlwaysOnVpnPackageForUser(mUserId);
if (mVpnPackage == null) {
finish();
return;
@@ -102,15 +98,6 @@ public class AlwaysOnDisconnectedDialog extends AlertActivity
}
}
- private String getAlwaysOnVpnPackage() {
- try {
- return mService.getAlwaysOnVpnPackage(mUserId);
- } catch (RemoteException e) {
- Log.e(TAG, "Can't getAlwaysOnVpnPackage()", e);
- return null;
- }
- }
-
private CharSequence getVpnLabel() {
try {
return VpnConfig.getVpnLabel(this, mVpnPackage);
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
index e66f2cc17a7f..aab01d03b96d 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java
@@ -18,15 +18,12 @@ package com.android.vpndialogs;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
-import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
-import android.net.IConnectivityManager;
+import android.net.ConnectivityManager;
import android.net.VpnManager;
import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.Html;
@@ -48,7 +45,8 @@ public class ConfirmDialog extends AlertActivity
private String mPackage;
- private IConnectivityManager mService;
+ private ConnectivityManager mCm; // TODO: switch entirely to VpnManager once VPN code moves
+ private VpnManager mVm;
public ConfirmDialog() {
this(VpnManager.TYPE_VPN_SERVICE);
@@ -62,10 +60,10 @@ public class ConfirmDialog extends AlertActivity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPackage = getCallingPackage();
- mService = IConnectivityManager.Stub.asInterface(
- ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
+ mCm = getSystemService(ConnectivityManager.class);
+ mVm = getSystemService(VpnManager.class);
- if (prepareVpn()) {
+ if (mVm.prepareVpn(mPackage, null, UserHandle.myUserId())) {
setResult(RESULT_OK);
finish();
return;
@@ -74,7 +72,7 @@ public class ConfirmDialog extends AlertActivity
finish();
return;
}
- final String alwaysOnVpnPackage = getAlwaysOnVpnPackage();
+ final String alwaysOnVpnPackage = mCm.getAlwaysOnVpnPackageForUser(UserHandle.myUserId());
// Can't prepare new vpn app when another vpn is always-on
if (alwaysOnVpnPackage != null && !alwaysOnVpnPackage.equals(mPackage)) {
finish();
@@ -97,24 +95,6 @@ public class ConfirmDialog extends AlertActivity
button.setFilterTouchesWhenObscured(true);
}
- private String getAlwaysOnVpnPackage() {
- try {
- return mService.getAlwaysOnVpnPackage(UserHandle.myUserId());
- } catch (RemoteException e) {
- Log.e(TAG, "fail to call getAlwaysOnVpnPackage", e);
- // Fallback to null to show the dialog
- return null;
- }
- }
-
- private boolean prepareVpn() {
- try {
- return mService.prepareVpn(mPackage, null, UserHandle.myUserId());
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
- }
- }
-
private CharSequence getVpnLabel() {
try {
return VpnConfig.getVpnLabel(this, mPackage);
@@ -146,10 +126,10 @@ public class ConfirmDialog extends AlertActivity
@Override
public void onClick(DialogInterface dialog, int which) {
try {
- if (mService.prepareVpn(null, mPackage, UserHandle.myUserId())) {
+ if (mVm.prepareVpn(null, mPackage, UserHandle.myUserId())) {
// Authorize this app to initiate VPN connections in the future without user
// intervention.
- mService.setVpnPackageAuthorization(mPackage, UserHandle.myUserId(), mVpnType);
+ mVm.setVpnPackageAuthorization(mPackage, UserHandle.myUserId(), mVpnType);
setResult(RESULT_OK);
}
} catch (Exception e) {
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
index 01dca7e30e64..1fc74f704f62 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
@@ -16,13 +16,11 @@
package com.android.vpndialogs;
-import android.content.Context;
import android.content.DialogInterface;
-import android.net.IConnectivityManager;
+import android.net.VpnManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
-import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.Log;
@@ -41,7 +39,7 @@ public class ManageDialog extends AlertActivity implements
private VpnConfig mConfig;
- private IConnectivityManager mService;
+ private VpnManager mVm;
private TextView mDuration;
private TextView mDataTransmitted;
@@ -55,11 +53,9 @@ public class ManageDialog extends AlertActivity implements
super.onCreate(savedInstanceState);
try {
+ mVm = getSystemService(VpnManager.class);
- mService = IConnectivityManager.Stub.asInterface(
- ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
-
- mConfig = mService.getVpnConfig(UserHandle.myUserId());
+ mConfig = mVm.getVpnConfig(UserHandle.myUserId());
// mConfig can be null if we are a restricted user, in that case don't show this dialog
if (mConfig == null) {
@@ -118,9 +114,9 @@ public class ManageDialog extends AlertActivity implements
} else if (which == DialogInterface.BUTTON_NEUTRAL) {
final int myUserId = UserHandle.myUserId();
if (mConfig.legacy) {
- mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, myUserId);
+ mVm.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, myUserId);
} else {
- mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN, myUserId);
+ mVm.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN, myUserId);
}
}
} catch (Exception e) {
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 8f093c7e6674..065e2bbd3eef 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -1113,7 +1113,7 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
try {
final IBinder overlayWindowToken = new Binder();
mWindowManagerService.addWindowToken(overlayWindowToken, TYPE_ACCESSIBILITY_OVERLAY,
- displayId);
+ displayId, null /* options */);
synchronized (mLock) {
mOverlayWindowTokens.put(displayId, overlayWindowToken);
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index e01c4df42ff5..37d2cdc16926 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -100,10 +100,10 @@ java_library_static {
libs: [
"services.net",
"android.hardware.light-V2.0-java",
- "android.hardware.gnss-java",
- "android.hardware.power-java",
+ "android.hardware.gnss-V1-java",
+ "android.hardware.power-V1-java",
"android.hardware.power-V1.0-java",
- "android.hardware.vibrator-java",
+ "android.hardware.vibrator-V1-java",
"android.net.ipsec.ike.stubs.module_lib",
"app-compat-annotations",
"framework-tethering.stubs.module_lib",
@@ -128,22 +128,22 @@ java_library_static {
"android.hardware.health-V1.0-java",
"android.hardware.health-V2.0-java",
"android.hardware.health-V2.1-java",
- "android.hardware.light-java",
+ "android.hardware.light-V1-java",
"android.hardware.tv.cec-V1.0-java",
"android.hardware.weaver-V1.0-java",
"android.hardware.biometrics.face-V1.1-java",
- "android.hardware.biometrics.face-java",
+ "android.hardware.biometrics.face-V1-java",
"android.hardware.biometrics.fingerprint-V2.3-java",
- "android.hardware.biometrics.fingerprint-java",
+ "android.hardware.biometrics.fingerprint-V1-java",
"android.hardware.oemlock-V1.0-java",
"android.hardware.configstore-V1.0-java",
"android.hardware.contexthub-V1.0-java",
- "android.hardware.rebootescrow-java",
+ "android.hardware.rebootescrow-V1-java",
"android.hardware.soundtrigger-V2.3-java",
- "android.hardware.power.stats-java",
+ "android.hardware.power.stats-V1-java",
"android.hidl.manager-V1.2-java",
"capture_state_listener-aidl-java",
- "dnsresolver_aidl_interface-java",
+ "dnsresolver_aidl_interface-V7-java",
"icu4j_calendar_astronomer",
"netd-client",
"overlayable_policy_aidl-java",
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 9ccb0c786ebe..6886cdefc28a 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -997,28 +997,6 @@ public abstract class PackageManagerInternal {
public abstract boolean isSuspendingAnyPackages(String suspendingPackage, int userId);
/**
- * Register to listen for loading progress of an installed package.
- * @param packageName The name of the installed package
- * @param callback To loading reporting progress
- * @param userId The user under which to check.
- * @return Whether the registration was successful. It can fail if the package has not been
- * installed yet.
- */
- public abstract boolean registerInstalledLoadingProgressCallback(@NonNull String packageName,
- @NonNull InstalledLoadingProgressCallback callback, int userId);
-
- /**
- * Unregister to stop listening to loading progress of an installed package
- * @param packageName The name of the installed package
- * @param callback To unregister
- * @return True if the callback is removed from registered callback list. False is the callback
- * does not exist on the registered callback list, which can happen if the callback has
- * already been unregistered.
- */
- public abstract boolean unregisterInstalledLoadingProgressCallback(@NonNull String packageName,
- @NonNull InstalledLoadingProgressCallback callback);
-
- /**
* Returns the string representation of a known package. For example,
* {@link #PACKAGE_SETUP_WIZARD} is represented by the string Setup Wizard.
*
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index bf9d564e434a..3933e379e872 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -120,6 +120,7 @@ import android.net.NetworkState;
import android.net.NetworkTestResultParcelable;
import android.net.NetworkUtils;
import android.net.NetworkWatchlistManager;
+import android.net.OemNetworkPreferences;
import android.net.PrivateDnsConfigParcel;
import android.net.ProxyInfo;
import android.net.QosCallbackException;
@@ -281,15 +282,18 @@ public class ConnectivityService extends IConnectivityManager.Stub
// connect anyway?" dialog after the user selects a network that doesn't validate.
private static final int PROMPT_UNVALIDATED_DELAY_MS = 8 * 1000;
- // Default to 30s linger time-out. Modifiable only for testing.
+ // Default to 30s linger time-out, and 5s for nascent network. Modifiable only for testing.
private static final String LINGER_DELAY_PROPERTY = "persist.netmon.linger";
private static final int DEFAULT_LINGER_DELAY_MS = 30_000;
+ private static final int DEFAULT_NASCENT_DELAY_MS = 5_000;
// The maximum number of network request allowed per uid before an exception is thrown.
private static final int MAX_NETWORK_REQUESTS_PER_UID = 100;
@VisibleForTesting
protected int mLingerDelayMs; // Can't be final, or test subclass constructors can't change it.
+ @VisibleForTesting
+ protected int mNascentDelayMs;
// How long to delay to removal of a pending intent based request.
// See Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS
@@ -1063,6 +1067,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000);
mLingerDelayMs = mSystemProperties.getInt(LINGER_DELAY_PROPERTY, DEFAULT_LINGER_DELAY_MS);
+ // TODO: Consider making the timer customizable.
+ mNascentDelayMs = DEFAULT_NASCENT_DELAY_MS;
mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService");
mStatsService = Objects.requireNonNull(statsService, "missing INetworkStatsService");
@@ -2030,7 +2036,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mHandler.sendMessage(mHandler.obtainMessage(
EVENT_PRIVATE_DNS_VALIDATION_UPDATE,
new PrivateDnsValidationUpdate(netId,
- InetAddress.parseNumericAddress(ipAddress),
+ InetAddresses.parseNumericAddress(ipAddress),
hostname, validated)));
} catch (IllegalArgumentException e) {
loge("Error parsing ip address in validation event");
@@ -3334,7 +3340,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// 3. If this network is unneeded (which implies it is not lingering), and there is at least
// one lingered request, set inactive.
nai.updateInactivityTimer();
- if (nai.isLingering() && nai.numForegroundNetworkRequests() > 0) {
+ if (nai.isInactive() && nai.numForegroundNetworkRequests() > 0) {
if (DBG) log("Unsetting inactive " + nai.toShortString());
nai.unsetInactive();
logNetworkEvent(nai, NetworkEvent.NETWORK_UNLINGER);
@@ -3588,10 +3594,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// As this request was not satisfied on rematch and thus never had any scores sent to the
// factories, send null now for each request of type REQUEST.
for (final NetworkRequest req : nri.mRequests) {
- if (!req.isRequest()) {
- continue;
- }
- sendUpdatedScoreToFactories(req, null);
+ if (req.isRequest()) sendUpdatedScoreToFactories(req, null);
}
}
@@ -3631,7 +3634,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
return true;
}
- if (!nai.everConnected || nai.isVPN() || nai.isLingering() || numRequests > 0) {
+ if (!nai.everConnected || nai.isVPN() || nai.isInactive() || numRequests > 0) {
return false;
}
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
@@ -3768,7 +3771,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mNetworkRequestInfoLogs.log("RELEASE " + nri);
if (null != nri.getActiveRequest()) {
- if (nri.getActiveRequest().isRequest()) {
+ if (!nri.getActiveRequest().isListen()) {
removeSatisfiedNetworkRequestFromNetwork(nri);
} else {
nri.setSatisfier(null, null);
@@ -5516,7 +5519,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
// The network currently satisfying this NRI. Only one request in an NRI can have a
- // satisfier. For non-multilayer requests, only REQUEST-type requests can have a satisfier.
+ // satisfier. For non-multilayer requests, only non-listen requests can have a satisfier.
@Nullable
private NetworkAgentInfo mSatisfier;
NetworkAgentInfo getSatisfier() {
@@ -7004,8 +7007,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
private void sendUpdatedScoreToFactories(NetworkAgentInfo nai) {
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest nr = nai.requestAt(i);
- // Don't send listening requests to factories. b/17393458
- if (nr.isListen()) continue;
+ // Don't send listening or track default request to factories. b/17393458
+ if (!nr.isRequest()) continue;
sendUpdatedScoreToFactories(nr, nai);
}
}
@@ -7067,10 +7070,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
ensureRunningOnConnectivityServiceThread();
for (final NetworkRequestInfo nri : getNrisFromGlobalRequests()) {
for (final NetworkRequest req : nri.mRequests) {
- if (req.isListen() && nri.getActiveRequest() == req) {
+ if (!req.isRequest() && nri.getActiveRequest() == req) {
break;
}
- if (req.isListen()) {
+ if (!req.isRequest()) {
continue;
}
// Only set the nai for the request it is satisfying.
@@ -7220,8 +7223,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (nai.numRequestNetworkRequests() != 0) {
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest nr = nai.requestAt(i);
- // Ignore listening requests.
- if (nr.isListen()) continue;
+ // Ignore listening and track default requests.
+ if (!nr.isRequest()) continue;
loge("Dead network still had at least " + nr);
break;
}
@@ -7244,7 +7247,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Tear the network down.
teardownUnneededNetwork(oldNetwork);
} else {
- // Put the network in the background.
+ // Put the network in the background if it doesn't satisfy any foreground request.
updateCapabilitiesForNetwork(oldNetwork);
}
}
@@ -7498,6 +7501,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
} else {
if (VDBG || DDBG) log(" accepting network in place of null");
}
+
+ // To prevent constantly CPU wake up for nascent timer, if a network comes up
+ // and immediately satisfies a request then remove the timer. This will happen for
+ // all networks except in the case of an underlying network for a VCN.
+ if (newSatisfier.isNascent()) {
+ newSatisfier.unlingerRequest(NetworkRequest.REQUEST_ID_NONE);
+ }
+
newSatisfier.unlingerRequest(newRequest.requestId);
if (!newSatisfier.addRequest(newRequest)) {
Log.wtf(TAG, "BUG: " + newSatisfier.toShortString() + " already has "
@@ -7640,19 +7651,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- // Update the linger state before processing listen callbacks, because the background
- // computation depends on whether the network is lingering. Don't send the LOSING callbacks
+ // Update the inactivity state before processing listen callbacks, because the background
+ // computation depends on whether the network is inactive. Don't send the LOSING callbacks
// just yet though, because they have to be sent after the listens are processed to keep
// backward compatibility.
- final ArrayList<NetworkAgentInfo> lingeredNetworks = new ArrayList<>();
+ final ArrayList<NetworkAgentInfo> inactiveNetworks = new ArrayList<>();
for (final NetworkAgentInfo nai : nais) {
- // Rematching may have altered the linger state of some networks, so update all linger
- // timers. updateLingerState reads the state from the network agent and does nothing
- // if the state has not changed : the source of truth is controlled with
- // NetworkAgentInfo#lingerRequest and NetworkAgentInfo#unlingerRequest, which have been
- // called while rematching the individual networks above.
+ // Rematching may have altered the inactivity state of some networks, so update all
+ // inactivity timers. updateInactivityState reads the state from the network agent
+ // and does nothing if the state has not changed : the source of truth is controlled
+ // with NetworkAgentInfo#lingerRequest and NetworkAgentInfo#unlingerRequest, which
+ // have been called while rematching the individual networks above.
if (updateInactivityState(nai, now)) {
- lingeredNetworks.add(nai);
+ inactiveNetworks.add(nai);
}
}
@@ -7669,7 +7680,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
processNewlySatisfiedListenRequests(nai);
}
- for (final NetworkAgentInfo nai : lingeredNetworks) {
+ for (final NetworkAgentInfo nai : inactiveNetworks) {
+ // For nascent networks, if connecting with no foreground request, skip broadcasting
+ // LOSING for backward compatibility. This is typical when mobile data connected while
+ // wifi connected with mobile data always-on enabled.
+ if (nai.isNascent()) continue;
notifyNetworkLosing(nai, now);
}
@@ -7910,6 +7925,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
// doing.
updateSignalStrengthThresholds(networkAgent, "CONNECT", null);
+ // Before first rematching networks, put an inactivity timer without any request, this
+ // allows {@code updateInactivityState} to update the state accordingly and prevent
+ // tearing down for any {@code unneeded} evaluation in this period.
+ // Note that the timer will not be rescheduled since the expiry time is
+ // fixed after connection regardless of the network satisfying other requests or not.
+ // But it will be removed as soon as the network satisfies a request for the first time.
+ networkAgent.lingerRequest(NetworkRequest.REQUEST_ID_NONE,
+ SystemClock.elapsedRealtime(), mNascentDelayMs);
+
// Consider network even though it is not yet validated.
rematchAllNetworksAndRequests();
@@ -9100,6 +9124,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
}
+
/**
* Registers {@link QosSocketFilter} with {@link IQosCallback}.
*
@@ -9149,4 +9174,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
public void unregisterQosCallback(@NonNull final IQosCallback callback) {
mQosCallbackTracker.unregisterCallback(callback);
}
+
+ @Override
+ public void setOemNetworkPreference(@NonNull final OemNetworkPreferences preference) {
+ // TODO http://b/176495594 track multiple default networks with networkPreferences
+ if (DBG) log("setOemNetworkPreference() called with: " + preference.toString());
+ }
}
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index e96fd390f15a..96f832d26816 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -50,6 +50,7 @@ import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.net.module.util.NetdUtils;
+import com.android.net.module.util.NetworkStackConstants;
import java.io.UncheckedIOException;
import java.net.Inet4Address;
@@ -280,10 +281,12 @@ class TestNetworkService extends ITestNetworkManager.Stub {
// Add global routes (but as non-default, non-internet providing network)
if (allowIPv4) {
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null, iface));
+ lp.addRoute(new RouteInfo(new IpPrefix(
+ NetworkStackConstants.IPV4_ADDR_ANY, 0), null, iface));
}
if (allowIPv6) {
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null, iface));
+ lp.addRoute(new RouteInfo(new IpPrefix(
+ NetworkStackConstants.IPV6_ADDR_ANY, 0), null, iface));
}
final TestNetworkAgent agent = new TestNetworkAgent(context, looper, nc, lp,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6ae064435da3..9382e1aa2a9e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -145,6 +145,7 @@ import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManagerInternal;
import android.app.ActivityTaskManager.RootTaskInfo;
import android.app.ActivityThread;
+import android.app.AnrController;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.AppOpsManagerInternal.CheckOpsDelegate;
@@ -15861,6 +15862,16 @@ public class ActivityManagerService extends IActivityManager.Stub
// PackageManagerService.
return mConstants.mBootTimeTempAllowlistDuration;
}
+
+ @Override
+ public void registerAnrController(AnrController controller) {
+ mActivityTaskManager.registerAnrController(controller);
+ }
+
+ @Override
+ public void unregisterAnrController(AnrController controller) {
+ mActivityTaskManager.unregisterAnrController(controller);
+ }
}
long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index fe71fbf79157..c971bd2ab6d5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2984,7 +2984,13 @@ final class ActivityManagerShellCommand extends ShellCommand {
pw.println("Reset all changes for " + packageName + " to default value.");
return 0;
}
- if (platformCompat.clearOverride(changeId, packageName)) {
+ boolean existed;
+ if (killPackage) {
+ existed = platformCompat.clearOverride(changeId, packageName);
+ } else {
+ existed = platformCompat.clearOverrideForTest(changeId, packageName);
+ }
+ if (existed) {
pw.println("Reset change " + changeId + " for " + packageName
+ " to default value.");
} else {
diff --git a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
index 64e307a5f182..165312352990 100644
--- a/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessErrorStateRecord.java
@@ -416,6 +416,14 @@ class ProcessErrorStateRecord {
return;
}
+ // Retrieve max ANR delay from AnrControllers without the mService lock since the
+ // controllers might in turn call into apps
+ long anrDialogDelayMs = mService.mActivityTaskManager.getMaxAnrDelayMillis(aInfo);
+ if (aInfo != null && aInfo.packageName != null && anrDialogDelayMs > 0) {
+ Slog.i(TAG, "Delaying ANR dialog for " + aInfo.packageName + " for " + anrDialogDelayMs
+ + "ms");
+ }
+
synchronized (mService) {
// mBatteryStatsService can be null if the AMS is constructed with injector only. This
// will only happen in tests.
@@ -447,7 +455,7 @@ class ProcessErrorStateRecord {
msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
msg.obj = new AppNotRespondingDialog.Data(mApp, aInfo, aboveSystem);
- mService.mUiHandler.sendMessage(msg);
+ mService.mUiHandler.sendMessageDelayed(msg, anrDialogDelayMs);
}
}
}
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 7299e814b020..e022e977e02f 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -81,6 +81,7 @@ public class SettingsToPropertiesMapper {
static final String[] sDeviceConfigScopes = new String[] {
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
DeviceConfig.NAMESPACE_CONFIGURATION,
+ DeviceConfig.NAMESPACE_CONNECTIVITY,
DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT,
DeviceConfig.NAMESPACE_INTELLIGENCE_CONTENT_SUGGESTIONS,
DeviceConfig.NAMESPACE_MEDIA_NATIVE,
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 9aea7c4c6dad..f72fb1f74fa8 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -765,10 +765,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
return mAudioService.getVssVolumeForDevice(streamType, device);
}
- /*package*/ int getModeOwnerPid() {
- return mModeOwnerPid;
- }
-
/*package*/ int getDeviceForStream(int streamType) {
return mAudioService.getDeviceForStream(streamType);
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index e7e98324605a..6f625a745ef6 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -95,6 +95,7 @@ import android.media.IVolumeController;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.media.MediaMetrics;
+import android.media.MediaRecorder.AudioSource;
import android.media.PlayerBase;
import android.media.VolumePolicy;
import android.media.audiofx.AudioEffect;
@@ -161,9 +162,11 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -301,6 +304,9 @@ public class AudioService extends IAudioService.Stub
private static final int MSG_UPDATE_VOLUME_STATES_FOR_DEVICE = 33;
private static final int MSG_REINIT_VOLUMES = 34;
private static final int MSG_UPDATE_A11Y_SERVICE_UIDS = 35;
+ private static final int MSG_UPDATE_AUDIO_MODE = 36;
+ private static final int MSG_RECORDING_CONFIG_CHANGE = 37;
+
// start of messages handled under wakelock
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
// and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -941,6 +947,7 @@ public class AudioService extends IAudioService.Stub
mDeviceBroker = new AudioDeviceBroker(mContext, this);
mRecordMonitor = new RecordingActivityMonitor(mContext);
+ mRecordMonitor.registerRecordingCallback(mVoiceRecordingActivityMonitor, true);
// must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
// array initialized by updateStreamVolumeAlias()
@@ -950,6 +957,8 @@ public class AudioService extends IAudioService.Stub
mPlaybackMonitor =
new PlaybackActivityMonitor(context, MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM]);
+ mPlaybackMonitor.registerPlaybackCallback(mVoicePlaybackActivityMonitor, true);
+
mMediaFocusControl = new MediaFocusControl(mContext, mPlaybackMonitor);
readAndSetLowRamDevice();
@@ -1198,12 +1207,8 @@ public class AudioService extends IAudioService.Stub
// Restore call state
synchronized (mDeviceBroker.mSetModeLock) {
- if (mAudioSystem.setPhoneState(mMode, getModeOwnerUid())
- == AudioSystem.AUDIO_STATUS_OK) {
- mModeLogger.log(new AudioEventLogger.StringEvent(
- "onAudioServerDied causes setPhoneState(" + AudioSystem.modeToString(mMode)
- + ", uid=" + getModeOwnerUid() + ")"));
- }
+ onUpdateAudioMode(AudioSystem.MODE_CURRENT, android.os.Process.myPid(),
+ mContext.getPackageName());
}
final int forSys;
synchronized (mSettingsLock) {
@@ -2991,7 +2996,7 @@ public class AudioService extends IAudioService.Stub
}
/*package*/ int getHearingAidStreamType() {
- return getHearingAidStreamType(mMode);
+ return getHearingAidStreamType(getMode());
}
private int getHearingAidStreamType(int mode) {
@@ -3004,15 +3009,15 @@ public class AudioService extends IAudioService.Stub
// other conditions will influence the stream type choice, read on...
break;
}
- if (mVoiceActive.get()) {
+ if (mVoicePlaybackActive.get()) {
return AudioSystem.STREAM_VOICE_CALL;
}
return AudioSystem.STREAM_MUSIC;
}
- private AtomicBoolean mVoiceActive = new AtomicBoolean(false);
+ private AtomicBoolean mVoicePlaybackActive = new AtomicBoolean(false);
- private final IPlaybackConfigDispatcher mVoiceActivityMonitor =
+ private final IPlaybackConfigDispatcher mVoicePlaybackActivityMonitor =
new IPlaybackConfigDispatcher.Stub() {
@Override
public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
@@ -3034,16 +3039,126 @@ public class AudioService extends IAudioService.Stub
break;
}
}
- if (mVoiceActive.getAndSet(voiceActive) != voiceActive) {
+ if (mVoicePlaybackActive.getAndSet(voiceActive) != voiceActive) {
updateHearingAidVolumeOnVoiceActivityUpdate();
}
+
+ // Update playback active state for all apps in audio mode stack.
+ // When the audio mode owner becomes active, replace any delayed MSG_UPDATE_AUDIO_MODE
+ // and request an audio mode update immediately. Upon any other change, queue the message
+ // and request an audio mode update after a grace period.
+ synchronized (mDeviceBroker.mSetModeLock) {
+ boolean updateAudioMode = false;
+ int existingMsgPolicy = SENDMSG_QUEUE;
+ int delay = CHECK_MODE_FOR_UID_PERIOD_MS;
+ for (SetModeDeathHandler h : mSetModeDeathHandlers) {
+ boolean wasActive = h.isActive();
+ h.setPlaybackActive(false);
+ for (AudioPlaybackConfiguration config : configs) {
+ final int usage = config.getAudioAttributes().getUsage();
+ if (config.getClientUid() == h.getUid()
+ && (usage == AudioAttributes.USAGE_VOICE_COMMUNICATION
+ || usage == AudioAttributes.USAGE_VOICE_COMMUNICATION_SIGNALLING)
+ && config.getPlayerState()
+ == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
+ h.setPlaybackActive(true);
+ break;
+ }
+ }
+ if (wasActive != h.isActive()) {
+ updateAudioMode = true;
+ if (h.isActive() && h == getAudioModeOwnerHandler()) {
+ existingMsgPolicy = SENDMSG_REPLACE;
+ delay = 0;
+ }
+ }
+ }
+ if (updateAudioMode) {
+ sendMsg(mAudioHandler,
+ MSG_UPDATE_AUDIO_MODE,
+ existingMsgPolicy,
+ AudioSystem.MODE_CURRENT,
+ android.os.Process.myPid(),
+ mContext.getPackageName(),
+ delay);
+ }
+ }
+ }
+
+ private final IRecordingConfigDispatcher mVoiceRecordingActivityMonitor =
+ new IRecordingConfigDispatcher.Stub() {
+ @Override
+ public void dispatchRecordingConfigChange(List<AudioRecordingConfiguration> configs) {
+ sendMsg(mAudioHandler, MSG_RECORDING_CONFIG_CHANGE, SENDMSG_REPLACE,
+ 0 /*arg1 ignored*/, 0 /*arg2 ignored*/,
+ configs /*obj*/, 0 /*delay*/);
+ }
+ };
+
+ private void onRecordingConfigChange(List<AudioRecordingConfiguration> configs) {
+ // Update recording active state for all apps in audio mode stack.
+ // When the audio mode owner becomes active, replace any delayed MSG_UPDATE_AUDIO_MODE
+ // and request an audio mode update immediately. Upon any other change, queue the message
+ // and request an audio mode update after a grace period.
+ synchronized (mDeviceBroker.mSetModeLock) {
+ boolean updateAudioMode = false;
+ int existingMsgPolicy = SENDMSG_QUEUE;
+ int delay = CHECK_MODE_FOR_UID_PERIOD_MS;
+ for (SetModeDeathHandler h : mSetModeDeathHandlers) {
+ boolean wasActive = h.isActive();
+ h.setRecordingActive(false);
+ for (AudioRecordingConfiguration config : configs) {
+ if (config.getClientUid() == h.getUid()
+ && config.getAudioSource() == AudioSource.VOICE_COMMUNICATION) {
+ h.setRecordingActive(true);
+ break;
+ }
+ }
+ if (wasActive != h.isActive()) {
+ updateAudioMode = true;
+ if (h.isActive() && h == getAudioModeOwnerHandler()) {
+ existingMsgPolicy = SENDMSG_REPLACE;
+ delay = 0;
+ }
+ }
+ }
+ if (updateAudioMode) {
+ sendMsg(mAudioHandler,
+ MSG_UPDATE_AUDIO_MODE,
+ existingMsgPolicy,
+ AudioSystem.MODE_CURRENT,
+ android.os.Process.myPid(),
+ mContext.getPackageName(),
+ delay);
+ }
+ }
+ }
+
+ private void dumpAudioMode(PrintWriter pw) {
+ pw.println("\nAudio mode: ");
+ pw.println("- Current mode = " + AudioSystem.modeToString(getMode()));
+ pw.println("- Mode owner: ");
+ SetModeDeathHandler hdlr = getAudioModeOwnerHandler();
+ if (hdlr != null) {
+ hdlr.dump(pw, -1);
+ } else {
+ pw.println(" None");
+ }
+ pw.println("- Mode owner stack: ");
+ if (mSetModeDeathHandlers.isEmpty()) {
+ pw.println(" Empty");
+ } else {
+ for (int i = 0; i < mSetModeDeathHandlers.size(); i++) {
+ mSetModeDeathHandlers.get(i).dump(pw, i);
+ }
+ }
}
private void updateHearingAidVolumeOnVoiceActivityUpdate() {
final int streamType = getHearingAidStreamType();
final int index = getStreamVolume(streamType);
sVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_VOICE_ACTIVITY_HEARING_AID,
- mVoiceActive.get(), streamType, index));
+ mVoicePlaybackActive.get(), streamType, index));
mDeviceBroker.postSetHearingAidVolumeIndex(index * 10, streamType);
}
@@ -4060,65 +4175,46 @@ public class AudioService extends IAudioService.Stub
}
- /**
- * Return the pid of the current audio mode owner
- * @return 0 if nobody owns the mode
- */
- /*package*/ int getModeOwnerPid() {
- int modeOwnerPid = 0;
- try {
- modeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
- } catch (Exception e) {
- // nothing to do, modeOwnerPid is not modified
- }
- return modeOwnerPid;
- }
-
- /**
- * Return the uid of the current audio mode owner
- * @return 0 if nobody owns the mode
- */
- /*package*/ int getModeOwnerUid() {
- int modeOwnerUid = 0;
- try {
- modeOwnerUid = mSetModeDeathHandlers.get(0).getUid();
- } catch (Exception e) {
- // nothing to do, modeOwnerUid is not modified
- }
- return modeOwnerUid;
- }
-
private class SetModeDeathHandler implements IBinder.DeathRecipient {
private final IBinder mCb; // To be notified of client's death
private final int mPid;
private final int mUid;
private final boolean mIsPrivileged;
private final String mPackage;
- private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
+ private int mMode;
+ private long mUpdateTime;
+ private boolean mPlaybackActive = false;
+ private boolean mRecordingActive = false;
- SetModeDeathHandler(IBinder cb, int pid, int uid, boolean isPrivileged, String caller) {
+ SetModeDeathHandler(IBinder cb, int pid, int uid, boolean isPrivileged,
+ String caller, int mode) {
+ mMode = mode;
mCb = cb;
mPid = pid;
mUid = uid;
- mIsPrivileged = isPrivileged;
mPackage = caller;
+ mIsPrivileged = isPrivileged;
+ mUpdateTime = java.lang.System.currentTimeMillis();
}
public void binderDied() {
- int newModeOwnerPid = 0;
synchronized (mDeviceBroker.mSetModeLock) {
- Log.w(TAG, "setMode() client died");
+ Log.w(TAG, "SetModeDeathHandler client died");
int index = mSetModeDeathHandlers.indexOf(this);
if (index < 0) {
- Log.w(TAG, "unregistered setMode() client died");
+ Log.w(TAG, "unregistered SetModeDeathHandler client died");
} else {
- newModeOwnerPid = setModeInt(
- AudioSystem.MODE_NORMAL, mCb, mPid, mUid, mIsPrivileged, TAG);
+ SetModeDeathHandler h = mSetModeDeathHandlers.get(index);
+ mSetModeDeathHandlers.remove(index);
+ sendMsg(mAudioHandler,
+ MSG_UPDATE_AUDIO_MODE,
+ SENDMSG_QUEUE,
+ AudioSystem.MODE_CURRENT,
+ android.os.Process.myPid(),
+ mContext.getPackageName(),
+ 0);
}
}
- // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
- // SCO connections not started by the application changing the mode when pid changes
- mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid, AudioService.this.getMode());
}
public int getPid() {
@@ -4127,6 +4223,7 @@ public class AudioService extends IAudioService.Stub
public void setMode(int mode) {
mMode = mode;
+ mUpdateTime = java.lang.System.currentTimeMillis();
}
public int getMode() {
@@ -4148,25 +4245,131 @@ public class AudioService extends IAudioService.Stub
public boolean isPrivileged() {
return mIsPrivileged;
}
+
+ public long getUpdateTime() {
+ return mUpdateTime;
+ }
+
+ public void setPlaybackActive(boolean active) {
+ mPlaybackActive = active;
+ }
+
+ public void setRecordingActive(boolean active) {
+ mRecordingActive = active;
+ }
+
+ /**
+ * An app is considered active if:
+ * - It is privileged (has MODIFY_PHONE_STATE permission)
+ * or
+ * - It requests mode MODE_IN_COMMUNICATION, and it is either playing
+ * or recording for VOICE_COMMUNICATION.
+ * or
+ * - It requests a mode different from MODE_IN_COMMUNICATION or MODE_NORMAL
+ */
+ public boolean isActive() {
+ return mIsPrivileged
+ || ((mMode == AudioSystem.MODE_IN_COMMUNICATION)
+ && (mRecordingActive || mPlaybackActive))
+ || mMode == AudioSystem.MODE_IN_CALL
+ || mMode == AudioSystem.MODE_RINGTONE
+ || mMode == AudioSystem.MODE_CALL_SCREENING;
+ }
+
+ public void dump(PrintWriter pw, int index) {
+ SimpleDateFormat format = new SimpleDateFormat("MM-dd HH:mm:ss:SSS");
+
+ if (index >= 0) {
+ pw.println(" Requester # " + (index + 1) + ":");
+ }
+ pw.println(" - Mode: " + AudioSystem.modeToString(mMode));
+ pw.println(" - Binder: " + mCb);
+ pw.println(" - Pid: " + mPid);
+ pw.println(" - Uid: " + mUid);
+ pw.println(" - Package: " + mPackage);
+ pw.println(" - Privileged: " + mIsPrivileged);
+ pw.println(" - Active: " + isActive());
+ pw.println(" Playback active: " + mPlaybackActive);
+ pw.println(" Recording active: " + mRecordingActive);
+ pw.println(" - update time: " + format.format(new Date(mUpdateTime)));
+ }
+ }
+
+ @GuardedBy("mDeviceBroker.mSetModeLock")
+ private SetModeDeathHandler getAudioModeOwnerHandler() {
+ // The Audio mode owner is:
+ // 1) the most recent privileged app in the stack
+ // 2) the most recent active app in the tack
+ SetModeDeathHandler modeOwner = null;
+ SetModeDeathHandler privilegedModeOwner = null;
+ for (SetModeDeathHandler h : mSetModeDeathHandlers) {
+ if (h.isActive()) {
+ // privileged apps are always active
+ if (h.isPrivileged()) {
+ if (privilegedModeOwner == null
+ || h.getUpdateTime() > privilegedModeOwner.getUpdateTime()) {
+ privilegedModeOwner = h;
+ }
+ } else {
+ if (modeOwner == null
+ || h.getUpdateTime() > modeOwner.getUpdateTime()) {
+ modeOwner = h;
+ }
+ }
+ }
+ }
+ return privilegedModeOwner != null ? privilegedModeOwner : modeOwner;
+ }
+
+ /**
+ * Return the pid of the current audio mode owner
+ * @return 0 if nobody owns the mode
+ */
+ @GuardedBy("mDeviceBroker.mSetModeLock")
+ /*package*/ int getModeOwnerPid() {
+ SetModeDeathHandler hdlr = getAudioModeOwnerHandler();
+ if (hdlr != null) {
+ return hdlr.getPid();
+ }
+ return 0;
+ }
+
+ /**
+ * Return the uid of the current audio mode owner
+ * @return 0 if nobody owns the mode
+ */
+ @GuardedBy("mDeviceBroker.mSetModeLock")
+ /*package*/ int getModeOwnerUid() {
+ SetModeDeathHandler hdlr = getAudioModeOwnerHandler();
+ if (hdlr != null) {
+ return hdlr.getUid();
+ }
+ return 0;
}
/** @see AudioManager#setMode(int) */
public void setMode(int mode, IBinder cb, String callingPackage) {
+ int pid = Binder.getCallingPid();
+ int uid = Binder.getCallingUid();
if (DEBUG_MODE) {
- Log.v(TAG, "setMode(mode=" + mode + ", callingPackage=" + callingPackage + ")");
+ Log.v(TAG, "setMode(mode=" + mode + ", pid=" + pid
+ + ", uid=" + uid + ", caller=" + callingPackage + ")");
}
if (!checkAudioSettingsPermission("setMode()")) {
return;
}
- final boolean hasModifyPhoneStatePermission = mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.MODIFY_PHONE_STATE)
- == PackageManager.PERMISSION_GRANTED;
- final int callingPid = Binder.getCallingPid();
- if ((mode == AudioSystem.MODE_IN_CALL) && !hasModifyPhoneStatePermission) {
- Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
- + callingPid + ", uid=" + Binder.getCallingUid());
+ if (cb == null) {
+ Log.e(TAG, "setMode() called with null binder");
return;
}
+ if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
+ Log.w(TAG, "setMode() invalid mode: " + mode);
+ return;
+ }
+
+ if (mode == AudioSystem.MODE_CURRENT) {
+ mode = getMode();
+ }
if (mode == AudioSystem.MODE_CALL_SCREENING && !mIsCallScreeningModeSupported) {
Log.w(TAG, "setMode(MODE_CALL_SCREENING) not permitted "
@@ -4174,171 +4377,152 @@ public class AudioService extends IAudioService.Stub
return;
}
- if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
+ final boolean hasModifyPhoneStatePermission = mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.MODIFY_PHONE_STATE)
+ == PackageManager.PERMISSION_GRANTED;
+ if ((mode == AudioSystem.MODE_IN_CALL) && !hasModifyPhoneStatePermission) {
+ Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
+ + pid + ", uid=" + Binder.getCallingUid());
return;
}
- int newModeOwnerPid;
+ SetModeDeathHandler currentModeHandler = null;
synchronized (mDeviceBroker.mSetModeLock) {
- if (mode == AudioSystem.MODE_CURRENT) {
- mode = mMode;
- }
- int oldModeOwnerPid = getModeOwnerPid();
- // Do not allow changing mode if a call is active and the requester
- // does not have permission to modify phone state or is not the mode owner,
- // unless returning to NORMAL mode (will not change current mode owner) or
- // not changing mode in which case the mode owner will reflect the last
- // requester of current mode
- if (!((mode == mMode) || (mode == AudioSystem.MODE_NORMAL))
- && ((mMode == AudioSystem.MODE_IN_CALL)
- || (mMode == AudioSystem.MODE_IN_COMMUNICATION))
- && !(hasModifyPhoneStatePermission || (oldModeOwnerPid == callingPid))) {
- Log.w(TAG, "setMode(" + mode + ") from pid=" + callingPid
- + ", uid=" + Binder.getCallingUid()
- + ", cannot change mode from " + mMode
- + " without permission or being mode owner");
- return;
- }
- newModeOwnerPid = setModeInt(mode, cb, callingPid, Binder.getCallingUid(),
- hasModifyPhoneStatePermission, callingPackage);
- }
- // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
- // SCO connections not started by the application changing the mode when pid changes
- mDeviceBroker.postSetModeOwnerPid(newModeOwnerPid, getMode());
- }
-
- // setModeInt() returns a valid PID if the audio mode was successfully set to
- // any mode other than NORMAL.
- @GuardedBy("mDeviceBroker.mSetModeLock")
- private int setModeInt(
- int mode, IBinder cb, int pid, int uid, boolean isPrivileged, String caller) {
- if (DEBUG_MODE) {
- Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid
- + ", uid=" + uid + ", caller=" + caller + ")");
- }
- int newModeOwnerPid = 0;
- if (cb == null) {
- Log.e(TAG, "setModeInt() called with null binder");
- return newModeOwnerPid;
- }
-
- SetModeDeathHandler hdlr = null;
- Iterator iter = mSetModeDeathHandlers.iterator();
- while (iter.hasNext()) {
- SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
- if (h.getPid() == pid) {
- hdlr = h;
- // Remove from client list so that it is re-inserted at top of list
- iter.remove();
- if (hdlr.getMode() == AudioSystem.MODE_IN_COMMUNICATION) {
- mAudioHandler.removeEqualMessages(MSG_CHECK_MODE_FOR_UID, hdlr);
- }
- try {
- hdlr.getBinder().unlinkToDeath(hdlr, 0);
- if (cb != hdlr.getBinder()){
- hdlr = null;
- }
- } catch (NoSuchElementException e) {
- hdlr = null;
- Log.w(TAG, "link does not exist ...");
+ for (SetModeDeathHandler h : mSetModeDeathHandlers) {
+ if (h.getPid() == pid) {
+ currentModeHandler = h;
+ break;
}
- break;
}
- }
- final int oldMode = mMode;
- int status = AudioSystem.AUDIO_STATUS_OK;
- int actualMode;
- do {
- actualMode = mode;
+
if (mode == AudioSystem.MODE_NORMAL) {
- // get new mode from client at top the list if any
- if (!mSetModeDeathHandlers.isEmpty()) {
- hdlr = mSetModeDeathHandlers.get(0);
- cb = hdlr.getBinder();
- actualMode = hdlr.getMode();
+ if (currentModeHandler != null) {
+ if (!currentModeHandler.isPrivileged()
+ && currentModeHandler.getMode() == AudioSystem.MODE_IN_COMMUNICATION) {
+ mAudioHandler.removeEqualMessages(
+ MSG_CHECK_MODE_FOR_UID, currentModeHandler);
+ }
+ mSetModeDeathHandlers.remove(currentModeHandler);
if (DEBUG_MODE) {
- Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
- + hdlr.mPid);
+ Log.v(TAG, "setMode(" + mode + ") removing hldr for pid: " + pid);
+ }
+ try {
+ currentModeHandler.getBinder().unlinkToDeath(currentModeHandler, 0);
+ } catch (NoSuchElementException e) {
+ Log.w(TAG, "setMode link does not exist ...");
}
}
} else {
- if (hdlr == null) {
- hdlr = new SetModeDeathHandler(cb, pid, uid, isPrivileged, caller);
- }
- // Register for client death notification
- try {
- cb.linkToDeath(hdlr, 0);
- } catch (RemoteException e) {
- // Client has died!
- Log.w(TAG, "setMode() could not link to "+cb+" binder death");
- }
-
- // Last client to call setMode() is always at top of client list
- // as required by SetModeDeathHandler.binderDied()
- mSetModeDeathHandlers.add(0, hdlr);
- hdlr.setMode(mode);
- }
-
- if (actualMode != mMode) {
- final long identity = Binder.clearCallingIdentity();
- status = mAudioSystem.setPhoneState(actualMode, getModeOwnerUid());
- Binder.restoreCallingIdentity(identity);
- if (status == AudioSystem.AUDIO_STATUS_OK) {
- if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + actualMode); }
- mMode = actualMode;
+ if (currentModeHandler != null) {
+ currentModeHandler.setMode(mode);
+ if (DEBUG_MODE) {
+ Log.v(TAG, "setMode(" + mode + ") updating hldr for pid: " + pid);
+ }
} else {
- if (hdlr != null) {
- mSetModeDeathHandlers.remove(hdlr);
- cb.unlinkToDeath(hdlr, 0);
+ currentModeHandler = new SetModeDeathHandler(cb, pid, uid,
+ hasModifyPhoneStatePermission, callingPackage, mode);
+ // Register for client death notification
+ try {
+ cb.linkToDeath(currentModeHandler, 0);
+ } catch (RemoteException e) {
+ // Client has died!
+ Log.w(TAG, "setMode() could not link to " + cb + " binder death");
+ return;
+ }
+ mSetModeDeathHandlers.add(currentModeHandler);
+ if (DEBUG_MODE) {
+ Log.v(TAG, "setMode(" + mode + ") adding handler for pid=" + pid);
}
- // force reading new top of mSetModeDeathHandlers stack
- if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
- mode = AudioSystem.MODE_NORMAL;
}
- } else {
- status = AudioSystem.AUDIO_STATUS_OK;
- }
- } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
-
- if (status == AudioSystem.AUDIO_STATUS_OK) {
- if (actualMode != AudioSystem.MODE_NORMAL) {
- newModeOwnerPid = getModeOwnerPid();
- if (newModeOwnerPid == 0) {
- Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
+ if (mode == AudioSystem.MODE_IN_COMMUNICATION) {
+ // Force active state when entering/updating the stack to avoid glitches when
+ // an app starts playing/recording after settng the audio mode,
+ // and send a reminder to check activity after a grace period.
+ if (!currentModeHandler.isPrivileged()) {
+ currentModeHandler.setPlaybackActive(true);
+ currentModeHandler.setRecordingActive(true);
+ sendMsg(mAudioHandler,
+ MSG_CHECK_MODE_FOR_UID,
+ SENDMSG_QUEUE,
+ 0,
+ 0,
+ currentModeHandler,
+ CHECK_MODE_FOR_UID_PERIOD_MS);
+ }
}
}
- // Note: newModeOwnerPid is always 0 when actualMode is MODE_NORMAL
- mModeLogger.log(
- new PhoneStateEvent(caller, pid, mode, newModeOwnerPid, actualMode));
- int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
- int device = getDeviceForStream(streamType);
- int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
- setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, caller,
- true /*hasModifyAudioSettings*/);
-
- updateStreamVolumeAlias(true /*updateVolumes*/, caller);
-
- // change of mode may require volume to be re-applied on some devices
- updateAbsVolumeMultiModeDevices(oldMode, actualMode);
+ sendMsg(mAudioHandler,
+ MSG_UPDATE_AUDIO_MODE,
+ SENDMSG_REPLACE,
+ mode,
+ pid,
+ callingPackage,
+ 0);
+ }
+ }
- if (actualMode == AudioSystem.MODE_IN_COMMUNICATION
- && !hdlr.isPrivileged()) {
- sendMsg(mAudioHandler,
- MSG_CHECK_MODE_FOR_UID,
- SENDMSG_QUEUE,
- 0,
- 0,
- hdlr,
- CHECK_MODE_FOR_UID_PERIOD_MS);
+ @GuardedBy("mDeviceBroker.mSetModeLock")
+ void onUpdateAudioMode(int requestedMode, int requesterPid, String requesterPackage) {
+ if (requestedMode == AudioSystem.MODE_CURRENT) {
+ requestedMode = getMode();
+ }
+ int mode = AudioSystem.MODE_NORMAL;
+ int uid = 0;
+ int pid = 0;
+ SetModeDeathHandler currentModeHandler = getAudioModeOwnerHandler();
+ if (currentModeHandler != null) {
+ mode = currentModeHandler.getMode();
+ uid = currentModeHandler.getUid();
+ pid = currentModeHandler.getPid();
+ }
+ if (DEBUG_MODE) {
+ Log.v(TAG, "onUpdateAudioMode() mode: " + mode + ", mMode: " + mMode
+ + " requestedMode: " + requestedMode);
+ }
+ if (mode != mMode) {
+ final long identity = Binder.clearCallingIdentity();
+ int status = mAudioSystem.setPhoneState(mode, uid);
+ Binder.restoreCallingIdentity(identity);
+ if (status == AudioSystem.AUDIO_STATUS_OK) {
+ if (DEBUG_MODE) {
+ Log.v(TAG, "onUpdateAudioMode: mode successfully set to " + mode);
+ }
+ int previousMode = mMode;
+ mMode = mode;
+ // Note: newModeOwnerPid is always 0 when actualMode is MODE_NORMAL
+ mModeLogger.log(new PhoneStateEvent(requesterPackage, requesterPid,
+ requestedMode, pid, mode));
+
+ int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
+ int device = getDeviceForStream(streamType);
+ int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
+ setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true,
+ requesterPackage, true /*hasModifyAudioSettings*/);
+
+ updateStreamVolumeAlias(true /*updateVolumes*/, requesterPackage);
+
+ // change of mode may require volume to be re-applied on some devices
+ updateAbsVolumeMultiModeDevices(previousMode, mode);
+
+ // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all SCO
+ // connections not started by the application changing the mode when pid changes
+ mDeviceBroker.postSetModeOwnerPid(pid, mode);
+ } else {
+ Log.w(TAG, "onUpdateAudioMode: failed to set audio mode to: " + mode);
}
}
- return newModeOwnerPid;
}
/** @see AudioManager#getMode() */
public int getMode() {
- return mMode;
+ synchronized (mDeviceBroker.mSetModeLock) {
+ SetModeDeathHandler currentModeHandler = getAudioModeOwnerHandler();
+ if (currentModeHandler != null) {
+ return currentModeHandler.getMode();
+ }
+ return AudioSystem.MODE_NORMAL;
+ }
}
/** cached value read from audiopolicy manager after initialization. */
@@ -5685,11 +5869,6 @@ public class AudioService extends IAudioService.Stub
throw new IllegalArgumentException("Illegal BluetoothProfile state for device "
+ " (dis)connection, got " + state);
}
- if (state == BluetoothProfile.STATE_CONNECTED) {
- mPlaybackMonitor.registerPlaybackCallback(mVoiceActivityMonitor, true);
- } else {
- mPlaybackMonitor.unregisterPlaybackCallback(mVoiceActivityMonitor);
- }
mDeviceBroker.postBluetoothHearingAidDeviceConnectionState(
device, state, suppressNoisyIntent, musicDevice, "AudioService");
}
@@ -7034,6 +7213,9 @@ public class AudioService extends IAudioService.Stub
case MSG_PLAYBACK_CONFIG_CHANGE:
onPlaybackConfigChange((List<AudioPlaybackConfiguration>) msg.obj);
break;
+ case MSG_RECORDING_CONFIG_CHANGE:
+ onRecordingConfigChange((List<AudioRecordingConfiguration>) msg.obj);
+ break;
case MSG_BROADCAST_MICROPHONE_MUTE:
mSystemServer.sendMicrophoneMuteChangedIntent();
@@ -7044,30 +7226,19 @@ public class AudioService extends IAudioService.Stub
if (msg.obj == null) {
break;
}
- // If no other app is currently owning the audio mode and
- // the app corresponding to this mode death handler object is still in the
- // mode owner stack but not capturing or playing audio after 3 seconds,
- // remove it from the stack.
- // Otherwise, check again in 3 seconds.
+ // Update active playback/recording for apps requesting IN_COMMUNICATION
+ // mode after a grace period following the mode change
SetModeDeathHandler h = (SetModeDeathHandler) msg.obj;
if (mSetModeDeathHandlers.indexOf(h) < 0) {
break;
}
- if (getModeOwnerUid() != h.getUid()
- || mRecordMonitor.isRecordingActiveForUid(h.getUid())
- || mPlaybackMonitor.isPlaybackActiveForUid(h.getUid())) {
- sendMsg(mAudioHandler,
- MSG_CHECK_MODE_FOR_UID,
- SENDMSG_QUEUE,
- 0,
- 0,
- h,
- CHECK_MODE_FOR_UID_PERIOD_MS);
- break;
+ boolean wasActive = h.isActive();
+ h.setPlaybackActive(mPlaybackMonitor.isPlaybackActiveForUid(h.getUid()));
+ h.setRecordingActive(mRecordMonitor.isRecordingActiveForUid(h.getUid()));
+ if (wasActive != h.isActive()) {
+ onUpdateAudioMode(AudioSystem.MODE_CURRENT,
+ android.os.Process.myPid(), mContext.getPackageName());
}
- setModeInt(AudioSystem.MODE_NORMAL, h.getBinder(), h.getPid(), h.getUid(),
- h.isPrivileged(), "MSG_CHECK_MODE_FOR_UID");
- mModeLogger.log(new PhoneStateEvent(h.getPackage(), h.getPid()));
}
break;
@@ -7084,10 +7255,16 @@ public class AudioService extends IAudioService.Stub
case MSG_REINIT_VOLUMES:
onReinitVolumes((String) msg.obj);
break;
+
case MSG_UPDATE_A11Y_SERVICE_UIDS:
onUpdateAccessibilityServiceUids();
break;
+ case MSG_UPDATE_AUDIO_MODE:
+ synchronized (mDeviceBroker.mSetModeLock) {
+ onUpdateAudioMode(msg.arg1, msg.arg2, (String) msg.obj);
+ }
+ break;
}
}
}
@@ -8118,6 +8295,7 @@ public class AudioService extends IAudioService.Stub
dumpStreamStates(pw);
dumpVolumeGroups(pw);
dumpRingerMode(pw);
+ dumpAudioMode(pw);
pw.println("\nAudio routes:");
pw.print(" mMainType=0x"); pw.println(Integer.toHexString(
mDeviceBroker.getCurAudioRoutes().mainType));
@@ -9088,6 +9266,18 @@ public class AudioService extends IAudioService.Stub
}
/**
+ * Update player session ID
+ * @param piid Player id to update
+ * @param sessionId The new audio session ID
+ */
+ public void playerSessionId(int piid, int sessionId) {
+ if (sessionId <= AudioSystem.AUDIO_SESSION_ALLOCATE) {
+ throw new IllegalArgumentException("invalid session Id " + sessionId);
+ }
+ mPlaybackMonitor.playerSessionId(piid, sessionId, Binder.getCallingUid());
+ }
+
+ /**
* Update player event
* @param piid Player id to update
* @param event The new player event
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 36c67cdbac4b..68a084e6d249 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -197,6 +197,28 @@ public final class PlaybackActivityMonitor
}
}
+ /**
+ * Update player session ID
+ * @param piid Player id to update
+ * @param sessionId The new audio session ID
+ * @param binderUid Calling binder uid
+ */
+ public void playerSessionId(int piid, int sessionId, int binderUid) {
+ final boolean change;
+ synchronized (mPlayerLock) {
+ final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
+ if (checkConfigurationCaller(piid, apc, binderUid)) {
+ change = apc.handleSessionIdEvent(sessionId);
+ } else {
+ Log.e(TAG, "Error updating audio session");
+ change = false;
+ }
+ }
+ if (change) {
+ dispatchPlaybackChange(false);
+ }
+ }
+
private static final int FLAGS_FOR_SILENCE_OVERRIDE =
AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY |
AudioAttributes.FLAG_BYPASS_MUTE;
@@ -921,6 +943,7 @@ public final class PlaybackActivityMonitor
private final int mClientUid;
private final int mClientPid;
private final AudioAttributes mPlayerAttr;
+ private final int mSessionId;
NewPlayerEvent(AudioPlaybackConfiguration apc) {
mPlayerIId = apc.getPlayerInterfaceId();
@@ -928,6 +951,7 @@ public final class PlaybackActivityMonitor
mClientUid = apc.getClientUid();
mClientPid = apc.getClientPid();
mPlayerAttr = apc.getAudioAttributes();
+ mSessionId = apc.getSessionId();
}
@Override
@@ -935,7 +959,8 @@ public final class PlaybackActivityMonitor
return new String("new player piid:" + mPlayerIId + " uid/pid:" + mClientUid + "/"
+ mClientPid + " type:"
+ AudioPlaybackConfiguration.toLogFriendlyPlayerType(mPlayerType)
- + " attr:" + mPlayerAttr);
+ + " attr:" + mPlayerAttr
+ + " session:" + mSessionId);
}
}
diff --git a/services/core/java/com/android/server/biometrics/PreAuthInfo.java b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
index 6905b3da9bc4..6851d7148191 100644
--- a/services/core/java/com/android/server/biometrics/PreAuthInfo.java
+++ b/services/core/java/com/android/server/biometrics/PreAuthInfo.java
@@ -90,6 +90,7 @@ class PreAuthInfo {
int userId, PromptInfo promptInfo, String opPackageName,
boolean checkDevicePolicyManager)
throws RemoteException {
+
final boolean confirmationRequested = promptInfo.isConfirmationRequested();
final boolean biometricRequested = Utils.isBiometricRequested(promptInfo);
final int requestedStrength = Utils.getPublicBiometricStrength(promptInfo);
@@ -111,7 +112,7 @@ class PreAuthInfo {
@AuthenticatorStatus int status = getStatusForBiometricAuthenticator(
devicePolicyManager, settingObserver, sensor, userId, opPackageName,
- checkDevicePolicyManager, requestedStrength);
+ checkDevicePolicyManager, requestedStrength, promptInfo.getSensorId());
Slog.d(TAG, "Package: " + opPackageName
+ " Sensor ID: " + sensor.id
@@ -141,7 +142,11 @@ class PreAuthInfo {
DevicePolicyManager devicePolicyManager,
BiometricService.SettingObserver settingObserver,
BiometricSensor sensor, int userId, String opPackageName,
- boolean checkDevicePolicyManager, int requestedStrength) {
+ boolean checkDevicePolicyManager, int requestedStrength, int requestedSensorId) {
+
+ if (requestedSensorId != BiometricManager.SENSOR_ID_ANY && sensor.id != requestedSensorId) {
+ return BIOMETRIC_NO_HARDWARE;
+ }
final boolean wasStrongEnough =
Utils.isAtLeastStrength(sensor.oemStrength, requestedStrength);
diff --git a/services/core/java/com/android/server/biometrics/Utils.java b/services/core/java/com/android/server/biometrics/Utils.java
index d87af4280ca3..5cd0bbfa4500 100644
--- a/services/core/java/com/android/server/biometrics/Utils.java
+++ b/services/core/java/com/android/server/biometrics/Utils.java
@@ -399,10 +399,15 @@ public class Utils {
}
}
- public static boolean isKeyguard(Context context, String clientPackage) {
- final boolean hasPermission = context.checkCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL)
- == PackageManager.PERMISSION_GRANTED;
-
+ /**
+ * Checks if a client package matches Keyguard and can perform internal biometric operations.
+ *
+ * @param context The system context.
+ * @param clientPackage The name of the package to be checked against Keyguard.
+ * @return Whether the given package matches Keyguard.
+ */
+ public static boolean isKeyguard(@NonNull Context context, @Nullable String clientPackage) {
+ final boolean hasPermission = hasInternalPermission(context);
final ComponentName keyguardComponent = ComponentName.unflattenFromString(
context.getResources().getString(R.string.config_keyguardComponent));
final String keyguardPackage = keyguardComponent != null
@@ -410,6 +415,34 @@ public class Utils {
return hasPermission && keyguardPackage != null && keyguardPackage.equals(clientPackage);
}
+ /**
+ * Checks if a client package matches the Android system and can perform internal biometric
+ * operations.
+ *
+ * @param context The system context.
+ * @param clientPackage The name of the package to be checked against the Android system.
+ * @return Whether the given package matches the Android system.
+ */
+ public static boolean isSystem(@NonNull Context context, @Nullable String clientPackage) {
+ return hasInternalPermission(context) && "android".equals(clientPackage);
+ }
+
+ /**
+ * Checks if a client package matches Settings and can perform internal biometric operations.
+ *
+ * @param context The system context.
+ * @param clientPackage The name of the package to be checked against Settings.
+ * @return Whether the given package matches Settings.
+ */
+ public static boolean isSettings(@NonNull Context context, @Nullable String clientPackage) {
+ return hasInternalPermission(context) && "com.android.settings".equals(clientPackage);
+ }
+
+ private static boolean hasInternalPermission(@NonNull Context context) {
+ return context.checkCallingOrSelfPermission(USE_BIOMETRIC_INTERNAL)
+ == PackageManager.PERMISSION_GRANTED;
+ }
+
public static String getClientName(@Nullable BaseClientMonitor client) {
return client != null ? client.getClass().getSimpleName() : "null";
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index 14433fb0ea9a..0536e78e58f6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -149,9 +149,10 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
pm.incrementAuthForUser(getTargetUserId(), authenticated);
}
- // Ensure authentication only succeeds if the client activity is on top or is keyguard.
+ // Ensure authentication only succeeds if the client activity is on top.
boolean isBackgroundAuth = false;
- if (authenticated && !Utils.isKeyguard(getContext(), getOwnerString())) {
+ if (authenticated && !Utils.isKeyguard(getContext(), getOwnerString())
+ && !Utils.isSystem(getContext(), getOwnerString())) {
final List<ActivityManager.RunningTaskInfo> tasks =
mActivityTaskManager.getTasks(1);
if (tasks == null || tasks.isEmpty()) {
@@ -166,7 +167,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
final String topPackage = topActivity.getPackageName();
if (!topPackage.contentEquals(getOwnerString())) {
Slog.e(TAG, "Background authentication detected, top: " + topPackage
- + ", client: " + this);
+ + ", client: " + getOwnerString());
isBackgroundAuth = true;
}
}
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 0265cb93ac8b..b0e42cd137eb 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
@@ -25,6 +25,10 @@ import static android.Manifest.permission.USE_BIOMETRIC;
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
import static android.Manifest.permission.USE_FINGERPRINT;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_USER_CANCELED;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ERROR_VENDOR;
+import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -32,6 +36,7 @@ import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.IBiometricSensorReceiver;
import android.hardware.biometrics.IBiometricService;
@@ -49,6 +54,7 @@ import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.Binder;
import android.os.Build;
+import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IBinder;
import android.os.Process;
@@ -80,6 +86,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.concurrent.Executor;
/**
* A service to manage multiple clients that want to access the fingerprint HAL API.
@@ -190,7 +197,7 @@ public class FingerprintService extends SystemService implements BiometricServic
@Override // Binder call
public void enroll(final IBinder token, final byte[] hardwareAuthToken, final int userId,
final IFingerprintServiceReceiver receiver, final String opPackageName,
- boolean shouldLogMetrics) {
+ @FingerprintManager.EnrollReason int enrollReason) {
Utils.checkPermission(getContext(), MANAGE_FINGERPRINT);
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
@@ -200,7 +207,7 @@ public class FingerprintService extends SystemService implements BiometricServic
}
provider.second.scheduleEnroll(provider.first, token, hardwareAuthToken, userId,
- receiver, opPackageName, shouldLogMetrics);
+ receiver, opPackageName, enrollReason);
}
@Override // Binder call
@@ -219,8 +226,8 @@ public class FingerprintService extends SystemService implements BiometricServic
@SuppressWarnings("deprecation")
@Override // Binder call
public void authenticate(final IBinder token, final long operationId,
- @FingerprintManager.SensorId final int sensorId, final int userId,
- final IFingerprintServiceReceiver receiver, final String opPackageName) {
+ final int sensorId, final int userId, final IFingerprintServiceReceiver receiver,
+ final String opPackageName) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final int callingUserId = UserHandle.getCallingUserId();
@@ -236,7 +243,7 @@ public class FingerprintService extends SystemService implements BiometricServic
final boolean isKeyguard = Utils.isKeyguard(getContext(), opPackageName);
// Clear calling identity when checking LockPatternUtils for StrongAuth flags.
- final long identity = Binder.clearCallingIdentity();
+ long identity = Binder.clearCallingIdentity();
try {
if (isKeyguard && Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) {
// If this happens, something in KeyguardUpdateMonitor is wrong.
@@ -266,9 +273,101 @@ public class FingerprintService extends SystemService implements BiometricServic
return;
}
- provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
- 0 /* cookie */, new ClientMonitorCallbackConverter(receiver), opPackageName,
- restricted, statsClient, isKeyguard);
+ final FingerprintSensorPropertiesInternal sensorProps =
+ provider.second.getSensorProperties(sensorId);
+ if (!isKeyguard && !Utils.isSettings(getContext(), opPackageName)
+ && sensorProps != null && sensorProps.isAnyUdfpsType()) {
+ identity = Binder.clearCallingIdentity();
+ try {
+ authenticateWithPrompt(operationId, sensorProps, userId, receiver);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ } else {
+ provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
+ 0 /* cookie */, new ClientMonitorCallbackConverter(receiver), opPackageName,
+ restricted, statsClient, isKeyguard);
+ }
+ }
+
+ private void authenticateWithPrompt(
+ final long operationId,
+ @NonNull final FingerprintSensorPropertiesInternal props,
+ final int userId,
+ final IFingerprintServiceReceiver receiver) {
+
+ final Context context = getUiContext();
+ final Executor executor = context.getMainExecutor();
+
+ final BiometricPrompt biometricPrompt = new BiometricPrompt.Builder(context)
+ .setTitle(context.getString(R.string.biometric_dialog_default_title))
+ .setSubtitle(context.getString(R.string.fingerprint_dialog_default_subtitle))
+ .setNegativeButton(
+ context.getString(R.string.cancel),
+ executor,
+ (dialog, which) -> {
+ try {
+ receiver.onError(
+ FINGERPRINT_ERROR_USER_CANCELED, 0 /* vendorCode */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception in negative button onClick()", e);
+ }
+ })
+ .setSensorId(props.sensorId)
+ .build();
+
+ final BiometricPrompt.AuthenticationCallback promptCallback =
+ new BiometricPrompt.AuthenticationCallback() {
+ @Override
+ public void onAuthenticationError(int errorCode, CharSequence errString) {
+ try {
+ if (FingerprintUtils.isKnownErrorCode(errorCode)) {
+ receiver.onError(errorCode, 0 /* vendorCode */);
+ } else {
+ receiver.onError(FINGERPRINT_ERROR_VENDOR, errorCode);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception in onAuthenticationError()", e);
+ }
+ }
+
+ @Override
+ public void onAuthenticationSucceeded(
+ BiometricPrompt.AuthenticationResult result) {
+ final Fingerprint fingerprint = new Fingerprint("", 0, 0L);
+ final boolean isStrong = props.sensorStrength == STRENGTH_STRONG;
+ try {
+ receiver.onAuthenticationSucceeded(fingerprint, userId, isStrong);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception in onAuthenticationSucceeded()", e);
+ }
+ }
+
+ @Override
+ public void onAuthenticationFailed() {
+ try {
+ receiver.onAuthenticationFailed();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception in onAuthenticationFailed()", e);
+ }
+ }
+
+ @Override
+ public void onAuthenticationAcquired(int acquireInfo) {
+ try {
+ if (FingerprintUtils.isKnownAcquiredCode(acquireInfo)) {
+ receiver.onAcquired(acquireInfo, 0 /* vendorCode */);
+ } else {
+ receiver.onAcquired(FINGERPRINT_ACQUIRED_VENDOR, acquireInfo);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Remote exception in onAuthenticationAcquired()", e);
+ }
+ }
+ };
+
+ biometricPrompt.authenticateUserForOperation(
+ new CancellationSignal(), executor, promptCallback, userId, operationId);
}
@Override
@@ -374,6 +473,7 @@ public class FingerprintService extends SystemService implements BiometricServic
@Override // Binder call
public void cancelAuthenticationFromService(final int sensorId, final IBinder token,
final String opPackageName) {
+
Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
final ServiceProvider provider = getProviderForSensor(sensorId);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUtils.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUtils.java
index dc6fd3a1b26d..d69151da55f6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUtils.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintUtils.java
@@ -16,8 +16,18 @@
package com.android.server.biometrics.sensors.fingerprint;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_IMAGER_DIRTY;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_INSUFFICIENT;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_PARTIAL;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_TOO_FAST;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_TOO_SLOW;
+import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR;
+
import android.annotation.Nullable;
import android.content.Context;
+import android.hardware.biometrics.fingerprint.V2_1.FingerprintError;
import android.hardware.fingerprint.Fingerprint;
import android.text.TextUtils;
import android.util.SparseArray;
@@ -138,5 +148,51 @@ public class FingerprintUtils implements BiometricUtils<Fingerprint> {
return state;
}
}
+
+ /**
+ * Checks if the given error code corresponds to a known fingerprint error.
+ *
+ * @param errorCode The error code to be checked.
+ * @return Whether the error code corresponds to a known error.
+ */
+ public static boolean isKnownErrorCode(int errorCode) {
+ switch (errorCode) {
+ case FingerprintError.ERROR_HW_UNAVAILABLE:
+ case FingerprintError.ERROR_UNABLE_TO_PROCESS:
+ case FingerprintError.ERROR_TIMEOUT:
+ case FingerprintError.ERROR_NO_SPACE:
+ case FingerprintError.ERROR_CANCELED:
+ case FingerprintError.ERROR_UNABLE_TO_REMOVE:
+ case FingerprintError.ERROR_LOCKOUT:
+ case FingerprintError.ERROR_VENDOR:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the given acquired code corresponds to a known fingerprint error.
+ *
+ * @param acquiredCode The acquired code to be checked.
+ * @return Whether the acquired code corresponds to a known error.
+ */
+ public static boolean isKnownAcquiredCode(int acquiredCode) {
+ switch (acquiredCode) {
+ case FINGERPRINT_ACQUIRED_GOOD:
+ 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_VENDOR:
+ case FINGERPRINT_ACQUIRED_START:
+ return true;
+
+ default:
+ return false;
+ }
+ }
}
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 303c080c044c..f672ae56e020 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
@@ -78,7 +78,7 @@ public interface ServiceProvider {
void scheduleEnroll(int sensorId, @NonNull IBinder token, byte[] hardwareAuthToken, int userId,
@NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
- boolean shouldLogMetrics);
+ @FingerprintManager.EnrollReason int enrollReason);
void cancelEnrollment(int sensorId, @NonNull IBinder token);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java
index d092e860e208..37f8e8c2c1ee 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/UdfpsHelper.java
@@ -65,6 +65,17 @@ public class UdfpsHelper {
}
}
+ public static int getReasonFromEnrollReason(@FingerprintManager.EnrollReason int reason) {
+ switch (reason) {
+ case FingerprintManager.ENROLL_FIND_SENSOR:
+ return IUdfpsOverlayController.REASON_ENROLL_FIND_SENSOR;
+ case FingerprintManager.ENROLL_ENROLL:
+ return IUdfpsOverlayController.REASON_ENROLL_ENROLLING;
+ default:
+ return IUdfpsOverlayController.REASON_UNKNOWN;
+ }
+ }
+
public static void showUdfpsOverlay(int sensorId, int reason,
@Nullable IUdfpsOverlayController udfpsOverlayController) {
if (udfpsOverlayController == null) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
index c2a30be6e2cb..ea9c709ec79f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.ITestSession;
import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.os.Binder;
import android.util.Slog;
@@ -131,7 +132,7 @@ class BiometricTestSessionImpl extends ITestSession.Stub {
Utils.checkPermission(mContext, TEST_BIOMETRIC);
mProvider.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver,
- mContext.getOpPackageName(), true /* shouldLogMetrics */);
+ mContext.getOpPackageName(), FingerprintManager.ENROLL_ENROLL);
}
@Override
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 08cc464b4766..ae64c77f1365 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
@@ -25,6 +25,7 @@ import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.common.ICancellationSignal;
import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.IBinder;
import android.os.RemoteException;
@@ -43,6 +44,7 @@ class FingerprintEnrollClient extends EnrollClient<ISession> implements Udfps {
private static final String TAG = "FingerprintEnrollClient";
@Nullable private final IUdfpsOverlayController mUdfpsOverlayController;
+ private final @FingerprintManager.EnrollReason int mEnrollReason;
@Nullable private ICancellationSignal mCancellationSignal;
private final int mMaxTemplatesPerUser;
@@ -52,13 +54,17 @@ class FingerprintEnrollClient extends EnrollClient<ISession> implements Udfps {
@NonNull byte[] hardwareAuthToken, @NonNull String owner,
@NonNull BiometricUtils<Fingerprint> utils, int sensorId,
@Nullable IUdfpsOverlayController udfpsOvelayController, int maxTemplatesPerUser,
- boolean shouldLogMetrics) {
+ @FingerprintManager.EnrollReason int enrollReason) {
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
0 /* timeoutSec */, BiometricsProtoEnums.MODALITY_FINGERPRINT, sensorId,
true /* shouldVibrate */);
mUdfpsOverlayController = udfpsOvelayController;
mMaxTemplatesPerUser = maxTemplatesPerUser;
- setShouldLog(shouldLogMetrics);
+
+ mEnrollReason = enrollReason;
+ if (enrollReason == FingerprintManager.ENROLL_FIND_SENSOR) {
+ setShouldLog(false);
+ }
}
@Override
@@ -72,6 +78,7 @@ class FingerprintEnrollClient extends EnrollClient<ISession> implements Udfps {
}
}
+
@Override
public void onAcquired(int acquiredInfo, int vendorCode) {
super.onAcquired(acquiredInfo, vendorCode);
@@ -112,7 +119,8 @@ class FingerprintEnrollClient extends EnrollClient<ISession> implements Udfps {
@Override
protected void startHalOperation() {
- UdfpsHelper.showUdfpsOverlay(getSensorId(), IUdfpsOverlayController.REASON_ENROLL,
+ UdfpsHelper.showUdfpsOverlay(getSensorId(),
+ UdfpsHelper.getReasonFromEnrollReason(mEnrollReason),
mUdfpsOverlayController);
try {
mCancellationSignal = getFreshDaemon().enroll(mSequentialId,
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 f8450245a18d..ced46e140c0a 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
@@ -28,6 +28,7 @@ import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.fingerprint.IFingerprint;
import android.hardware.biometrics.fingerprint.SensorProps;
import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.hardware.fingerprint.IUdfpsOverlayController;
@@ -96,7 +97,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
Slog.e(getTag(), "Task stack changed for client: " + client);
continue;
}
- if (Utils.isKeyguard(mContext, client.getOwnerString())) {
+ if (Utils.isKeyguard(mContext, client.getOwnerString())
+ || Utils.isSystem(mContext, client.getOwnerString())) {
continue; // Keyguard is always allowed
}
@@ -365,7 +367,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
@Override
public void scheduleEnroll(int sensorId, @NonNull IBinder token, byte[] hardwareAuthToken,
int userId, @NonNull IFingerprintServiceReceiver receiver,
- @NonNull String opPackageName, boolean shouldLogMetrics) {
+ @NonNull String opPackageName, @FingerprintManager.EnrollReason int enrollReason) {
mHandler.post(() -> {
final IFingerprint daemon = getHalInstance();
if (daemon == null) {
@@ -387,7 +389,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
mSensors.get(sensorId).getLazySession(), token,
new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
opPackageName, FingerprintUtils.getInstance(sensorId), sensorId,
- mUdfpsOverlayController, maxTemplatesPerUser, shouldLogMetrics);
+ mUdfpsOverlayController, maxTemplatesPerUser, enrollReason);
scheduleForSensor(sensorId, client, new BaseClientMonitor.Callback() {
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
index 6893e72486bc..312ee0a267ac 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
@@ -22,6 +22,7 @@ import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.ITestSession;
import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
import android.os.Binder;
import android.util.Slog;
@@ -132,7 +133,7 @@ public class BiometricTestSessionImpl extends ITestSession.Stub {
Utils.checkPermission(mContext, TEST_BIOMETRIC);
mFingerprint21.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver,
- mContext.getOpPackageName(), true/* shouldLogMetrics */);
+ mContext.getOpPackageName(), FingerprintManager.ENROLL_ENROLL);
}
@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 1135126d86fb..7a74c6a39aa1 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
@@ -33,6 +33,7 @@ import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.hardware.biometrics.fingerprint.V2_2.IBiometricsFingerprintClientCallback;
import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintServiceReceiver;
@@ -49,6 +50,7 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.biometrics.SensorServiceStateProto;
import com.android.server.biometrics.SensorStateProto;
@@ -113,7 +115,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
@NonNull private final HalResultController mHalResultController;
@Nullable private IUdfpsOverlayController mUdfpsOverlayController;
private int mCurrentUserId = UserHandle.USER_NULL;
- private boolean mIsUdfps = false;
+ private final boolean mIsUdfps;
private final int mSensorId;
private final class BiometricTaskStackListener extends TaskStackListener {
@@ -125,7 +127,8 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
Slog.e(TAG, "Task stack changed for client: " + client);
return;
}
- if (Utils.isKeyguard(mContext, client.getOwnerString())) {
+ if (Utils.isKeyguard(mContext, client.getOwnerString())
+ || Utils.isSystem(mContext, client.getOwnerString())) {
return; // Keyguard is always allowed
}
@@ -335,23 +338,14 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
Slog.e(TAG, "Unable to register user switch observer");
}
- final IBiometricsFingerprint daemon = getDaemon();
- mIsUdfps = false;
- android.hardware.biometrics.fingerprint.V2_3.IBiometricsFingerprint extension =
- android.hardware.biometrics.fingerprint.V2_3.IBiometricsFingerprint.castFrom(
- daemon);
- if (extension != null) {
- try {
- mIsUdfps = extension.isUdfps(sensorId);
- } catch (RemoteException e) {
- Slog.e(TAG, "Remote exception while quering udfps", e);
- mIsUdfps = false;
- }
- }
+ // TODO(b/179175438): Remove this code block after transition to AIDL.
+ // The existence of config_udfps_sensor_props indicates that the sensor is UDFPS.
+ mIsUdfps = !ArrayUtils.isEmpty(
+ mContext.getResources().getIntArray(R.array.config_udfps_sensor_props));
final @FingerprintSensorProperties.SensorType int sensorType =
mIsUdfps ? FingerprintSensorProperties.TYPE_UDFPS_OPTICAL
- : FingerprintSensorProperties.TYPE_REAR;
+ : FingerprintSensorProperties.TYPE_REAR;
// resetLockout is controlled by the framework, so hardwareAuthToken is not required
final boolean resetLockoutRequiresHardwareAuthToken = false;
final int maxEnrollmentsPerUser = mContext.getResources()
@@ -415,7 +409,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
Slog.d(TAG, "Daemon was null, reconnecting, current operation: "
+ mScheduler.getCurrentClient());
try {
- mDaemon = IBiometricsFingerprint.getService(true /* retry */);
+ mDaemon = IBiometricsFingerprint.getService();
} catch (java.util.NoSuchElementException e) {
// Service doesn't exist or cannot be opened.
Slog.w(TAG, "NoSuchElementException", e);
@@ -554,7 +548,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
public void scheduleEnroll(int sensorId, @NonNull IBinder token,
@NonNull byte[] hardwareAuthToken, int userId,
@NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
- boolean shouldLogMetrics) {
+ @FingerprintManager.EnrollReason int enrollReason) {
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
@@ -562,7 +556,7 @@ public class Fingerprint21 implements IHwBinder.DeathRecipient, ServiceProvider
mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId,
hardwareAuthToken, opPackageName, FingerprintUtils.getLegacyInstance(mSensorId),
ENROLL_TIMEOUT_SEC, mSensorProperties.sensorId, mUdfpsOverlayController,
- shouldLogMetrics);
+ enrollReason);
mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
index d927aa717fbc..33db64c3259b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintEnrollClient.java
@@ -24,6 +24,7 @@ import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricsProtoEnums;
import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.IBinder;
import android.os.RemoteException;
@@ -46,6 +47,7 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
private static final String TAG = "FingerprintEnrollClient";
@Nullable private final IUdfpsOverlayController mUdfpsOverlayController;
+ private final @FingerprintManager.EnrollReason int mEnrollReason;
FingerprintEnrollClient(@NonNull Context context,
@NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token,
@@ -53,12 +55,16 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
@NonNull byte[] hardwareAuthToken, @NonNull String owner,
@NonNull BiometricUtils<Fingerprint> utils, int timeoutSec, int sensorId,
@Nullable IUdfpsOverlayController udfpsOverlayController,
- boolean shouldLogMetrics) {
+ @FingerprintManager.EnrollReason int enrollReason) {
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
timeoutSec, BiometricsProtoEnums.MODALITY_FINGERPRINT, sensorId,
true /* shouldVibrate */);
mUdfpsOverlayController = udfpsOverlayController;
- setShouldLog(shouldLogMetrics);
+
+ mEnrollReason = enrollReason;
+ if (enrollReason == FingerprintManager.ENROLL_FIND_SENSOR) {
+ setShouldLog(false);
+ }
}
@Override
@@ -76,7 +82,8 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
@Override
protected void startHalOperation() {
- UdfpsHelper.showUdfpsOverlay(getSensorId(), IUdfpsOverlayController.REASON_ENROLL,
+ UdfpsHelper.showUdfpsOverlay(getSensorId(),
+ UdfpsHelper.getReasonFromEnrollReason(mEnrollReason),
mUdfpsOverlayController);
try {
// GroupId was never used. In fact, groupId is always the same as userId.
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 6b2a1c950e38..51ba5f775880 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -211,9 +211,9 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
@Override
- public void clearOverrideForTest(long changeId, String packageName) {
+ public boolean clearOverrideForTest(long changeId, String packageName) {
checkCompatChangeOverridePermission();
- mCompatConfig.removeOverride(changeId, packageName);
+ return mCompatConfig.removeOverride(changeId, packageName);
}
@Override
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index c70bb080b0b1..43d9ade67a11 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -32,6 +32,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.IDnsResolver;
+import android.net.InetAddresses;
import android.net.LinkProperties;
import android.net.Network;
import android.net.ResolverOptionsParcel;
@@ -190,7 +191,7 @@ public class DnsManager {
for (String ipAddress : ipAddresses) {
try {
latestDnses.add(new Pair(hostname,
- InetAddress.parseNumericAddress(ipAddress)));
+ InetAddresses.parseNumericAddress(ipAddress)));
} catch (IllegalArgumentException e) {}
}
// Remove <hostname, ipAddress> pairs that should not be tracked.
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 952193b77681..46c49e7fc28c 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -34,9 +34,9 @@ import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
+import com.android.net.module.util.NetworkStackConstants;
import com.android.server.net.BaseNetworkObserver;
-import java.net.Inet4Address;
import java.net.Inet6Address;
import java.util.Objects;
@@ -433,7 +433,7 @@ public class Nat464Xlat extends BaseNetworkObserver {
// clat IPv4 address itself (for those apps, it doesn't matter what
// the IP of the gateway is, only that there is one).
RouteInfo ipv4Default = new RouteInfo(
- new LinkAddress(Inet4Address.ANY, 0),
+ new LinkAddress(NetworkStackConstants.IPV4_ADDR_ANY, 0),
clatAddress.getAddress(), mIface);
stacked.addRoute(ipv4Default);
stacked.addLinkAddress(clatAddress);
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index a9a705f07ac4..bff1a5c99dd2 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -122,6 +122,13 @@ import java.util.TreeSet;
//
// When ConnectivityService disconnects a network:
// -----------------------------------------------
+// If a network is just connected, ConnectivityService will think it will be used soon, but might
+// not be used. Thus, a 5s timer will be held to prevent the network being torn down immediately.
+// This "nascent" state is implemented by the "lingering" logic below without relating to any
+// request, and is used in some cases where network requests race with network establishment. The
+// nascent state ends when the 5-second timer fires, or as soon as the network satisfies a
+// request, whichever is earlier. In this state, the network is considered in the background.
+//
// If a network has no chance of satisfying any requests (even if it were to become validated
// and enter state #5), ConnectivityService will disconnect the NetworkAgent's AsyncChannel.
//
@@ -271,7 +278,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
// All inactivity timers for this network, sorted by expiry time. A timer is added whenever
// a request is moved to a network with a better score, regardless of whether the network is or
- // was lingering or not.
+ // was lingering or not. An inactivity timer is also added when a network connects
+ // without immediately satisfying any requests.
// TODO: determine if we can replace this with a smaller or unsorted data structure. (e.g.,
// SparseLongArray) combined with the timestamp of when the last timer is scheduled to fire.
private final SortedSet<InactivityTimer> mInactivityTimers = new TreeSet<>();
@@ -896,7 +904,12 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
/**
* Sets the specified requestId to linger on this network for the specified time. Called by
- * ConnectivityService when the request is moved to another network with a higher score.
+ * ConnectivityService when the request is moved to another network with a higher score, or
+ * when a network is newly created.
+ *
+ * @param requestId The requestId of the request that no longer need to be served by this
+ * network. Or {@link NetworkRequest.REQUEST_ID_NONE} if this is the
+ * {@code LingerTimer} for a newly created network.
*/
public void lingerRequest(int requestId, long now, long duration) {
if (mInactivityTimerForRequest.get(requestId) != null) {
@@ -969,10 +982,23 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
mInactive = false;
}
- public boolean isLingering() {
+ public boolean isInactive() {
return mInactive;
}
+ public boolean isLingering() {
+ return mInactive && !isNascent();
+ }
+
+ /**
+ * Return whether the network is just connected and about to be torn down because of not
+ * satisfying any request.
+ */
+ public boolean isNascent() {
+ return mInactive && mInactivityTimers.size() == 1
+ && mInactivityTimers.first().requestId == NetworkRequest.REQUEST_ID_NONE;
+ }
+
public void clearInactivityState() {
if (mInactivityMessage != null) {
mInactivityMessage.cancel();
@@ -1022,7 +1048,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
+ "network{" + network + "} handle{" + network.getNetworkHandle() + "} ni{"
+ networkInfo.toShortString() + "} "
+ " Score{" + getCurrentScore() + "} "
- + (isLingering() ? " lingering" : "")
+ + (isNascent() ? " nascent" : (isLingering() ? " lingering" : ""))
+ (everValidated ? " everValidated" : "")
+ (lastValidated ? " lastValidated" : "")
+ (partialConnectivity ? " partialConnectivity" : "")
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index d507b5f82bd0..8d21f6f0f59f 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -265,7 +265,10 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
for (Entry<Integer, Boolean> app : apps.entrySet()) {
List<Integer> list = app.getValue() ? system : network;
for (int user : users) {
- list.add(UserHandle.getUid(user, app.getKey()));
+ final UserHandle handle = UserHandle.of(user);
+ if (handle == null) continue;
+
+ list.add(UserHandle.getUid(handle, app.getKey()));
}
}
try {
@@ -550,7 +553,10 @@ public class PermissionMonitor implements PackageManagerInternal.PackageListObse
for (UidRange range : ranges) {
for (int userId = range.getStartUser(); userId <= range.getEndUser(); userId++) {
for (int appId : appIds) {
- final int uid = UserHandle.getUid(userId, appId);
+ final UserHandle handle = UserHandle.of(userId);
+ if (handle == null) continue;
+
+ final int uid = UserHandle.getUid(handle, appId);
if (range.contains(uid)) {
result.add(uid);
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index e8062ae0eb57..fc2c7e01efde 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -51,6 +51,7 @@ import android.net.DnsResolver;
import android.net.INetd;
import android.net.INetworkManagementEventObserver;
import android.net.Ikev2VpnProfile;
+import android.net.InetAddresses;
import android.net.IpPrefix;
import android.net.IpSecManager;
import android.net.IpSecManager.IpSecTunnelInterface;
@@ -111,6 +112,7 @@ import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
+import com.android.net.module.util.NetworkStackConstants;
import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.net.BaseNetworkObserver;
@@ -332,7 +334,7 @@ public class Vpn {
public InetAddress resolve(final String endpoint)
throws ExecutionException, InterruptedException {
try {
- return InetAddress.parseNumericAddress(endpoint);
+ return InetAddresses.parseNumericAddress(endpoint);
} catch (IllegalArgumentException e) {
// Endpoint is not numeric : fall through and resolve
}
@@ -1125,7 +1127,7 @@ public class Vpn {
if (mConfig.dnsServers != null) {
for (String dnsServer : mConfig.dnsServers) {
- InetAddress address = InetAddress.parseNumericAddress(dnsServer);
+ InetAddress address = InetAddresses.parseNumericAddress(dnsServer);
lp.addDnsServer(address);
allowIPv4 |= address instanceof Inet4Address;
allowIPv6 |= address instanceof Inet6Address;
@@ -1135,10 +1137,12 @@ public class Vpn {
lp.setHttpProxy(mConfig.proxyInfo);
if (!allowIPv4) {
- lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
+ lp.addRoute(new RouteInfo(new IpPrefix(
+ NetworkStackConstants.IPV4_ADDR_ANY, 0), RTN_UNREACHABLE));
}
if (!allowIPv6) {
- lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
+ lp.addRoute(new RouteInfo(new IpPrefix(
+ NetworkStackConstants.IPV6_ADDR_ANY, 0), RTN_UNREACHABLE));
}
// Concatenate search domains into a string.
diff --git a/services/core/java/com/android/server/devicestate/DeviceState.java b/services/core/java/com/android/server/devicestate/DeviceState.java
index 802472fcfba8..e496d77deaf5 100644
--- a/services/core/java/com/android/server/devicestate/DeviceState.java
+++ b/services/core/java/com/android/server/devicestate/DeviceState.java
@@ -16,8 +16,6 @@
package com.android.server.devicestate;
-import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
-
import android.annotation.IntRange;
import android.annotation.NonNull;
@@ -37,16 +35,16 @@ import java.util.Objects;
*/
public final class DeviceState {
/** Unique identifier for the device state. */
- @IntRange(from = INVALID_DEVICE_STATE)
+ @IntRange(from = 0)
private final int mIdentifier;
/** String description of the device state. */
@NonNull
private final String mName;
- public DeviceState(@IntRange(from = INVALID_DEVICE_STATE) int identifier,
+ public DeviceState(@IntRange(from = 0) int identifier,
@NonNull String name) {
- if (identifier != INVALID_DEVICE_STATE && identifier < 0) {
+ if (identifier < 0) {
throw new IllegalArgumentException("Identifier must be greater than or equal to zero.");
}
mIdentifier = identifier;
@@ -54,7 +52,7 @@ public final class DeviceState {
}
/** Returns the unique identifier for the device state. */
- @IntRange(from = INVALID_DEVICE_STATE)
+ @IntRange(from = 0)
public int getIdentifier() {
return mIdentifier;
}
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
index 375ec3a0f95f..984a17694e07 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -17,13 +17,13 @@
package com.android.server.devicestate;
import static android.Manifest.permission.CONTROL_DEVICE_STATE;
-import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
+import static android.hardware.devicestate.DeviceStateRequest.FLAG_CANCEL_WHEN_BASE_CHANGES;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
-import android.content.pm.PackageManager;
+import android.hardware.devicestate.DeviceStateManager;
import android.hardware.devicestate.IDeviceStateManager;
import android.hardware.devicestate.IDeviceStateManagerCallback;
import android.os.Binder;
@@ -31,6 +31,8 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ShellCallback;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
@@ -62,8 +64,12 @@ import java.util.Optional;
* the {@link DeviceStateProvider} to modify the current device state and communicating with the
* {@link DeviceStatePolicy policy} to ensure the system is configured to match the requested state.
* </p>
+ * The service also provides the {@link DeviceStateManager} API allowing clients to listen for
+ * changes in device state and submit requests to override the device state provided by the
+ * {@link DeviceStateProvider}.
*
* @see DeviceStatePolicy
+ * @see DeviceStateManager
*/
public final class DeviceStateManagerService extends SystemService {
private static final String TAG = "DeviceStateManagerService";
@@ -79,11 +85,11 @@ public final class DeviceStateManagerService extends SystemService {
@GuardedBy("mLock")
private SparseArray<DeviceState> mDeviceStates = new SparseArray<>();
- // The current committed device state. The default of INVALID_DEVICE_STATE will be replaced by
+ // The current committed device state. The default of UNSET will be replaced by
// the current state after the initial callback from the DeviceStateProvider.
@GuardedBy("mLock")
@NonNull
- private DeviceState mCommittedState = new DeviceState(INVALID_DEVICE_STATE, "INVALID");
+ private DeviceState mCommittedState = new DeviceState(0, "UNSET");
// The device state that is currently awaiting callback from the policy to be committed.
@GuardedBy("mLock")
@NonNull
@@ -91,19 +97,23 @@ public final class DeviceStateManagerService extends SystemService {
// Whether or not the policy is currently waiting to be notified of the current pending state.
@GuardedBy("mLock")
private boolean mIsPolicyWaitingForState = false;
- // The device state that is currently requested and is next to be configured and committed.
- // Can be overwritten by an override state value if requested.
- @GuardedBy("mLock")
- @NonNull
- private Optional<DeviceState> mRequestedState = Optional.empty();
- // The most recently requested override state, or empty if no override is requested.
+
+ // The device state that is set by the device state provider.
@GuardedBy("mLock")
@NonNull
- private Optional<DeviceState> mRequestedOverrideState = Optional.empty();
+ private Optional<DeviceState> mBaseState = Optional.empty();
- // List of registered callbacks indexed by process id.
+ // List of processes registered to receive notifications about changes to device state and
+ // request status indexed by process id.
@GuardedBy("mLock")
- private final SparseArray<CallbackRecord> mCallbacks = new SparseArray<>();
+ private final SparseArray<ProcessRecord> mProcessRecords = new SparseArray<>();
+ // List of override requests with the highest precedence request at the end.
+ @GuardedBy("mLock")
+ private final ArrayList<OverrideRequestRecord> mRequestRecords = new ArrayList<>();
+ // Set of override requests that are pending a call to notifyStatusIfNeeded() to be notified
+ // of a change in status.
+ @GuardedBy("mLock")
+ private final ArraySet<OverrideRequestRecord> mRequestsPendingStatusChange = new ArraySet<>();
public DeviceStateManagerService(@NonNull Context context) {
this(context, new DeviceStatePolicyImpl(context));
@@ -148,55 +158,32 @@ public final class DeviceStateManagerService extends SystemService {
}
/**
- * Returns the requested state. The service will configure the device to match the requested
- * state when possible.
- */
- @NonNull
- Optional<DeviceState> getRequestedState() {
- synchronized (mLock) {
- return mRequestedState;
- }
- }
-
- /**
- * Overrides the current device state with the provided state.
+ * Returns the base state. The service will configure the device to match the base state when
+ * there is no active request to override the base state.
*
- * @return {@code true} if the override state is valid and supported, {@code false} otherwise.
+ * @see #getOverrideState()
*/
- boolean setOverrideState(int overrideState) {
- if (getContext().checkCallingOrSelfPermission(CONTROL_DEVICE_STATE)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Must hold permission " + CONTROL_DEVICE_STATE);
- }
-
+ @NonNull
+ Optional<DeviceState> getBaseState() {
synchronized (mLock) {
- if (overrideState != INVALID_DEVICE_STATE && !isSupportedStateLocked(overrideState)) {
- return false;
- }
-
- mRequestedOverrideState = getStateLocked(overrideState);
- updatePendingStateLocked();
+ return mBaseState;
}
-
- notifyPolicyIfNeeded();
- return true;
- }
-
- /**
- * Clears an override state set with {@link #setOverrideState(int)}.
- */
- void clearOverrideState() {
- setOverrideState(INVALID_DEVICE_STATE);
}
/**
- * Returns the current requested override state, or {@link Optional#empty()} if no override
- * state is requested.
+ * Returns the current override state, or {@link Optional#empty()} if no override state is
+ * requested. If an override states is present, the returned state will take precedence over
+ * the base state returned from {@link #getBaseState()}.
*/
@NonNull
Optional<DeviceState> getOverrideState() {
synchronized (mLock) {
- return mRequestedOverrideState;
+ if (mRequestRecords.isEmpty()) {
+ return Optional.empty();
+ }
+
+ OverrideRequestRecord topRequest = mRequestRecords.get(mRequestRecords.size() - 1);
+ return Optional.of(topRequest.mRequestedState);
}
}
@@ -211,6 +198,17 @@ public final class DeviceStateManagerService extends SystemService {
}
}
+ /** Returns the list of currently supported device state identifiers. */
+ private int[] getSupportedStateIdentifiers() {
+ synchronized (mLock) {
+ int[] supportedStates = new int[mDeviceStates.size()];
+ for (int i = 0; i < supportedStates.length; i++) {
+ supportedStates[i] = mDeviceStates.valueAt(i).getIdentifier();
+ }
+ return supportedStates;
+ }
+ }
+
@VisibleForTesting
IDeviceStateManager getBinderService() {
return mBinderService;
@@ -224,22 +222,26 @@ public final class DeviceStateManagerService extends SystemService {
mDeviceStates.put(state.getIdentifier(), state);
}
- if (mRequestedState.isPresent()
- && !isSupportedStateLocked(mRequestedState.get().getIdentifier())) {
- // The current requested state is no longer valid. We'll clear it here, though
+ if (mBaseState.isPresent()
+ && !isSupportedStateLocked(mBaseState.get().getIdentifier())) {
+ // The current base state is no longer valid. We'll clear it here, though
// we won't actually update the current state until a callback comes from the
// provider with the most recent state.
- mRequestedState = Optional.empty();
+ mBaseState = Optional.empty();
}
- if (mRequestedOverrideState.isPresent()
- && !isSupportedStateLocked(mRequestedOverrideState.get().getIdentifier())) {
- // The current override state is no longer valid. We'll clear it here and update
- // the committed state if necessary.
- mRequestedOverrideState = Optional.empty();
+
+ final int requestSize = mRequestRecords.size();
+ for (int i = 0; i < requestSize; i++) {
+ OverrideRequestRecord request = mRequestRecords.get(i);
+ if (!isSupportedStateLocked(request.mRequestedState.getIdentifier())) {
+ request.setStatusLocked(OverrideRequestRecord.STATUS_CANCELED);
+ }
}
+
updatePendingStateLocked();
}
+ notifyRequestsOfStatusChangeIfNeeded();
notifyPolicyIfNeeded();
}
@@ -261,20 +263,37 @@ public final class DeviceStateManagerService extends SystemService {
}
/**
- * Requests that the system enter the provided {@code state}. The request may not be honored
- * under certain conditions, for example if the provided state is not supported.
+ * Requests to set the base state. The request may not be honored under certain conditions, for
+ * example if the provided state is not supported.
*
* @see #isSupportedStateLocked(int)
*/
- private void requestState(int identifier) {
+ private void setBaseState(int identifier) {
synchronized (mLock) {
- final Optional<DeviceState> requestedState = getStateLocked(identifier);
- if (requestedState.isPresent()) {
- mRequestedState = requestedState;
+ if (mBaseState.isPresent() && mBaseState.get().getIdentifier() == identifier) {
+ // Base state hasn't changed. Nothing to do.
+ return;
+ }
+
+ final Optional<DeviceState> baseState = getStateLocked(identifier);
+ if (!baseState.isPresent()) {
+ throw new IllegalArgumentException("Base state is not supported");
}
+
+ mBaseState = baseState;
+
+ final int requestSize = mRequestRecords.size();
+ for (int i = 0; i < requestSize; i++) {
+ OverrideRequestRecord request = mRequestRecords.get(i);
+ if ((request.mFlags & FLAG_CANCEL_WHEN_BASE_CHANGES) > 0) {
+ request.setStatusLocked(OverrideRequestRecord.STATUS_CANCELED);
+ }
+ }
+
updatePendingStateLocked();
}
+ notifyRequestsOfStatusChangeIfNeeded();
notifyPolicyIfNeeded();
}
@@ -290,10 +309,10 @@ public final class DeviceStateManagerService extends SystemService {
}
final DeviceState stateToConfigure;
- if (mRequestedOverrideState.isPresent()) {
- stateToConfigure = mRequestedOverrideState.get();
+ if (!mRequestRecords.isEmpty()) {
+ stateToConfigure = mRequestRecords.get(mRequestRecords.size() - 1).mRequestedState;
} else {
- stateToConfigure = mRequestedState.orElse(null);
+ stateToConfigure = mBaseState.orElse(null);
}
if (stateToConfigure == null) {
@@ -360,6 +379,13 @@ public final class DeviceStateManagerService extends SystemService {
}
mCommittedState = mPendingState.get();
newState = mCommittedState.getIdentifier();
+
+ if (!mRequestRecords.isEmpty()) {
+ final OverrideRequestRecord topRequest =
+ mRequestRecords.get(mRequestRecords.size() - 1);
+ topRequest.setStatusLocked(OverrideRequestRecord.STATUS_ACTIVE);
+ }
+
mPendingState = Optional.empty();
updatePendingStateLocked();
}
@@ -367,6 +393,9 @@ public final class DeviceStateManagerService extends SystemService {
// Notify callbacks of a change.
notifyDeviceStateChanged(newState);
+ // Notify the top request that it's active.
+ notifyRequestsOfStatusChangeIfNeeded();
+
// Try to configure the next state if needed.
notifyPolicyIfNeeded();
}
@@ -377,43 +406,69 @@ public final class DeviceStateManagerService extends SystemService {
"Attempting to notify callbacks with service lock held.");
}
- // Grab the lock and copy the callbacks.
- ArrayList<CallbackRecord> callbacks;
+ // Grab the lock and copy the process records.
+ ArrayList<ProcessRecord> registeredProcesses;
synchronized (mLock) {
- if (mCallbacks.size() == 0) {
+ if (mProcessRecords.size() == 0) {
return;
}
- callbacks = new ArrayList<>();
- for (int i = 0; i < mCallbacks.size(); i++) {
- callbacks.add(mCallbacks.valueAt(i));
+ registeredProcesses = new ArrayList<>();
+ for (int i = 0; i < mProcessRecords.size(); i++) {
+ registeredProcesses.add(mProcessRecords.valueAt(i));
+ }
+ }
+
+ // After releasing the lock, send the notifications out.
+ for (int i = 0; i < registeredProcesses.size(); i++) {
+ registeredProcesses.get(i).notifyDeviceStateAsync(deviceState);
+ }
+ }
+
+ /**
+ * Notifies all dirty requests (requests that have a change in status, but have not yet been
+ * notified) that their status has changed.
+ */
+ private void notifyRequestsOfStatusChangeIfNeeded() {
+ if (Thread.holdsLock(mLock)) {
+ throw new IllegalStateException(
+ "Attempting to notify requests with service lock held.");
+ }
+
+ ArraySet<OverrideRequestRecord> dirtyRequests;
+ synchronized (mLock) {
+ if (mRequestsPendingStatusChange.isEmpty()) {
+ return;
}
+
+ dirtyRequests = new ArraySet<>(mRequestsPendingStatusChange);
+ mRequestsPendingStatusChange.clear();
}
// After releasing the lock, send the notifications out.
- for (int i = 0; i < callbacks.size(); i++) {
- callbacks.get(i).notifyDeviceStateAsync(deviceState);
+ for (int i = 0; i < dirtyRequests.size(); i++) {
+ dirtyRequests.valueAt(i).notifyStatusIfNeeded();
}
}
- private void registerCallbackInternal(IDeviceStateManagerCallback callback, int callingPid) {
+ private void registerProcess(int pid, IDeviceStateManagerCallback callback) {
int currentState;
- CallbackRecord record;
+ ProcessRecord record;
// Grab the lock to register the callback and get the current state.
synchronized (mLock) {
- if (mCallbacks.contains(callingPid)) {
+ if (mProcessRecords.contains(pid)) {
throw new SecurityException("The calling process has already registered an"
+ " IDeviceStateManagerCallback.");
}
- record = new CallbackRecord(callback, callingPid);
+ record = new ProcessRecord(callback, pid);
try {
callback.asBinder().linkToDeath(record, 0);
} catch (RemoteException ex) {
throw new RuntimeException(ex);
}
- mCallbacks.put(callingPid, record);
+ mProcessRecords.put(pid, record);
currentState = mCommittedState.getIdentifier();
}
@@ -421,10 +476,86 @@ public final class DeviceStateManagerService extends SystemService {
record.notifyDeviceStateAsync(currentState);
}
- private void unregisterCallbackInternal(CallbackRecord record) {
+ private void handleProcessDied(ProcessRecord processRecord) {
+ synchronized (mLock) {
+ // Cancel all requests from this process.
+ final int requestCount = processRecord.mRequestRecords.size();
+ for (int i = 0; i < requestCount; i++) {
+ final OverrideRequestRecord request = processRecord.mRequestRecords.valueAt(i);
+ // Cancel the request but don't mark it as dirty since there's no need to send
+ // notifications if the process has died.
+ request.setStatusLocked(OverrideRequestRecord.STATUS_CANCELED,
+ false /* markDirty */);
+ }
+
+ mProcessRecords.remove(processRecord.mPid);
+
+ updatePendingStateLocked();
+ }
+
+ notifyPolicyIfNeeded();
+ }
+
+ private void requestStateInternal(int state, int flags, int callingPid,
+ @NonNull IBinder token) {
+ synchronized (mLock) {
+ final ProcessRecord processRecord = mProcessRecords.get(callingPid);
+ if (processRecord == null) {
+ throw new IllegalStateException("Process " + callingPid
+ + " has no registered callback.");
+ }
+
+ if (processRecord.mRequestRecords.get(token) != null) {
+ throw new IllegalStateException("Request has already been made for the supplied"
+ + " token: " + token);
+ }
+
+ final Optional<DeviceState> deviceState = getStateLocked(state);
+ if (!deviceState.isPresent()) {
+ throw new IllegalArgumentException("Requested state: " + state
+ + " is not supported.");
+ }
+
+ OverrideRequestRecord topRecord = mRequestRecords.isEmpty()
+ ? null : mRequestRecords.get(mRequestRecords.size() - 1);
+ if (topRecord != null) {
+ topRecord.setStatusLocked(OverrideRequestRecord.STATUS_SUSPENDED);
+ }
+
+ final OverrideRequestRecord request =
+ new OverrideRequestRecord(processRecord, token, deviceState.get(), flags);
+ mRequestRecords.add(request);
+ processRecord.mRequestRecords.put(request.mToken, request);
+ // We don't set the status of the new request to ACTIVE here as it will be set in
+ // commitPendingState().
+
+ updatePendingStateLocked();
+ }
+
+ notifyRequestsOfStatusChangeIfNeeded();
+ notifyPolicyIfNeeded();
+ }
+
+ private void cancelRequestInternal(int callingPid, @NonNull IBinder token) {
synchronized (mLock) {
- mCallbacks.remove(record.mPid);
+ final ProcessRecord processRecord = mProcessRecords.get(callingPid);
+ if (processRecord == null) {
+ throw new IllegalStateException("Process " + callingPid
+ + " has no registered callback.");
+ }
+
+ OverrideRequestRecord request = processRecord.mRequestRecords.get(token);
+ if (request == null) {
+ throw new IllegalStateException("No known request for the given token");
+ }
+
+ request.setStatusLocked(OverrideRequestRecord.STATUS_CANCELED);
+
+ updatePendingStateLocked();
}
+
+ notifyRequestsOfStatusChangeIfNeeded();
+ notifyPolicyIfNeeded();
}
private void dumpInternal(PrintWriter pw) {
@@ -433,15 +564,26 @@ public final class DeviceStateManagerService extends SystemService {
synchronized (mLock) {
pw.println(" mCommittedState=" + mCommittedState);
pw.println(" mPendingState=" + mPendingState);
- pw.println(" mRequestedState=" + mRequestedState);
- pw.println(" mRequestedOverrideState=" + mRequestedOverrideState);
+ pw.println(" mBaseState=" + mBaseState);
+ pw.println(" mOverrideState=" + getOverrideState());
- final int callbackCount = mCallbacks.size();
+ final int processCount = mProcessRecords.size();
pw.println();
- pw.println("Callbacks: size=" + callbackCount);
- for (int i = 0; i < callbackCount; i++) {
- CallbackRecord callback = mCallbacks.valueAt(i);
- pw.println(" " + i + ": mPid=" + callback.mPid);
+ pw.println("Registered processes: size=" + processCount);
+ for (int i = 0; i < processCount; i++) {
+ ProcessRecord processRecord = mProcessRecords.valueAt(i);
+ pw.println(" " + i + ": mPid=" + processRecord.mPid);
+ }
+
+ final int requestCount = mRequestRecords.size();
+ pw.println();
+ pw.println("Override requests: size=" + requestCount);
+ for (int i = 0; i < requestCount; i++) {
+ OverrideRequestRecord requestRecord = mRequestRecords.get(i);
+ pw.println(" " + i + ": mPid=" + requestRecord.mProcessRecord.mPid
+ + ", mRequestedState=" + requestRecord.mRequestedState
+ + ", mFlags=" + requestRecord.mFlags
+ + ", mStatus=" + requestRecord.statusToString(requestRecord.mStatus));
}
}
}
@@ -452,12 +594,6 @@ public final class DeviceStateManagerService extends SystemService {
if (newDeviceStates.length == 0) {
throw new IllegalArgumentException("Supported device states must not be empty");
}
- for (int i = 0; i < newDeviceStates.length; i++) {
- if (newDeviceStates[i].getIdentifier() == INVALID_DEVICE_STATE) {
- throw new IllegalArgumentException(
- "Supported device states includes INVALID_DEVICE_STATE identifier");
- }
- }
updateSupportedStates(newDeviceStates);
}
@@ -467,22 +603,24 @@ public final class DeviceStateManagerService extends SystemService {
throw new IllegalArgumentException("Invalid identifier: " + identifier);
}
- requestState(identifier);
+ setBaseState(identifier);
}
}
- private final class CallbackRecord implements IBinder.DeathRecipient {
+ private final class ProcessRecord implements IBinder.DeathRecipient {
private final IDeviceStateManagerCallback mCallback;
private final int mPid;
- CallbackRecord(IDeviceStateManagerCallback callback, int pid) {
+ private final ArrayMap<IBinder, OverrideRequestRecord> mRequestRecords = new ArrayMap<>();
+
+ ProcessRecord(IDeviceStateManagerCallback callback, int pid) {
mCallback = callback;
mPid = pid;
}
@Override
public void binderDied() {
- unregisterCallbackInternal(this);
+ handleProcessDied(this);
}
public void notifyDeviceStateAsync(int devicestate) {
@@ -493,6 +631,119 @@ public final class DeviceStateManagerService extends SystemService {
ex);
}
}
+
+ public void notifyRequestActiveAsync(OverrideRequestRecord request) {
+ try {
+ mCallback.onRequestActive(request.mToken);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to notify process " + mPid + " that request state changed.",
+ ex);
+ }
+ }
+
+ public void notifyRequestSuspendedAsync(OverrideRequestRecord request) {
+ try {
+ mCallback.onRequestSuspended(request.mToken);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to notify process " + mPid + " that request state changed.",
+ ex);
+ }
+ }
+
+ public void notifyRequestCanceledAsync(OverrideRequestRecord request) {
+ try {
+ mCallback.onRequestCanceled(request.mToken);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Failed to notify process " + mPid + " that request state changed.",
+ ex);
+ }
+ }
+ }
+
+ /** A record describing a request to override the state of the device. */
+ private final class OverrideRequestRecord {
+ public static final int STATUS_UNKNOWN = 0;
+ public static final int STATUS_ACTIVE = 1;
+ public static final int STATUS_SUSPENDED = 2;
+ public static final int STATUS_CANCELED = 3;
+
+ @Nullable
+ public String statusToString(int status) {
+ switch (status) {
+ case STATUS_ACTIVE:
+ return "ACTIVE";
+ case STATUS_SUSPENDED:
+ return "SUSPENDED";
+ case STATUS_CANCELED:
+ return "CANCELED";
+ case STATUS_UNKNOWN:
+ return "UNKNOWN";
+ default:
+ return null;
+ }
+ }
+
+ private final ProcessRecord mProcessRecord;
+ @NonNull
+ private final IBinder mToken;
+ @NonNull
+ private final DeviceState mRequestedState;
+ private final int mFlags;
+
+ private int mStatus = STATUS_UNKNOWN;
+ private int mLastNotifiedStatus = STATUS_UNKNOWN;
+
+ OverrideRequestRecord(@NonNull ProcessRecord processRecord, @NonNull IBinder token,
+ @NonNull DeviceState requestedState, int flags) {
+ mProcessRecord = processRecord;
+ mToken = token;
+ mRequestedState = requestedState;
+ mFlags = flags;
+ }
+
+ public void setStatusLocked(int status) {
+ setStatusLocked(status, true /* markDirty */);
+ }
+
+ public void setStatusLocked(int status, boolean markDirty) {
+ if (mStatus != status) {
+ if (mStatus == STATUS_CANCELED) {
+ throw new IllegalStateException(
+ "Can not alter the status of a request after set to CANCELED.");
+ }
+
+ mStatus = status;
+
+ if (mStatus == STATUS_CANCELED) {
+ mRequestRecords.remove(this);
+ mProcessRecord.mRequestRecords.remove(mToken);
+ }
+
+ if (markDirty) {
+ mRequestsPendingStatusChange.add(this);
+ }
+ }
+ }
+
+ public void notifyStatusIfNeeded() {
+ int stateToReport;
+ synchronized (mLock) {
+ if (mLastNotifiedStatus == mStatus) {
+ return;
+ }
+
+ stateToReport = mStatus;
+ mLastNotifiedStatus = mStatus;
+ }
+
+ if (stateToReport == STATUS_ACTIVE) {
+ mProcessRecord.notifyRequestActiveAsync(this);
+ } else if (stateToReport == STATUS_SUSPENDED) {
+ mProcessRecord.notifyRequestSuspendedAsync(this);
+ } else if (stateToReport == STATUS_CANCELED) {
+ mProcessRecord.notifyRequestCanceledAsync(this);
+ }
+ }
}
/** Implementation of {@link IDeviceStateManager} published as a binder service. */
@@ -506,13 +757,59 @@ public final class DeviceStateManagerService extends SystemService {
final int callingPid = Binder.getCallingPid();
final long token = Binder.clearCallingIdentity();
try {
- registerCallbackInternal(callback, callingPid);
+ registerProcess(callingPid, callback);
} finally {
Binder.restoreCallingIdentity(token);
}
}
@Override // Binder call
+ public int[] getSupportedDeviceStates() {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return getSupportedStateIdentifiers();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override // Binder call
+ public void requestState(IBinder token, int state, int flags) {
+ getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE,
+ "Permission required to request device state.");
+
+ if (token == null) {
+ throw new IllegalArgumentException("Request token must not be null.");
+ }
+
+ final int callingPid = Binder.getCallingPid();
+ final long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ requestStateInternal(state, flags, callingPid, token);
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ }
+
+ @Override // Binder call
+ public void cancelRequest(IBinder token) {
+ getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE,
+ "Permission required to clear requested device state.");
+
+ if (token == null) {
+ throw new IllegalArgumentException("Request token must not be null.");
+ }
+
+ final int callingPid = Binder.getCallingPid();
+ final long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ cancelRequestInternal(callingPid, token);
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ }
+
+ @Override // Binder call
public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
String[] args, ShellCallback callback, ResultReceiver result) {
new DeviceStateManagerShellCommand(DeviceStateManagerService.this)
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
index 7914531f9910..6cc55a6c4774 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerShellCommand.java
@@ -16,6 +16,13 @@
package com.android.server.devicestate;
+import static android.Manifest.permission.CONTROL_DEVICE_STATE;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.hardware.devicestate.DeviceStateManager;
+import android.hardware.devicestate.DeviceStateRequest;
+import android.os.Binder;
import android.os.ShellCommand;
import java.io.PrintWriter;
@@ -27,10 +34,15 @@ import java.util.Optional;
* Use with {@code adb shell cmd device_state ...}.
*/
public class DeviceStateManagerShellCommand extends ShellCommand {
- private final DeviceStateManagerService mInternal;
+ @Nullable
+ private static DeviceStateRequest sLastRequest;
+
+ private final DeviceStateManagerService mService;
+ private final DeviceStateManager mClient;
public DeviceStateManagerShellCommand(DeviceStateManagerService service) {
- mInternal = service;
+ mService = service;
+ mClient = service.getContext().getSystemService(DeviceStateManager.class);
}
@Override
@@ -51,15 +63,15 @@ public class DeviceStateManagerShellCommand extends ShellCommand {
}
private void printState(PrintWriter pw) {
- DeviceState committedState = mInternal.getCommittedState();
- Optional<DeviceState> requestedState = mInternal.getRequestedState();
- Optional<DeviceState> requestedOverrideState = mInternal.getOverrideState();
+ DeviceState committedState = mService.getCommittedState();
+ Optional<DeviceState> baseState = mService.getBaseState();
+ Optional<DeviceState> overrideState = mService.getOverrideState();
pw.println("Committed state: " + committedState);
- if (requestedOverrideState.isPresent()) {
+ if (overrideState.isPresent()) {
pw.println("----------------------");
- pw.println("Base state: " + requestedState.orElse(null));
- pw.println("Override state: " + requestedOverrideState.get());
+ pw.println("Base state: " + baseState.orElse(null));
+ pw.println("Override state: " + overrideState.get());
}
}
@@ -67,32 +79,51 @@ public class DeviceStateManagerShellCommand extends ShellCommand {
final String nextArg = getNextArg();
if (nextArg == null) {
printState(pw);
- } else if ("reset".equals(nextArg)) {
- mInternal.clearOverrideState();
- } else {
- int requestedState;
- try {
- requestedState = Integer.parseInt(nextArg);
- } catch (NumberFormatException e) {
- getErrPrintWriter().println("Error: requested state should be an integer");
- return -1;
- }
+ }
- boolean success = mInternal.setOverrideState(requestedState);
- if (!success) {
- getErrPrintWriter().println("Error: failed to set override state. Run:");
- getErrPrintWriter().println("");
- getErrPrintWriter().println(" print-states");
- getErrPrintWriter().println("");
- getErrPrintWriter().println("to get the list of currently supported device states");
- return -1;
+ final Context context = mService.getContext();
+ context.enforceCallingOrSelfPermission(
+ CONTROL_DEVICE_STATE,
+ "Permission required to request device state.");
+ final long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ if ("reset".equals(nextArg)) {
+ if (sLastRequest != null) {
+ mClient.cancelRequest(sLastRequest);
+ sLastRequest = null;
+ }
+ } else {
+ int requestedState = Integer.parseInt(nextArg);
+ DeviceStateRequest request = DeviceStateRequest.newBuilder(requestedState).build();
+
+ mClient.requestState(request, null /* executor */, null /* callback */);
+ if (sLastRequest != null) {
+ mClient.cancelRequest(sLastRequest);
+ }
+
+ sLastRequest = request;
}
+ } catch (NumberFormatException e) {
+ getErrPrintWriter().println("Error: requested state should be an integer");
+ return -1;
+ } catch (IllegalArgumentException e) {
+ getErrPrintWriter().println("Error: " + e.getMessage());
+ getErrPrintWriter().println("-------------------");
+ getErrPrintWriter().println("Run:");
+ getErrPrintWriter().println("");
+ getErrPrintWriter().println(" print-states");
+ getErrPrintWriter().println("");
+ getErrPrintWriter().println("to get the list of currently supported device states");
+ return -1;
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
}
+
return 0;
}
private int runPrintStates(PrintWriter pw) {
- DeviceState[] states = mInternal.getSupportedStates();
+ DeviceState[] states = mService.getSupportedStates();
pw.print("Supported states: [\n");
for (int i = 0; i < states.length; i++) {
pw.print(" " + states[i] + ",\n");
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index e5151d84c33e..0950d5dd076f 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -514,8 +514,8 @@ public final class DisplayManagerService extends SystemService {
DeviceStateManager deviceStateManager =
mContext.getSystemService(DeviceStateManager.class);
- deviceStateManager.registerDeviceStateListener(new DeviceStateListener(),
- new HandlerExecutor(mHandler));
+ deviceStateManager.addDeviceStateListener(new HandlerExecutor(mHandler),
+ new DeviceStateListener());
scheduleTraversalLocked(false);
}
diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
index 3e2b5ab795be..1b27572ad8de 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
@@ -345,6 +345,7 @@ public final class FontManagerService extends IFontManager.Stub {
synchronized (mSerializedFontMapLock) {
mSerializedFontMap = serializeFontMap;
}
+ return;
} catch (IOException | ErrnoException e) {
Slog.w(TAG, "Failed to serialize updatable font map. "
+ "Retrying with system image fonts.", e);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index d8e124a00104..1a4c8b7d6571 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2546,7 +2546,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
+ mCurTokenDisplayId);
}
mIWindowManager.addWindowToken(mCurToken, LayoutParams.TYPE_INPUT_METHOD,
- mCurTokenDisplayId);
+ mCurTokenDisplayId, null /* options */);
} catch (RemoteException e) {
}
return new InputBindResult(
@@ -5227,6 +5227,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+
boolean asProto = false;
for (int argIndex = 0; argIndex < args.length; argIndex++) {
if (args[argIndex].equals(PROTO_ARG)) {
@@ -5249,8 +5251,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
private void doDump(FileDescriptor fd, PrintWriter pw, String[] args, boolean useProto) {
- if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
-
if (useProto) {
final ProtoOutputStream proto = new ProtoOutputStream(fd);
dumpDebug(proto, InputMethodManagerServiceTraceProto.INPUT_METHOD_MANAGER_SERVICE);
diff --git a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
index 6fec9063ba94..1dd3d4190e8a 100644
--- a/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/MultiClientInputMethodManagerService.java
@@ -1309,7 +1309,8 @@ public final class MultiClientInputMethodManagerService {
final Binder token = new Binder();
Binder.withCleanCallingIdentity(
PooledLambda.obtainRunnable(WindowManagerInternal::addWindowToken,
- mIWindowManagerInternal, token, TYPE_INPUT_METHOD, displayId));
+ mIWindowManagerInternal, token, TYPE_INPUT_METHOD, displayId,
+ null /* options */));
mPerUserData.mDisplayIdToImeWindowTokenMap.add(new TokenInfo(token, displayId));
return token;
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6843733eea9f..571b6934e425 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3041,7 +3041,8 @@ public class NotificationManagerService extends SystemService {
}
Binder windowToken = new Binder();
- mWindowManagerInternal.addWindowToken(windowToken, TYPE_TOAST, displayId);
+ mWindowManagerInternal.addWindowToken(windowToken, TYPE_TOAST, displayId,
+ null /* options */);
record = getToastRecord(callingUid, callingPid, pkg, isSystemToast, token,
text, callback, duration, windowToken, displayId, textCallback);
mToastQueue.add(record);
diff --git a/services/core/java/com/android/server/pm/DefaultAppProvider.java b/services/core/java/com/android/server/pm/DefaultAppProvider.java
index a17967fcc76e..c18d0e9ef35e 100644
--- a/services/core/java/com/android/server/pm/DefaultAppProvider.java
+++ b/services/core/java/com/android/server/pm/DefaultAppProvider.java
@@ -41,14 +41,18 @@ import java.util.function.Supplier;
public class DefaultAppProvider {
@NonNull
private final Supplier<RoleManager> mRoleManagerSupplier;
+ @NonNull
+ private final Supplier<UserManagerInternal> mUserManagerInternalSupplier;
/**
* Create a new instance of this class
*
* @param roleManagerSupplier the supplier for {@link RoleManager}
*/
- public DefaultAppProvider(@NonNull Supplier<RoleManager> roleManagerSupplier) {
+ public DefaultAppProvider(@NonNull Supplier<RoleManager> roleManagerSupplier,
+ @NonNull Supplier<UserManagerInternal> userManagerInternalSupplier) {
mRoleManagerSupplier = roleManagerSupplier;
+ mUserManagerInternalSupplier = userManagerInternalSupplier;
}
/**
@@ -132,7 +136,8 @@ public class DefaultAppProvider {
*/
@Nullable
public String getDefaultHome(@NonNull int userId) {
- return getRoleHolder(RoleManager.ROLE_HOME, userId);
+ return getRoleHolder(RoleManager.ROLE_HOME,
+ mUserManagerInternalSupplier.get().getProfileParentId(userId));
}
/**
diff --git a/services/core/java/com/android/server/pm/IncrementalStates.java b/services/core/java/com/android/server/pm/IncrementalStates.java
index f5ec595cc45a..ecafdfdbd6f1 100644
--- a/services/core/java/com/android/server/pm/IncrementalStates.java
+++ b/services/core/java/com/android/server/pm/IncrementalStates.java
@@ -249,24 +249,6 @@ public final class IncrementalStates {
}
/**
- * @return the current startable state.
- */
- public boolean isStartable() {
- synchronized (mLock) {
- return mStartableState.isStartable();
- }
- }
-
- /**
- * @return Whether the package is still being loaded or has been fully loaded.
- */
- public boolean isLoading() {
- synchronized (mLock) {
- return mLoadingState.isLoading();
- }
- }
-
- /**
* @return all current states in a Parcelable.
*/
public IncrementalStatesInfo getIncrementalStatesInfo() {
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index c4a23f961072..f240d85572c4 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -1316,10 +1316,6 @@ public class LauncherAppsService extends SystemService {
} finally {
mListeners.finishBroadcast();
}
- PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
- pmi.registerInstalledLoadingProgressCallback(packageName,
- new PackageLoadingProgressCallback(packageName, user),
- user.getIdentifier());
super.onPackageAdded(packageName, uid);
}
@@ -1542,38 +1538,5 @@ public class LauncherAppsService extends SystemService {
checkCallbackCount();
}
}
-
- class PackageLoadingProgressCallback extends
- PackageManagerInternal.InstalledLoadingProgressCallback {
- private String mPackageName;
- private UserHandle mUser;
-
- PackageLoadingProgressCallback(String packageName, UserHandle user) {
- super(mCallbackHandler);
- mPackageName = packageName;
- mUser = user;
- }
-
- @Override
- public void onLoadingProgressChanged(float progress) {
- final int n = mListeners.beginBroadcast();
- try {
- for (int i = 0; i < n; i++) {
- IOnAppsChangedListener listener = mListeners.getBroadcastItem(i);
- BroadcastCookie cookie = (BroadcastCookie) mListeners.getBroadcastCookie(i);
- if (!isEnabledProfileOf(cookie.user, mUser, "onLoadingProgressChanged")) {
- continue;
- }
- try {
- listener.onPackageLoadingProgressChanged(mUser, mPackageName, progress);
- } catch (RemoteException re) {
- Slog.d(TAG, "Callback failed ", re);
- }
- }
- } finally {
- mListeners.finishBroadcast();
- }
- }
- }
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 498c314cbc68..81b65b294456 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -24,7 +24,6 @@ import static android.Manifest.permission.SET_HARMFUL_APP_WARNINGS;
import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.content.Intent.ACTION_MAIN;
-import static android.content.Intent.CATEGORY_BROWSABLE;
import static android.content.Intent.CATEGORY_DEFAULT;
import static android.content.Intent.CATEGORY_HOME;
import static android.content.Intent.EXTRA_LONG_VERSION_CODE;
@@ -68,11 +67,7 @@ import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_RESTORE;
import static android.content.pm.PackageManager.INSTALL_REASON_DEVICE_SETUP;
import static android.content.pm.PackageManager.INSTALL_STAGED;
import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
import static android.content.pm.PackageManager.MATCH_ALL;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.content.pm.PackageManager.MATCH_APEX;
@@ -378,11 +373,6 @@ import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.PackageDexUsage;
import com.android.server.pm.dex.ViewCompiler;
-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.pm.verify.domain.proxy.DomainVerificationProxyV2;
import com.android.server.pm.parsing.PackageCacher;
import com.android.server.pm.parsing.PackageInfoUtils;
import com.android.server.pm.parsing.PackageParser2;
@@ -396,6 +386,11 @@ import com.android.server.pm.permission.LegacyPermissionManagerService;
import com.android.server.pm.permission.Permission;
import com.android.server.pm.permission.PermissionManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
+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.pm.verify.domain.proxy.DomainVerificationProxyV2;
import com.android.server.rollback.RollbackManagerInternal;
import com.android.server.security.VerityUtils;
import com.android.server.storage.DeviceStorageMonitorInternal;
@@ -405,7 +400,6 @@ import com.android.server.utils.Watchable;
import com.android.server.utils.Watched;
import com.android.server.utils.WatchedArrayMap;
import com.android.server.utils.WatchedSparseBooleanArray;
-import com.android.server.utils.WatchedSparseIntArray;
import com.android.server.utils.Watcher;
import com.android.server.wm.ActivityTaskManagerInternal;
@@ -467,7 +461,6 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Predicate;
-import java.util.function.Supplier;
/**
* Keep track of all those APKs everywhere.
@@ -3623,8 +3616,6 @@ public class PackageManagerService extends IPackageManager.Stub
final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
final int userId = UserHandle.getUserId(uid);
final int appId = UserHandle.getAppId(uid);
- enforceCrossUserPermission(callingUid, userId,
- /* requireFullPermission */ false, /* checkShell */ false, "getPackagesForUid");
return getPackagesForUidInternalBody(callingUid, userId, appId, isCallerInstantApp);
}
@@ -5770,8 +5761,8 @@ public class PackageManagerService extends IPackageManager.Stub
(i, pm) -> new ViewCompiler(i.getInstallLock(), i.getInstaller()),
(i, pm) -> (IncrementalManager)
i.getContext().getSystemService(Context.INCREMENTAL_SERVICE),
- (i, pm) -> new DefaultAppProvider(() -> context.getSystemService(
- RoleManager.class)),
+ (i, pm) -> new DefaultAppProvider(() -> context.getSystemService(RoleManager.class),
+ () -> LocalServices.getService(UserManagerInternal.class)),
(i, pm) -> new DisplayMetrics(),
(i, pm) -> new PackageParser2(pm.mSeparateProcesses, pm.mOnlyCore,
i.getDisplayMetrics(), pm.mCacheDir,
@@ -8949,6 +8940,7 @@ public class PackageManagerService extends IPackageManager.Stub
@Override
public List<String> getAllPackages() {
+ enforceSystemOrRootOrShell("getAllPackages is limited to privileged callers");
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
synchronized (mLock) {
@@ -19169,6 +19161,8 @@ public class PackageManagerService extends IPackageManager.Stub
extras, 0 /*flags*/,
null /*targetPackage*/, null /*finishedReceiver*/,
mInstalledUserIds, null /* instantUserIds */, newBroadcastAllowList, null);
+ // Unregister progress listener
+ mIncrementalManager.unregisterLoadingProgressCallbacks(codePath);
// Unregister health listener as it will always be healthy from now
mIncrementalManager.unregisterHealthListener(codePath);
}
@@ -27046,47 +27040,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
- public boolean registerInstalledLoadingProgressCallback(String packageName,
- PackageManagerInternal.InstalledLoadingProgressCallback callback, int userId) {
- final PackageSetting ps = getPackageSettingForUser(packageName, Binder.getCallingUid(),
- userId);
- if (ps == null) {
- return false;
- }
- if (!ps.isPackageLoading()) {
- Slog.w(TAG,
- "Failed registering loading progress callback. Package is fully loaded.");
- return false;
- }
- if (mIncrementalManager == null) {
- Slog.w(TAG,
- "Failed registering loading progress callback. Incremental is not enabled");
- return false;
- }
- return mIncrementalManager.registerLoadingProgressCallback(ps.getPathString(),
- (IPackageLoadingProgressCallback) callback.getBinder());
- }
-
- @Override
- public boolean unregisterInstalledLoadingProgressCallback(String packageName,
- PackageManagerInternal.InstalledLoadingProgressCallback callback) {
- final PackageSetting ps;
- synchronized (mLock) {
- ps = mSettings.getPackageLPr(packageName);
- if (ps == null) {
- Slog.w(TAG, "Failed unregistering loading progress callback. Package "
- + packageName + " is not installed");
- return false;
- }
- }
- if (mIncrementalManager == null) {
- return false;
- }
- return mIncrementalManager.unregisterLoadingProgressCallback(ps.getPathString(),
- (IPackageLoadingProgressCallback) callback.getBinder());
- }
-
- @Override
public IncrementalStatesInfo getIncrementalStatesInfo(
@NonNull String packageName, int filterCallingUid, int userId) {
final PackageSetting ps = getPackageSettingForUser(packageName, filterCallingUid,
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 69e84b536004..ca5d2b49b99d 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -344,8 +344,8 @@ public class PackageSetting extends PackageSettingBase {
installSource.originatingPackageName);
proto.end(sourceToken);
}
- proto.write(PackageProto.StatesProto.IS_STARTABLE, incrementalStates.isStartable());
- proto.write(PackageProto.StatesProto.IS_LOADING, incrementalStates.isLoading());
+ proto.write(PackageProto.StatesProto.IS_STARTABLE, isPackageStartable());
+ proto.write(PackageProto.StatesProto.IS_LOADING, isPackageLoading());
writeUsersInfoToProto(proto, PackageProto.USERS);
writePackageUserPermissionsProto(proto, PackageProto.USER_PERMISSIONS, users, dataProvider);
proto.end(packageToken);
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 8aa553d68b98..3a142837e063 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -26,8 +26,6 @@ import android.annotation.UserIdInt;
import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
import android.content.pm.IncrementalStatesInfo;
-import android.content.pm.IntentFilterVerificationInfo;
-import android.content.pm.PackageManager;
import android.content.pm.PackageManager.UninstallReason;
import android.content.pm.PackageParser;
import android.content.pm.PackageUserState;
@@ -42,8 +40,6 @@ import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
-import com.android.server.pm.verify.domain.DomainVerificationService;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.io.File;
@@ -731,14 +727,14 @@ public abstract class PackageSettingBase extends SettingBase {
* @return True if package is startable, false otherwise.
*/
public boolean isPackageStartable() {
- return incrementalStates.isStartable();
+ return getIncrementalStates().isStartable();
}
/**
* @return True if package is still being loaded, false if the package is fully loaded.
*/
public boolean isPackageLoading() {
- return incrementalStates.isLoading();
+ return getIncrementalStates().isLoading();
}
/**
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 89729b585b14..9b092c000172 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -1535,6 +1535,27 @@ class ShortcutPackage extends ShortcutPackageItem {
pw.println(")");
}
+ public void dumpShortcuts(@NonNull PrintWriter pw, int matchFlags) {
+ final boolean matchDynamic = (matchFlags & ShortcutManager.FLAG_MATCH_DYNAMIC) != 0;
+ final boolean matchPinned = (matchFlags & ShortcutManager.FLAG_MATCH_PINNED) != 0;
+ final boolean matchManifest = (matchFlags & ShortcutManager.FLAG_MATCH_MANIFEST) != 0;
+ final boolean matchCached = (matchFlags & ShortcutManager.FLAG_MATCH_CACHED) != 0;
+
+ final int shortcutFlags = (matchDynamic ? ShortcutInfo.FLAG_DYNAMIC : 0)
+ | (matchPinned ? ShortcutInfo.FLAG_PINNED : 0)
+ | (matchManifest ? ShortcutInfo.FLAG_MANIFEST : 0)
+ | (matchCached ? ShortcutInfo.FLAG_CACHED_ALL : 0);
+
+ final ArrayMap<String, ShortcutInfo> shortcuts = mShortcuts;
+ final int size = shortcuts.size();
+ for (int i = 0; i < size; i++) {
+ final ShortcutInfo si = shortcuts.valueAt(i);
+ if ((si.getFlags() & shortcutFlags) != 0) {
+ pw.println(si.toDumpString(""));
+ }
+ }
+ }
+
@Override
public JSONObject dumpCheckin(boolean clear) throws JSONException {
final JSONObject result = super.dumpCheckin(clear);
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 3c4457db6cf0..863e3fe5c6a3 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -40,6 +40,7 @@ import android.content.IntentSender.SendIntentException;
import android.content.LocusId;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
import android.content.pm.IPackageManager;
import android.content.pm.IShortcutService;
import android.content.pm.LauncherApps;
@@ -4556,6 +4557,10 @@ public class ShortcutService extends IShortcutService.Stub {
private int mUserId = UserHandle.USER_SYSTEM;
+ private int mShortcutMatchFlags = ShortcutManager.FLAG_MATCH_CACHED
+ | ShortcutManager.FLAG_MATCH_DYNAMIC | ShortcutManager.FLAG_MATCH_MANIFEST
+ | ShortcutManager.FLAG_MATCH_PINNED;
+
private void parseOptionsLocked(boolean takeUser)
throws CommandException {
String opt;
@@ -4571,6 +4576,9 @@ public class ShortcutService extends IShortcutService.Stub {
break;
}
// fallthrough
+ case "--flags":
+ mShortcutMatchFlags = Integer.parseInt(getNextArgRequired());
+ break;
default:
throw new CommandException("Unknown option: " + opt);
}
@@ -4606,9 +4614,15 @@ public class ShortcutService extends IShortcutService.Stub {
case "clear-shortcuts":
handleClearShortcuts();
break;
+ case "get-shortcuts":
+ handleGetShortcuts();
+ break;
case "verify-states": // hidden command to verify various internal states.
handleVerifyStates();
break;
+ case "has-shortcut-access":
+ handleHasShortcutAccess();
+ break;
default:
return handleDefaultCommands(cmd);
}
@@ -4640,7 +4654,7 @@ public class ShortcutService extends IShortcutService.Stub {
pw.println("[Deprecated] cmd shortcut get-default-launcher [--user USER_ID]");
pw.println(" Show the default launcher");
pw.println(" Note: This command is deprecated. Callers should query the default"
- + " launcher directly from RoleManager instead.");
+ + " launcher from RoleManager instead.");
pw.println();
pw.println("cmd shortcut unload-user [--user USER_ID]");
pw.println(" Unload a user from the memory");
@@ -4649,6 +4663,13 @@ public class ShortcutService extends IShortcutService.Stub {
pw.println("cmd shortcut clear-shortcuts [--user USER_ID] PACKAGE");
pw.println(" Remove all shortcuts from a package, including pinned shortcuts");
pw.println();
+ pw.println("cmd shortcut get-shortcuts [--user USER_ID] [--flags FLAGS] PACKAGE");
+ pw.println(" Show the shortcuts for a package that match the given flags");
+ pw.println();
+ pw.println("cmd shortcut has-shortcut-access [--user USER_ID] PACKAGE");
+ pw.println(" Prints \"true\" if the package can access shortcuts,"
+ + " \"false\" otherwise");
+ pw.println();
}
private void handleResetThrottling() throws CommandException {
@@ -4693,11 +4714,24 @@ public class ShortcutService extends IShortcutService.Stub {
private void handleGetDefaultLauncher() throws CommandException {
synchronized (mLock) {
parseOptionsLocked(/* takeUser =*/ true);
+
+ final String defaultLauncher = getDefaultLauncher(mUserId);
+ if (defaultLauncher == null) {
+ throw new CommandException(
+ "Failed to get the default launcher for user " + mUserId);
+ }
+
+ // Get the class name of the component from PM to keep the old behaviour.
final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
- // Default launcher from package manager.
- final ComponentName defaultLauncher = mPackageManagerInternal
- .getHomeActivitiesAsUser(allHomeCandidates, getParentOrSelfUserId(mUserId));
- getOutPrintWriter().println("Launcher: " + defaultLauncher);
+ mPackageManagerInternal.getHomeActivitiesAsUser(allHomeCandidates,
+ getParentOrSelfUserId(mUserId));
+ for (ResolveInfo ri : allHomeCandidates) {
+ final ComponentInfo ci = ri.getComponentInfo();
+ if (ci.packageName.equals(defaultLauncher)) {
+ getOutPrintWriter().println("Launcher: " + ci.getComponentName());
+ break;
+ }
+ }
}
}
@@ -4723,6 +4757,24 @@ public class ShortcutService extends IShortcutService.Stub {
}
}
+ private void handleGetShortcuts() throws CommandException {
+ synchronized (mLock) {
+ parseOptionsLocked(/* takeUser =*/ true);
+ final String packageName = getNextArgRequired();
+
+ Slog.i(TAG, "cmd: handleGetShortcuts: user=" + mUserId + ", flags="
+ + mShortcutMatchFlags + ", package=" + packageName);
+
+ final ShortcutUser user = ShortcutService.this.getUserShortcutsLocked(mUserId);
+ final ShortcutPackage p = user.getPackageShortcutsIfExists(packageName);
+ if (p == null) {
+ return;
+ }
+
+ p.dumpShortcuts(getOutPrintWriter(), mShortcutMatchFlags);
+ }
+ }
+
private void handleVerifyStates() throws CommandException {
try {
verifyStatesForce(); // This will throw when there's an issue.
@@ -4730,6 +4782,16 @@ public class ShortcutService extends IShortcutService.Stub {
throw new CommandException(th.getMessage() + "\n" + Log.getStackTraceString(th));
}
}
+
+ private void handleHasShortcutAccess() throws CommandException {
+ synchronized (mLock) {
+ parseOptionsLocked(/* takeUser =*/ true);
+ final String packageName = getNextArgRequired();
+
+ boolean shortcutAccess = hasShortcutHostPermissionInner(packageName, mUserId);
+ getOutPrintWriter().println(Boolean.toString(shortcutAccess));
+ }
+ }
}
// === Unit test support ===
diff --git a/services/core/java/com/android/server/policy/DisplayFoldController.java b/services/core/java/com/android/server/policy/DisplayFoldController.java
index c10e828d8c3d..82fc22c51afc 100644
--- a/services/core/java/com/android/server/policy/DisplayFoldController.java
+++ b/services/core/java/com/android/server/policy/DisplayFoldController.java
@@ -74,8 +74,8 @@ class DisplayFoldController {
mHandler = handler;
DeviceStateManager deviceStateManager = context.getSystemService(DeviceStateManager.class);
- deviceStateManager.registerDeviceStateListener(new DeviceStateListener(context),
- new HandlerExecutor(handler));
+ deviceStateManager.addDeviceStateListener(new HandlerExecutor(handler),
+ new DeviceStateListener(context));
}
void finishedGoingToSleep() {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index c77e266ee11a..db33e750d803 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -417,8 +417,7 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
WindowManagerFuncs windowManagerFuncs);
/**
- * Check permissions when adding a window or a window token from
- * {@link android.app.WindowContext}.
+ * Check permissions when adding a window.
*
* @param type The window type
* @param isRoundedCornerOverlay {@code true} to indicate the adding window is
@@ -431,7 +430,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
* else an error code, usually
* {@link WindowManagerGlobal#ADD_PERMISSION_DENIED}, to abort the add.
*
- * @see IWindowManager#addWindowTokenWithOptions(IBinder, int, int, Bundle, String)
* @see WindowManager.LayoutParams#PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY
*/
int checkAddPermission(int type, boolean isRoundedCornerOverlay, String packageName,
diff --git a/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java b/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java
index 57e39b6c6829..b995b19c5841 100644
--- a/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java
+++ b/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java
@@ -45,6 +45,8 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.infra.ServiceConnector;
+import java.lang.ref.WeakReference;
+
/** Manages the connection to the remote rotation resolver service. */
class RemoteRotationResolverService extends ServiceConnector.Impl<IRotationResolverService> {
@@ -128,13 +130,20 @@ class RemoteRotationResolverService extends ServiceConnector.Impl<IRotationResol
mProposedRotation = proposedRotation;
mCurrentRotation = currentRotation;
mPackageName = packageName;
- mIRotationResolverCallback = new RotationResolverCallback();
+ mIRotationResolverCallback = new RotationResolverCallback(this);
mCancellationSignalInternal = cancellationSignal;
mRequestStartTimeMillis = SystemClock.elapsedRealtime();
}
void cancelInternal() {
+ synchronized (mLock) {
+ if (mIsFulfilled) {
+ Slog.v(TAG, "Trying to cancel the request that has been already fulfilled.");
+ return;
+ }
+ mIsFulfilled = true;
+ }
Handler.getMain().post(() -> {
synchronized (mLock) {
try {
@@ -147,9 +156,6 @@ class RemoteRotationResolverService extends ServiceConnector.Impl<IRotationResol
}
}
});
- synchronized (mLock) {
- mIsFulfilled = true;
- }
mCallbackInternal.onFailure(ROTATION_RESULT_FAILURE_CANCELLED);
}
@@ -160,44 +166,53 @@ class RemoteRotationResolverService extends ServiceConnector.Impl<IRotationResol
ipw.decreaseIndent();
}
- private class RotationResolverCallback extends IRotationResolverCallback.Stub {
+ private static class RotationResolverCallback extends IRotationResolverCallback.Stub {
+ private WeakReference<RotationRequest> mRequestWeakReference;
+
+ RotationResolverCallback(RotationRequest request) {
+ this.mRequestWeakReference = new WeakReference<>(request);
+ }
+
@Override
public void onSuccess(int rotation) {
- synchronized (mLock) {
- if (mIsFulfilled) {
+ final RotationRequest request = mRequestWeakReference.get();
+ synchronized (request.mLock) {
+ if (request.mIsFulfilled) {
Slog.w(TAG, "Callback received after the rotation request is fulfilled.");
return;
}
- mIsFulfilled = true;
- mCallbackInternal.onSuccess(rotation);
+ request.mIsFulfilled = true;
+ request.mCallbackInternal.onSuccess(rotation);
final long timeToCalculate =
- SystemClock.elapsedRealtime() - mRequestStartTimeMillis;
- logRotationStats(mProposedRotation, mCurrentRotation, rotation,
+ SystemClock.elapsedRealtime() - request.mRequestStartTimeMillis;
+ logRotationStats(request.mProposedRotation, request.mCurrentRotation, rotation,
timeToCalculate);
}
}
@Override
public void onFailure(int error) {
- synchronized (mLock) {
- if (mIsFulfilled) {
+ final RotationRequest request = mRequestWeakReference.get();
+ synchronized (request.mLock) {
+ if (request.mIsFulfilled) {
Slog.w(TAG, "Callback received after the rotation request is fulfilled.");
return;
}
- mIsFulfilled = true;
- mCallbackInternal.onFailure(error);
+ request.mIsFulfilled = true;
+ request.mCallbackInternal.onFailure(error);
final long timeToCalculate =
- SystemClock.elapsedRealtime() - mRequestStartTimeMillis;
- logRotationStats(mProposedRotation, mCurrentRotation, RESOLUTION_FAILURE,
- timeToCalculate);
+ SystemClock.elapsedRealtime() - request.mRequestStartTimeMillis;
+ logRotationStats(request.mProposedRotation, request.mCurrentRotation,
+ RESOLUTION_FAILURE, timeToCalculate);
}
}
@Override
public void onCancellable(@NonNull ICancellationSignal cancellation) {
- synchronized (mLock) {
- mCancellation = cancellation;
- if (mCancellationSignalInternal.isCanceled()) {
+ final RotationRequest request = mRequestWeakReference.get();
+ synchronized (request.mLock) {
+ request.mCancellation = cancellation;
+ if (request.mCancellationSignalInternal.isCanceled()) {
// Dispatch the cancellation signal if the client has cancelled the request.
try {
cancellation.cancel();
diff --git a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java
index 3dbc32ad54d8..6f7c016cb3f6 100644
--- a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java
+++ b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerPerUserService.java
@@ -122,14 +122,9 @@ final class RotationResolverManagerPerUserService extends
}
});
- if (mRemoteService != null) {
- mRemoteService.resolveRotationLocked(mCurrentRequest);
- mCurrentRequest.mIsDispatched = true;
- } else {
- Slog.w(TAG, "Remote service is not available at this moment.");
- callbackInternal.onFailure(ROTATION_RESULT_FAILURE_CANCELLED);
- cancelLocked();
- }
+
+ mRemoteService.resolveRotationLocked(mCurrentRequest);
+ mCurrentRequest.mIsDispatched = true;
}
@GuardedBy("mLock")
@@ -198,15 +193,6 @@ final class RotationResolverManagerPerUserService extends
if (mCurrentRequest == null) {
return;
}
-
- if (mCurrentRequest.mIsFulfilled) {
- if (isVerbose()) {
- Slog.d(TAG, "Trying to cancel the request that has been already fulfilled.");
- }
- mCurrentRequest = null;
- return;
- }
-
mCurrentRequest.cancelInternal();
mCurrentRequest = null;
}
diff --git a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerService.java b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerService.java
index 4a37e7960912..03d76649e7ee 100644
--- a/services/core/java/com/android/server/rotationresolver/RotationResolverManagerService.java
+++ b/services/core/java/com/android/server/rotationresolver/RotationResolverManagerService.java
@@ -191,7 +191,7 @@ public class RotationResolverManagerService extends
TAG);
final RotationResolverManagerPerUserService service = getServiceForUserLocked(
UserHandle.getCallingUserId());
- new RotationResolverShellCommend(service).exec(this, in, out, err, args, callback,
+ new RotationResolverShellCommand(service).exec(this, in, out, err, args, callback,
resultReceiver);
}
}
diff --git a/services/core/java/com/android/server/rotationresolver/RotationResolverShellCommend.java b/services/core/java/com/android/server/rotationresolver/RotationResolverShellCommand.java
index 0a873892b5bf..54a9edba4e03 100644
--- a/services/core/java/com/android/server/rotationresolver/RotationResolverShellCommend.java
+++ b/services/core/java/com/android/server/rotationresolver/RotationResolverShellCommand.java
@@ -26,13 +26,13 @@ import android.view.Surface;
import java.io.PrintWriter;
-final class RotationResolverShellCommend extends ShellCommand {
+final class RotationResolverShellCommand extends ShellCommand {
private static final int INITIAL_RESULT_CODE = -1;
@NonNull
private final RotationResolverManagerPerUserService mService;
- RotationResolverShellCommend(@NonNull RotationResolverManagerPerUserService service) {
+ RotationResolverShellCommand(@NonNull RotationResolverManagerPerUserService service) {
mService = service;
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 31984531d31f..5697564ce93f 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1094,7 +1094,8 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
return;
}
if (DEBUG) Slog.v(TAG, "Adding window token: " + mToken);
- mWindowManagerInternal.addWindowToken(mToken, TYPE_WALLPAPER, mDisplayId);
+ mWindowManagerInternal.addWindowToken(mToken, TYPE_WALLPAPER, mDisplayId,
+ null /* options */);
final DisplayData wpdData = getDisplayDataOrCreate(mDisplayId);
try {
connection.mService.attach(connection, mToken, TYPE_WALLPAPER, false,
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 2ecefeafcf5c..3bbc81a696e6 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -16,12 +16,27 @@
package com.android.server.wm;
+import static android.os.Build.IS_USER;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static android.view.WindowManager.LayoutParams.TYPE_MAGNIFICATION_OVERLAY;
+import static com.android.server.accessibility.AccessibilityTraceFileProto.ENTRY;
+import static com.android.server.accessibility.AccessibilityTraceFileProto.MAGIC_NUMBER;
+import static com.android.server.accessibility.AccessibilityTraceFileProto.MAGIC_NUMBER_H;
+import static com.android.server.accessibility.AccessibilityTraceFileProto.MAGIC_NUMBER_L;
+import static com.android.server.accessibility.AccessibilityTraceProto.ACCESSIBILITY_SERVICE;
+import static com.android.server.accessibility.AccessibilityTraceProto.CALENDAR_TIME;
+import static com.android.server.accessibility.AccessibilityTraceProto.CALLING_PARAMS;
+import static com.android.server.accessibility.AccessibilityTraceProto.CALLING_PKG;
+import static com.android.server.accessibility.AccessibilityTraceProto.CALLING_STACKS;
+import static com.android.server.accessibility.AccessibilityTraceProto.ELAPSED_REALTIME_NANOS;
+import static com.android.server.accessibility.AccessibilityTraceProto.PROCESS_NAME;
+import static com.android.server.accessibility.AccessibilityTraceProto.THREAD_ID_NAME;
+import static com.android.server.accessibility.AccessibilityTraceProto.WHERE;
+import static com.android.server.accessibility.AccessibilityTraceProto.WINDOW_MANAGER_SERVICE;
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.utils.RegionUtils.forEachRect;
@@ -29,7 +44,9 @@ import static com.android.server.wm.utils.RegionUtils.forEachRect;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
+import android.app.Application;
import android.content.Context;
+import android.content.pm.PackageManagerInternal;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
@@ -41,15 +58,20 @@ import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
+import android.os.Binder;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.Process;
+import android.os.SystemClock;
import android.util.ArraySet;
import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TypedValue;
+import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.InsetsSource;
import android.view.MagnificationSpec;
@@ -64,13 +86,22 @@ import android.view.animation.Interpolator;
import com.android.internal.R;
import com.android.internal.os.SomeArgs;
+import com.android.internal.util.TraceBuffer;
+import com.android.server.LocalServices;
import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.wm.WindowManagerInternal.AccessibilityControllerInternal;
import com.android.server.wm.WindowManagerInternal.MagnificationCallbacks;
import com.android.server.wm.WindowManagerInternal.WindowsForAccessibilityCallback;
+import java.io.File;
+import java.io.IOException;
import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -79,26 +110,37 @@ import java.util.Set;
* This class contains the accessibility related logic of the window manager.
*/
final class AccessibilityController {
+ private static final String TAG = AccessibilityController.class.getSimpleName();
- private final WindowManagerService mService;
+ private static final Object STATIC_LOCK = new Object();
+ static AccessibilityControllerInternal
+ getAccessibilityControllerInternal(WindowManagerService service) {
+ return AccessibilityControllerInternalImpl.getInstance(service);
+ }
+ private final AccessibilityTracing mAccessibilityTracing;
+ private final WindowManagerService mService;
private static final Rect EMPTY_RECT = new Rect();
private static final float[] sTempFloats = new float[9];
- public AccessibilityController(WindowManagerService service) {
+ AccessibilityController(WindowManagerService service) {
mService = service;
+ mAccessibilityTracing = AccessibilityTracing.getInstance(service);
}
private SparseArray<DisplayMagnifier> mDisplayMagnifiers = new SparseArray<>();
-
private SparseArray<WindowsForAccessibilityObserver> mWindowsForAccessibilityObserver =
new SparseArray<>();
// Set to true if initializing window population complete.
private boolean mAllObserversInitialized = true;
- public boolean setMagnificationCallbacksLocked(int displayId,
- MagnificationCallbacks callbacks) {
+ boolean setMagnificationCallbacks(int displayId, MagnificationCallbacks callbacks) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(
+ TAG + ".setMagnificationCallbacks",
+ "displayId=" + displayId + "; callbacks={" + callbacks + "}");
+ }
boolean result = false;
if (callbacks != null) {
if (mDisplayMagnifiers.get(displayId) != null) {
@@ -118,7 +160,7 @@ final class AccessibilityController {
if (displayMagnifier == null) {
throw new IllegalStateException("Magnification callbacks already cleared!");
}
- displayMagnifier.destroyLocked();
+ displayMagnifier.destroy();
mDisplayMagnifiers.remove(displayId);
result = true;
}
@@ -133,8 +175,13 @@ final class AccessibilityController {
* @param callback The callback.
* @return {@code false} if display id is not valid or an embedded display.
*/
- public boolean setWindowsForAccessibilityCallbackLocked(int displayId,
+ boolean setWindowsForAccessibilityCallback(int displayId,
WindowsForAccessibilityCallback callback) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(
+ TAG + ".setWindowsForAccessibilityCallback",
+ "displayId=" + displayId + "; callback={" + callback + "}");
+ }
final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
if (dc == null) {
return false;
@@ -147,7 +194,7 @@ final class AccessibilityController {
// empty, that means this mapping didn't be set, and needs to do this again.
// This happened when accessibility window observer is disabled and enabled again.
if (mWindowsForAccessibilityObserver.get(displayId) == null) {
- handleWindowObserverOfEmbeddedDisplayLocked(displayId, dc.getParentWindow());
+ handleWindowObserverOfEmbeddedDisplay(displayId, dc.getParentWindow());
}
return false;
} else if (mWindowsForAccessibilityObserver.get(displayId) != null) {
@@ -181,7 +228,12 @@ final class AccessibilityController {
return true;
}
- public void performComputeChangedWindowsNotLocked(int displayId, boolean forceSend) {
+ void performComputeChangedWindowsNot(int displayId, boolean forceSend) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(
+ TAG + ".performComputeChangedWindowsNot",
+ "displayId=" + displayId + "; forceSend=" + forceSend);
+ }
WindowsForAccessibilityObserver observer = null;
synchronized (mService.mGlobalLock) {
final WindowsForAccessibilityObserver windowsForA11yObserver =
@@ -191,86 +243,119 @@ final class AccessibilityController {
}
}
if (observer != null) {
- observer.performComputeChangedWindowsNotLocked(forceSend);
+ observer.performComputeChangedWindows(forceSend);
}
}
- public void setMagnificationSpecLocked(int displayId, MagnificationSpec spec) {
+ void setMagnificationSpec(int displayId, MagnificationSpec spec) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(TAG + ".setMagnificationSpec",
+ "displayId=" + displayId + "; spec={" + spec + "}");
+ }
final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
if (displayMagnifier != null) {
- displayMagnifier.setMagnificationSpecLocked(spec);
+ displayMagnifier.setMagnificationSpec(spec);
}
final WindowsForAccessibilityObserver windowsForA11yObserver =
mWindowsForAccessibilityObserver.get(displayId);
if (windowsForA11yObserver != null) {
- windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
+ windowsForA11yObserver.scheduleComputeChangedWindows();
}
}
- public void getMagnificationRegionLocked(int displayId, Region outMagnificationRegion) {
+ void getMagnificationRegion(int displayId, Region outMagnificationRegion) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(TAG + ".getMagnificationRegion",
+ "displayId=" + displayId + "; outMagnificationRegion={" + outMagnificationRegion
+ + "}");
+ }
final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
if (displayMagnifier != null) {
- displayMagnifier.getMagnificationRegionLocked(outMagnificationRegion);
+ displayMagnifier.getMagnificationRegion(outMagnificationRegion);
}
}
- public void onRectangleOnScreenRequestedLocked(int displayId, Rect rectangle) {
+ void onRectangleOnScreenRequested(int displayId, Rect rectangle) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(
+ TAG + ".onRectangleOnScreenRequested",
+ "displayId=" + displayId + "; rectangle={" + rectangle + "}");
+ }
final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
if (displayMagnifier != null) {
- displayMagnifier.onRectangleOnScreenRequestedLocked(rectangle);
+ displayMagnifier.onRectangleOnScreenRequested(rectangle);
}
// Not relevant for the window observer.
}
- public void onWindowLayersChangedLocked(int displayId) {
+ void onWindowLayersChanged(int displayId) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(
+ TAG + ".onWindowLayersChanged", "displayId=" + displayId);
+ }
final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
if (displayMagnifier != null) {
- displayMagnifier.onWindowLayersChangedLocked();
+ displayMagnifier.onWindowLayersChanged();
}
final WindowsForAccessibilityObserver windowsForA11yObserver =
mWindowsForAccessibilityObserver.get(displayId);
if (windowsForA11yObserver != null) {
- windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
+ windowsForA11yObserver.scheduleComputeChangedWindows();
}
}
- public void onRotationChangedLocked(DisplayContent displayContent) {
+ void onRotationChanged(DisplayContent displayContent) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(TAG + ".onRotationChanged",
+ "displayContent={" + displayContent + "}");
+ }
final int displayId = displayContent.getDisplayId();
final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
if (displayMagnifier != null) {
- displayMagnifier.onRotationChangedLocked(displayContent);
+ displayMagnifier.onRotationChanged(displayContent);
}
final WindowsForAccessibilityObserver windowsForA11yObserver =
mWindowsForAccessibilityObserver.get(displayId);
if (windowsForA11yObserver != null) {
- windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
+ windowsForA11yObserver.scheduleComputeChangedWindows();
}
}
- public void onAppWindowTransitionLocked(int displayId, int transition) {
+ void onAppWindowTransition(int displayId, int transition) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(TAG + ".onAppWindowTransition",
+ "displayId=" + displayId + "; transition=" + transition);
+ }
final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
if (displayMagnifier != null) {
- displayMagnifier.onAppWindowTransitionLocked(displayId, transition);
+ displayMagnifier.onAppWindowTransition(displayId, transition);
}
// Not relevant for the window observer.
}
- public void onWindowTransitionLocked(WindowState windowState, int transition) {
+ void onWindowTransition(WindowState windowState, int transition) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(TAG + ".onWindowTransition",
+ "windowState={" + windowState + "}; transition=" + transition);
+ }
final int displayId = windowState.getDisplayId();
final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
if (displayMagnifier != null) {
- displayMagnifier.onWindowTransitionLocked(windowState, transition);
+ displayMagnifier.onWindowTransition(windowState, transition);
}
final WindowsForAccessibilityObserver windowsForA11yObserver =
mWindowsForAccessibilityObserver.get(displayId);
if (windowsForA11yObserver != null) {
- windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
+ windowsForA11yObserver.scheduleComputeChangedWindows();
}
}
- public void onWindowFocusChangedNotLocked(int displayId) {
+ void onWindowFocusChangedNot(int displayId) {
// Not relevant for the display magnifier.
-
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(
+ TAG + ".onWindowFocusChangedNot", "displayId=" + displayId);
+ }
WindowsForAccessibilityObserver observer = null;
synchronized (mService.mGlobalLock) {
final WindowsForAccessibilityObserver windowsForA11yObserver =
@@ -280,7 +365,7 @@ final class AccessibilityController {
}
}
if (observer != null) {
- observer.performComputeChangedWindowsNotLocked(false);
+ observer.performComputeChangedWindows(false);
}
// Since we abandon initializing observers if no window has focus, make sure all observers
// are initialized.
@@ -311,7 +396,7 @@ final class AccessibilityController {
boolean areAllObserversInitialized = true;
for (int i = unInitializedObservers.size() - 1; i >= 0; --i) {
final WindowsForAccessibilityObserver observer = unInitializedObservers.get(i);
- observer.performComputeChangedWindowsNotLocked(true);
+ observer.performComputeChangedWindows(true);
areAllObserversInitialized &= observer.mInitialized;
}
synchronized (mService.mGlobalLock) {
@@ -324,50 +409,89 @@ final class AccessibilityController {
* another display is also taken into consideration.
* @param displayIds the display ids of displays when the situation happens.
*/
- public void onSomeWindowResizedOrMovedLocked(int... displayIds) {
+ void onSomeWindowResizedOrMoved(int... displayIds) {
+ onSomeWindowResizedOrMovedWithCallingUid(Binder.getCallingUid(), displayIds);
+ }
+
+ void onSomeWindowResizedOrMovedWithCallingUid(int callingUid, int... displayIds) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(
+ TAG + ".onSomeWindowResizedOrMoved",
+ "displayIds={" + displayIds.toString() + "}",
+ "".getBytes(),
+ callingUid);
+ }
// Not relevant for the display magnifier.
for (int i = 0; i < displayIds.length; i++) {
final WindowsForAccessibilityObserver windowsForA11yObserver =
mWindowsForAccessibilityObserver.get(displayIds[i]);
if (windowsForA11yObserver != null) {
- windowsForA11yObserver.scheduleComputeChangedWindowsLocked();
+ windowsForA11yObserver.scheduleComputeChangedWindows();
}
}
}
- public void drawMagnifiedRegionBorderIfNeededLocked(int displayId,
- SurfaceControl.Transaction t) {
+ void drawMagnifiedRegionBorderIfNeeded(int displayId, SurfaceControl.Transaction t) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(
+ TAG + ".drawMagnifiedRegionBorderIfNeeded",
+ "displayId=" + displayId + "; transaction={" + t + "}");
+ }
final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
if (displayMagnifier != null) {
- displayMagnifier.drawMagnifiedRegionBorderIfNeededLocked(t);
+ displayMagnifier.drawMagnifiedRegionBorderIfNeeded(t);
}
// Not relevant for the window observer.
}
- public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
+ MagnificationSpec getMagnificationSpecForWindow(WindowState windowState) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(TAG + ".getMagnificationSpecForWindow",
+ "windowState={" + windowState + "}");
+ }
final int displayId = windowState.getDisplayId();
final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
if (displayMagnifier != null) {
- return displayMagnifier.getMagnificationSpecForWindowLocked(windowState);
+ return displayMagnifier.getMagnificationSpecForWindow(windowState);
}
return null;
}
- public boolean hasCallbacksLocked() {
+ boolean hasCallbacks() {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(TAG + ".hasCallbacks");
+ }
return (mDisplayMagnifiers.size() > 0
|| mWindowsForAccessibilityObserver.size() > 0);
}
- public void setForceShowMagnifiableBoundsLocked(int displayId, boolean show) {
+ void setForceShowMagnifiableBounds(int displayId, boolean show) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(TAG + ".setForceShowMagnifiableBounds",
+ "displayId=" + displayId + "; show=" + show);
+ }
final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
if (displayMagnifier != null) {
- displayMagnifier.setForceShowMagnifiableBoundsLocked(show);
+ displayMagnifier.setForceShowMagnifiableBounds(show);
displayMagnifier.showMagnificationBoundsIfNeeded();
}
}
- public void handleWindowObserverOfEmbeddedDisplayLocked(int embeddedDisplayId,
+ void handleWindowObserverOfEmbeddedDisplay(int embeddedDisplayId,
WindowState parentWindow) {
+ handleWindowObserverOfEmbeddedDisplay(
+ embeddedDisplayId, parentWindow, Binder.getCallingUid());
+ }
+
+ void handleWindowObserverOfEmbeddedDisplay(
+ int embeddedDisplayId, WindowState parentWindow, int callingUid) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(TAG + ".handleWindowObserverOfEmbeddedDisplay",
+ "embeddedDisplayId=" + embeddedDisplayId + "; parentWindowState={"
+ + parentWindow + "}",
+ "".getBytes(),
+ callingUid);
+ }
if (embeddedDisplayId == Display.DEFAULT_DISPLAY || parentWindow == null) {
return;
}
@@ -390,7 +514,7 @@ final class AccessibilityController {
}
}
- private static void populateTransformationMatrixLocked(WindowState windowState,
+ private static void populateTransformationMatrix(WindowState windowState,
Matrix outMatrix) {
windowState.getTransformationMatrix(sTempFloats, outMatrix);
}
@@ -451,6 +575,7 @@ final class AccessibilityController {
private final Handler mHandler;
private final DisplayContent mDisplayContent;
private final Display mDisplay;
+ private final AccessibilityTracing mAccessibilityTracing;
private final MagnificationCallbacks mCallbacks;
@@ -458,7 +583,7 @@ final class AccessibilityController {
private boolean mForceShowMagnifiableBounds = false;
- public DisplayMagnifier(WindowManagerService windowManagerService,
+ DisplayMagnifier(WindowManagerService windowManagerService,
DisplayContent displayContent,
Display display,
MagnificationCallbacks callbacks) {
@@ -469,36 +594,58 @@ final class AccessibilityController {
mDisplay = display;
mHandler = new MyHandler(mService.mH.getLooper());
mMagnifedViewport = new MagnifiedViewport();
+ mAccessibilityTracing = AccessibilityTracing.getInstance(mService);
mLongAnimationDuration = mDisplayContext.getResources().getInteger(
com.android.internal.R.integer.config_longAnimTime);
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(LOG_TAG + ".DisplayMagnifier.constructor",
+ "windowManagerService={" + windowManagerService + "}; displayContent={"
+ + displayContent + "}; display={" + display + "}; callbacks={"
+ + callbacks + "}");
+ }
}
- public void setMagnificationSpecLocked(MagnificationSpec spec) {
- mMagnifedViewport.updateMagnificationSpecLocked(spec);
- mMagnifedViewport.recomputeBoundsLocked();
+ void setMagnificationSpec(MagnificationSpec spec) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(
+ LOG_TAG + ".setMagnificationSpec", "spec={" + spec + "}");
+ }
+ mMagnifedViewport.updateMagnificationSpec(spec);
+ mMagnifedViewport.recomputeBounds();
mService.applyMagnificationSpecLocked(mDisplay.getDisplayId(), spec);
mService.scheduleAnimationLocked();
}
- public void setForceShowMagnifiableBoundsLocked(boolean show) {
+ void setForceShowMagnifiableBounds(boolean show) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(
+ LOG_TAG + ".setForceShowMagnifiableBounds", "show=" + show);
+ }
mForceShowMagnifiableBounds = show;
- mMagnifedViewport.setMagnifiedRegionBorderShownLocked(show, true);
+ mMagnifedViewport.setMagnifiedRegionBorderShown(show, true);
}
- public boolean isForceShowingMagnifiableBoundsLocked() {
+ boolean isForceShowingMagnifiableBounds() {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(LOG_TAG + ".isForceShowingMagnifiableBounds");
+ }
return mForceShowMagnifiableBounds;
}
- public void onRectangleOnScreenRequestedLocked(Rect rectangle) {
+ void onRectangleOnScreenRequested(Rect rectangle) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(
+ LOG_TAG + ".onRectangleOnScreenRequested", "rectangle={" + rectangle + "}");
+ }
if (DEBUG_RECTANGLE_REQUESTED) {
Slog.i(LOG_TAG, "Rectangle on screen requested: " + rectangle);
}
- if (!mMagnifedViewport.isMagnifyingLocked()) {
+ if (!mMagnifedViewport.isMagnifying()) {
return;
}
Rect magnifiedRegionBounds = mTempRect2;
- mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(magnifiedRegionBounds);
+ mMagnifedViewport.getMagnifiedFrameInContentCoords(magnifiedRegionBounds);
if (magnifiedRegionBounds.contains(rectangle)) {
return;
}
@@ -511,31 +658,42 @@ final class AccessibilityController {
args).sendToTarget();
}
- public void onWindowLayersChangedLocked() {
+ void onWindowLayersChanged() {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(LOG_TAG + ".onWindowLayersChanged");
+ }
if (DEBUG_LAYERS) {
Slog.i(LOG_TAG, "Layers changed.");
}
- mMagnifedViewport.recomputeBoundsLocked();
+ mMagnifedViewport.recomputeBounds();
mService.scheduleAnimationLocked();
}
- public void onRotationChangedLocked(DisplayContent displayContent) {
+ void onRotationChanged(DisplayContent displayContent) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(
+ LOG_TAG + ".onRotationChanged", "displayContent={" + displayContent + "}");
+ }
if (DEBUG_ROTATION) {
final int rotation = displayContent.getRotation();
Slog.i(LOG_TAG, "Rotation: " + Surface.rotationToString(rotation)
+ " displayId: " + displayContent.getDisplayId());
}
- mMagnifedViewport.onRotationChangedLocked(displayContent.getPendingTransaction());
+ mMagnifedViewport.onRotationChanged(displayContent.getPendingTransaction());
mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_ROTATION_CHANGED);
}
- public void onAppWindowTransitionLocked(int displayId, int transition) {
+ void onAppWindowTransition(int displayId, int transition) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(LOG_TAG + ".onAppWindowTransition",
+ "displayId=" + displayId + "; transition=" + transition);
+ }
if (DEBUG_WINDOW_TRANSITIONS) {
Slog.i(LOG_TAG, "Window transition: "
+ AppTransition.appTransitionOldToString(transition)
+ " displayId: " + displayId);
}
- final boolean magnifying = mMagnifedViewport.isMagnifyingLocked();
+ final boolean magnifying = mMagnifedViewport.isMagnifying();
if (magnifying) {
switch (transition) {
case WindowManager.TRANSIT_OLD_ACTIVITY_OPEN:
@@ -550,13 +708,17 @@ final class AccessibilityController {
}
}
- public void onWindowTransitionLocked(WindowState windowState, int transition) {
+ void onWindowTransition(WindowState windowState, int transition) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(LOG_TAG + ".onWindowTransition",
+ "windowState={" + windowState + "}; transition=" + transition);
+ }
if (DEBUG_WINDOW_TRANSITIONS) {
Slog.i(LOG_TAG, "Window transition: "
+ AppTransition.appTransitionOldToString(transition)
+ " displayId: " + windowState.getDisplayId());
}
- final boolean magnifying = mMagnifedViewport.isMagnifyingLocked();
+ final boolean magnifying = mMagnifedViewport.isMagnifying();
final int type = windowState.mAttrs.type;
switch (transition) {
case WindowManagerPolicy.TRANSIT_ENTER:
@@ -586,7 +748,7 @@ final class AccessibilityController {
case WindowManager.LayoutParams.TYPE_QS_DIALOG:
case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: {
Rect magnifiedRegionBounds = mTempRect2;
- mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(
+ mMagnifedViewport.getMagnifiedFrameInContentCoords(
magnifiedRegionBounds);
Rect touchableRegionBounds = mTempRect1;
windowState.getTouchableRegion(mTempRegion1);
@@ -604,8 +766,12 @@ final class AccessibilityController {
}
}
- public MagnificationSpec getMagnificationSpecForWindowLocked(WindowState windowState) {
- MagnificationSpec spec = mMagnifedViewport.getMagnificationSpecLocked();
+ MagnificationSpec getMagnificationSpecForWindow(WindowState windowState) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(LOG_TAG + ".getMagnificationSpecForWindow",
+ "windowState={" + windowState + "}");
+ }
+ MagnificationSpec spec = mMagnifedViewport.getMagnificationSpec();
if (spec != null && !spec.isNop()) {
if (!windowState.shouldMagnify()) {
return null;
@@ -614,24 +780,38 @@ final class AccessibilityController {
return spec;
}
- public void getMagnificationRegionLocked(Region outMagnificationRegion) {
+ void getMagnificationRegion(Region outMagnificationRegion) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(LOG_TAG + ".getMagnificationRegion",
+ "outMagnificationRegion={" + outMagnificationRegion + "}");
+ }
// Make sure we're working with the most current bounds
- mMagnifedViewport.recomputeBoundsLocked();
- mMagnifedViewport.getMagnificationRegionLocked(outMagnificationRegion);
+ mMagnifedViewport.recomputeBounds();
+ mMagnifedViewport.getMagnificationRegion(outMagnificationRegion);
}
- public void destroyLocked() {
+ void destroy() {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(LOG_TAG + ".destroy");
+ }
mMagnifedViewport.destroyWindow();
}
// Can be called outside of a surface transaction
- public void showMagnificationBoundsIfNeeded() {
+ void showMagnificationBoundsIfNeeded() {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(LOG_TAG + ".showMagnificationBoundsIfNeeded");
+ }
mHandler.obtainMessage(MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)
.sendToTarget();
}
- public void drawMagnifiedRegionBorderIfNeededLocked(SurfaceControl.Transaction t) {
- mMagnifedViewport.drawWindowIfNeededLocked(t);
+ void drawMagnifiedRegionBorderIfNeeded(SurfaceControl.Transaction t) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(LOG_TAG + ".drawMagnifiedRegionBorderIfNeeded",
+ "transition={" + t + "}");
+ }
+ mMagnifedViewport.drawWindowIfNeeded(t);
}
void dump(PrintWriter pw, String prefix) {
@@ -665,7 +845,7 @@ final class AccessibilityController {
private boolean mFullRedrawNeeded;
private int mTempLayer = 0;
- public MagnifiedViewport() {
+ MagnifiedViewport() {
mBorderWidth = mDisplayContext.getResources().getDimension(
com.android.internal.R.dimen.accessibility_magnification_indicator_width);
mHalfBorderWidth = (int) Math.ceil(mBorderWidth / 2);
@@ -681,14 +861,14 @@ final class AccessibilityController {
mCircularPath = null;
}
- recomputeBoundsLocked();
+ recomputeBounds();
}
- public void getMagnificationRegionLocked(@NonNull Region outMagnificationRegion) {
+ void getMagnificationRegion(@NonNull Region outMagnificationRegion) {
outMagnificationRegion.set(mMagnificationRegion);
}
- public void updateMagnificationSpecLocked(MagnificationSpec spec) {
+ void updateMagnificationSpec(MagnificationSpec spec) {
if (spec != null) {
mMagnificationSpec.initialize(spec.scale, spec.offsetX, spec.offsetY);
} else {
@@ -698,12 +878,12 @@ final class AccessibilityController {
// to show the border. We will do so when the pending message is handled.
if (!mHandler.hasMessages(
MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)) {
- setMagnifiedRegionBorderShownLocked(
- isMagnifyingLocked() || isForceShowingMagnifiableBoundsLocked(), true);
+ setMagnifiedRegionBorderShown(
+ isMagnifying() || isForceShowingMagnifiableBounds(), true);
}
}
- public void recomputeBoundsLocked() {
+ void recomputeBounds() {
mDisplay.getRealSize(mTempPoint);
final int screenWidth = mTempPoint.x;
final int screenHeight = mTempPoint.y;
@@ -721,7 +901,7 @@ final class AccessibilityController {
SparseArray<WindowState> visibleWindows = mTempWindowStates;
visibleWindows.clear();
- populateWindowsOnScreenLocked(visibleWindows);
+ populateWindowsOnScreen(visibleWindows);
final int visibleWindowCount = visibleWindows.size();
for (int i = visibleWindowCount - 1; i >= 0; i--) {
@@ -736,7 +916,7 @@ final class AccessibilityController {
// Consider the touchable portion of the window
Matrix matrix = mTempMatrix;
- populateTransformationMatrixLocked(windowState, matrix);
+ populateTransformationMatrix(windowState, matrix);
Region touchableRegion = mTempRegion3;
windowState.getTouchableRegion(touchableRegion);
Rect touchableFrame = mTempRect1;
@@ -848,24 +1028,24 @@ final class AccessibilityController {
return letterboxBounds;
}
- public void onRotationChangedLocked(SurfaceControl.Transaction t) {
+ void onRotationChanged(SurfaceControl.Transaction t) {
// If we are showing the magnification border, hide it immediately so
// the user does not see strange artifacts during rotation. The screenshot
// used for rotation already has the border. After the rotation is complete
// we will show the border.
- if (isMagnifyingLocked() || isForceShowingMagnifiableBoundsLocked()) {
- setMagnifiedRegionBorderShownLocked(false, false);
+ if (isMagnifying() || isForceShowingMagnifiableBounds()) {
+ setMagnifiedRegionBorderShown(false, false);
final long delay = (long) (mLongAnimationDuration
* mService.getWindowAnimationScaleLocked());
Message message = mHandler.obtainMessage(
MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED);
mHandler.sendMessageDelayed(message, delay);
}
- recomputeBoundsLocked();
+ recomputeBounds();
mWindow.updateSize(t);
}
- public void setMagnifiedRegionBorderShownLocked(boolean shown, boolean animate) {
+ void setMagnifiedRegionBorderShown(boolean shown, boolean animate) {
if (shown) {
mFullRedrawNeeded = true;
mOldMagnificationRegion.set(0, 0, 0, 0);
@@ -873,31 +1053,31 @@ final class AccessibilityController {
mWindow.setShown(shown, animate);
}
- public void getMagnifiedFrameInContentCoordsLocked(Rect rect) {
+ void getMagnifiedFrameInContentCoords(Rect rect) {
MagnificationSpec spec = mMagnificationSpec;
mMagnificationRegion.getBounds(rect);
rect.offset((int) -spec.offsetX, (int) -spec.offsetY);
rect.scale(1.0f / spec.scale);
}
- public boolean isMagnifyingLocked() {
+ boolean isMagnifying() {
return mMagnificationSpec.scale > 1.0f;
}
- public MagnificationSpec getMagnificationSpecLocked() {
+ MagnificationSpec getMagnificationSpec() {
return mMagnificationSpec;
}
- public void drawWindowIfNeededLocked(SurfaceControl.Transaction t) {
- recomputeBoundsLocked();
+ void drawWindowIfNeeded(SurfaceControl.Transaction t) {
+ recomputeBounds();
mWindow.drawIfNeeded(t);
}
- public void destroyWindow() {
+ void destroyWindow() {
mWindow.releaseSurface();
}
- private void populateWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
+ private void populateWindowsOnScreen(SparseArray<WindowState> outWindows) {
mTempLayer = 0;
mDisplayContent.forAllWindows((w) -> {
if (w.isOnScreen() && w.isVisible()
@@ -929,7 +1109,7 @@ final class AccessibilityController {
private boolean mInvalidated;
- public ViewportWindow(Context context) {
+ ViewportWindow(Context context) {
SurfaceControl surfaceControl = null;
try {
mDisplay.getRealSize(mTempPoint);
@@ -971,7 +1151,7 @@ final class AccessibilityController {
mInvalidated = true;
}
- public void setShown(boolean shown, boolean animate) {
+ void setShown(boolean shown, boolean animate) {
synchronized (mService.mGlobalLock) {
if (mShown == shown) {
return;
@@ -986,13 +1166,13 @@ final class AccessibilityController {
@SuppressWarnings("unused")
// Called reflectively from an animator.
- public int getAlpha() {
+ int getAlpha() {
synchronized (mService.mGlobalLock) {
return mAlpha;
}
}
- public void setAlpha(int alpha) {
+ void setAlpha(int alpha) {
synchronized (mService.mGlobalLock) {
if (mAlpha == alpha) {
return;
@@ -1005,7 +1185,7 @@ final class AccessibilityController {
}
}
- public void setBounds(Region bounds) {
+ void setBounds(Region bounds) {
synchronized (mService.mGlobalLock) {
if (mBounds.equals(bounds)) {
return;
@@ -1018,7 +1198,7 @@ final class AccessibilityController {
}
}
- public void updateSize(SurfaceControl.Transaction t) {
+ void updateSize(SurfaceControl.Transaction t) {
synchronized (mService.mGlobalLock) {
mDisplay.getRealSize(mTempPoint);
t.setBufferSize(mSurfaceControl, mTempPoint.x, mTempPoint.y);
@@ -1026,7 +1206,7 @@ final class AccessibilityController {
}
}
- public void invalidate(Rect dirtyRect) {
+ void invalidate(Rect dirtyRect) {
if (dirtyRect != null) {
mDirtyRect.set(dirtyRect);
} else {
@@ -1036,7 +1216,7 @@ final class AccessibilityController {
mService.scheduleAnimationLocked();
}
- public void drawIfNeeded(SurfaceControl.Transaction t) {
+ void drawIfNeeded(SurfaceControl.Transaction t) {
synchronized (mService.mGlobalLock) {
if (!mInvalidated) {
return;
@@ -1078,7 +1258,7 @@ final class AccessibilityController {
}
}
- public void releaseSurface() {
+ void releaseSurface() {
mService.mTransactionFactory.get().remove(mSurfaceControl).apply();
mSurface.release();
}
@@ -1101,7 +1281,7 @@ final class AccessibilityController {
private final ValueAnimator mShowHideFrameAnimator;
- public AnimationController(Context context, Looper looper) {
+ AnimationController(Context context, Looper looper) {
super(looper);
mShowHideFrameAnimator = ObjectAnimator.ofInt(ViewportWindow.this,
PROPERTY_NAME_ALPHA, MIN_ALPHA, MAX_ALPHA);
@@ -1114,7 +1294,7 @@ final class AccessibilityController {
mShowHideFrameAnimator.setDuration(longAnimationDuration);
}
- public void onFrameShownStateChanged(boolean shown, boolean animate) {
+ void onFrameShownStateChanged(boolean shown, boolean animate) {
obtainMessage(MSG_FRAME_SHOWN_STATE_CHANGED,
shown ? 1 : 0, animate ? 1 : 0).sendToTarget();
}
@@ -1158,7 +1338,7 @@ final class AccessibilityController {
public static final int MESSAGE_NOTIFY_ROTATION_CHANGED = 4;
public static final int MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED = 5;
- public MyHandler(Looper looper) {
+ MyHandler(Looper looper) {
super(looper);
}
@@ -1193,9 +1373,9 @@ final class AccessibilityController {
case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : {
synchronized (mService.mGlobalLock) {
- if (mMagnifedViewport.isMagnifyingLocked()
- || isForceShowingMagnifiableBoundsLocked()) {
- mMagnifedViewport.setMagnifiedRegionBorderShownLocked(true, true);
+ if (mMagnifedViewport.isMagnifying()
+ || isForceShowingMagnifiableBounds()) {
+ mMagnifedViewport.setMagnifiedRegionBorderShown(true, true);
mService.scheduleAnimationLocked();
}
}
@@ -1252,6 +1432,8 @@ final class AccessibilityController {
private final Handler mHandler;
+ private final AccessibilityTracing mAccessibilityTracing;
+
private final WindowsForAccessibilityCallback mCallback;
private final int mDisplayId;
@@ -1263,24 +1445,32 @@ final class AccessibilityController {
// Set to true if initializing window population complete.
private boolean mInitialized;
- public WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
+ WindowsForAccessibilityObserver(WindowManagerService windowManagerService,
int displayId,
WindowsForAccessibilityCallback callback) {
mService = windowManagerService;
mCallback = callback;
mDisplayId = displayId;
mHandler = new MyHandler(mService.mH.getLooper());
+ mAccessibilityTracing = AccessibilityTracing.getInstance(mService);
mRecurringAccessibilityEventsIntervalMillis = ViewConfiguration
.getSendRecurringAccessibilityEventsInterval();
computeChangedWindows(true);
}
- public void performComputeChangedWindowsNotLocked(boolean forceSend) {
+ void performComputeChangedWindows(boolean forceSend) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(LOG_TAG + ".performComputeChangedWindows",
+ "forceSend=" + forceSend);
+ }
mHandler.removeMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS);
computeChangedWindows(forceSend);
}
- public void scheduleComputeChangedWindowsLocked() {
+ void scheduleComputeChangedWindows() {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(LOG_TAG + ".scheduleComputeChangedWindows");
+ }
if (!mHandler.hasMessages(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS)) {
mHandler.sendEmptyMessageDelayed(MyHandler.MESSAGE_COMPUTE_CHANGED_WINDOWS,
mRecurringAccessibilityEventsIntervalMillis);
@@ -1307,7 +1497,11 @@ final class AccessibilityController {
*
* @param forceSend Send the windows the accessibility even if they haven't changed.
*/
- public void computeChangedWindows(boolean forceSend) {
+ void computeChangedWindows(boolean forceSend) {
+ if (mAccessibilityTracing.isEnabled()) {
+ mAccessibilityTracing.logState(
+ LOG_TAG + ".computeChangedWindows", "forceSend=" + forceSend);
+ }
if (DEBUG) {
Slog.i(LOG_TAG, "computeChangedWindows()");
}
@@ -1343,7 +1537,7 @@ final class AccessibilityController {
unaccountedSpace.set(0, 0, screenWidth, screenHeight);
final SparseArray<WindowState> visibleWindows = mTempWindowStates;
- populateVisibleWindowsOnScreenLocked(visibleWindows);
+ populateVisibleWindowsOnScreen(visibleWindows);
Set<IBinder> addedWindows = mTempBinderSet;
addedWindows.clear();
@@ -1518,7 +1712,7 @@ final class AccessibilityController {
// Map the frame to get what appears on the screen.
Matrix matrix = mTempMatrix;
- populateTransformationMatrixLocked(windowState, matrix);
+ populateTransformationMatrix(windowState, matrix);
forEachRect(touchableRegion, rect -> {
// Move to origin as all transforms are captured by the matrix.
@@ -1563,7 +1757,7 @@ final class AccessibilityController {
&& windowType != WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION);
}
- private void populateVisibleWindowsOnScreenLocked(SparseArray<WindowState> outWindows) {
+ private void populateVisibleWindowsOnScreen(SparseArray<WindowState> outWindows) {
final List<WindowState> tempWindowStatesList = new ArrayList<>();
final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
if (dc == null) {
@@ -1637,4 +1831,292 @@ final class AccessibilityController {
}
}
}
+
+ private static final class AccessibilityControllerInternalImpl
+ implements AccessibilityControllerInternal {
+
+ private static AccessibilityControllerInternal sInstance;
+ static AccessibilityControllerInternal getInstance(WindowManagerService service) {
+ synchronized (STATIC_LOCK) {
+ if (sInstance == null) {
+ sInstance = new AccessibilityControllerInternalImpl(service);
+ }
+ return sInstance;
+ }
+ }
+
+ private final AccessibilityTracing mTracing;
+ private AccessibilityControllerInternalImpl(WindowManagerService service) {
+ mTracing = AccessibilityTracing.getInstance(service);
+ }
+
+ @Override
+ public void startTrace() {
+ mTracing.startTrace();
+ }
+
+ @Override
+ public void stopTrace() {
+ mTracing.stopTrace();
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return mTracing.isEnabled();
+ }
+
+ @Override
+ public void logTrace(
+ String where, String callingParams, byte[] a11yDump, int callingUid,
+ StackTraceElement[] stackTrace) {
+ mTracing.logState(where, callingParams, a11yDump, callingUid, stackTrace);
+ }
+ }
+
+ private static final class AccessibilityTracing {
+ private static AccessibilityTracing sInstance;
+ static AccessibilityTracing getInstance(WindowManagerService service) {
+ synchronized (STATIC_LOCK) {
+ if (sInstance == null) {
+ sInstance = new AccessibilityTracing(service);
+ }
+ return sInstance;
+ }
+ }
+
+ private static final int BUFFER_CAPACITY = 4096 * 1024;
+ private static final String TRACE_FILENAME = "/data/misc/a11ytrace/a11y_trace.pb";
+ private static final String TRACE_DIRECTORY = "/data/misc/a11ytrace/";
+ private static final String TAG = "AccessibilityTracing";
+ private static final long MAGIC_NUMBER_VALUE =
+ ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
+
+ private final Object mLock = new Object();
+ private final WindowManagerService mService;
+ private final File mTraceFile;
+ private final TraceBuffer mBuffer;
+ private final LogHandler mHandler;
+ private volatile boolean mEnabled;
+
+ AccessibilityTracing(WindowManagerService service) {
+ mService = service;
+ mTraceFile = new File(TRACE_FILENAME);
+ mBuffer = new TraceBuffer(BUFFER_CAPACITY);
+ HandlerThread workThread = new HandlerThread(TAG);
+ workThread.start();
+ mHandler = new LogHandler(workThread.getLooper());
+ }
+
+ /**
+ * Start the trace.
+ */
+ void startTrace() {
+ if (IS_USER) {
+ Slog.e(TAG, "Error: Tracing is not supported on user builds.");
+ return;
+ }
+ synchronized (mLock) {
+ try {
+ Files.createDirectories(Paths.get(TRACE_DIRECTORY));
+ mTraceFile.createNewFile();
+ } catch (Exception e) {
+ Slog.e(TAG, "Error: Failed to create trace file.");
+ return;
+ }
+ mEnabled = true;
+ mBuffer.resetBuffer();
+ }
+ }
+
+ /**
+ * Stops the trace and write the current buffer to disk
+ */
+ void stopTrace() {
+ if (IS_USER) {
+ Slog.e(TAG, "Error: Tracing is not supported on user builds.");
+ return;
+ }
+ synchronized (mLock) {
+ mEnabled = false;
+ if (mEnabled) {
+ Slog.e(TAG, "Error: tracing enabled while waiting for flush.");
+ return;
+ }
+ writeTraceToFile();
+ }
+ }
+
+ boolean isEnabled() {
+ return mEnabled;
+ }
+
+ /**
+ * Write an accessibility trace log entry.
+ */
+ void logState(String where) {
+ if (!mEnabled) {
+ return;
+ }
+ logState(where, "");
+ }
+
+ /**
+ * Write an accessibility trace log entry.
+ */
+ void logState(String where, String callingParams) {
+ if (!mEnabled) {
+ return;
+ }
+ logState(where, callingParams, "".getBytes());
+ }
+
+ /**
+ * Write an accessibility trace log entry.
+ */
+ void logState(String where, String callingParams, byte[] a11yDump) {
+ if (!mEnabled) {
+ return;
+ }
+ logState(where, callingParams, a11yDump, Binder.getCallingUid());
+ }
+
+ /**
+ * Write an accessibility trace log entry.
+ */
+ void logState(
+ String where, String callingParams, byte[] a11yDump, int callingUid) {
+ if (!mEnabled) {
+ return;
+ }
+ StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
+
+ logState(where, callingParams, a11yDump, callingUid, stackTraceElements);
+ }
+
+ /**
+ * Write an accessibility trace log entry.
+ */
+ void logState(String where, String callingParams, byte[] a11yDump, int callingUid,
+ StackTraceElement[] stackTrace) {
+ if (!mEnabled) {
+ return;
+ }
+
+ log(where, callingParams, a11yDump, callingUid, stackTrace);
+ }
+
+ private String toStackTraceString(StackTraceElement[] stackTraceElements) {
+ if (stackTraceElements == null) {
+ return "";
+ }
+ StringBuilder stringBuilder = new StringBuilder();
+ boolean skip = true;
+ for (int i = 0; i < stackTraceElements.length; i++) {
+ if (stackTraceElements[i].toString().contains(
+ AccessibilityTracing.class.getSimpleName())) {
+ skip = false;
+ } else if (!skip) {
+ stringBuilder.append(stackTraceElements[i].toString()).append("\n");
+ }
+ }
+ return stringBuilder.toString();
+ }
+
+ /**
+ * Write the current state to the buffer
+ */
+ private void log(String where, String callingParams, byte[] a11yDump, int callingUid,
+ StackTraceElement[] stackTrace) {
+ SimpleDateFormat fm = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = SystemClock.elapsedRealtimeNanos();
+ args.arg2 = fm.format(new Date()).toString();
+ args.arg3 = where;
+ args.arg4 = Process.myPid() + ":" + Application.getProcessName();
+ args.arg5 = Thread.currentThread().getId() + ":" + Thread.currentThread().getName();
+ args.arg6 = callingUid;
+ args.arg7 = callingParams;
+ args.arg8 = stackTrace;
+ args.arg9 = a11yDump;
+ mHandler.obtainMessage(LogHandler.MESSAGE_LOG_TRACE_ENTRY, args).sendToTarget();
+ }
+
+ /**
+ * Writes the trace buffer to new file for the bugreport.
+ */
+ void writeTraceToFile() {
+ mHandler.sendEmptyMessage(LogHandler.MESSAGE_WRITE_FILE);
+ }
+
+ private class LogHandler extends Handler {
+ public static final int MESSAGE_LOG_TRACE_ENTRY = 1;
+ public static final int MESSAGE_WRITE_FILE = 2;
+
+ LogHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case MESSAGE_LOG_TRACE_ENTRY: {
+ final SomeArgs args = (SomeArgs) message.obj;
+ try {
+ ProtoOutputStream os = new ProtoOutputStream();
+ PackageManagerInternal pmInternal =
+ LocalServices.getService(PackageManagerInternal.class);
+
+ long tokenOuter = os.start(ENTRY);
+ String callingStack =
+ toStackTraceString((StackTraceElement[]) args.arg8);
+
+ os.write(ELAPSED_REALTIME_NANOS, (long) args.arg1);
+ os.write(CALENDAR_TIME, (String) args.arg2);
+ os.write(WHERE, (String) args.arg3);
+ os.write(PROCESS_NAME, (String) args.arg4);
+ os.write(THREAD_ID_NAME, (String) args.arg5);
+ os.write(CALLING_PKG, pmInternal.getNameForUid((int) args.arg6));
+ os.write(CALLING_PARAMS, (String) args.arg7);
+ os.write(CALLING_STACKS, callingStack);
+ os.write(ACCESSIBILITY_SERVICE, (byte[]) args.arg9);
+
+ long tokenInner = os.start(WINDOW_MANAGER_SERVICE);
+ synchronized (mService.mGlobalLock) {
+ mService.dumpDebugLocked(os, WindowTraceLogLevel.ALL);
+ }
+ os.end(tokenInner);
+
+ os.end(tokenOuter);
+ synchronized (mLock) {
+ mBuffer.add(os);
+ }
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception while tracing state", e);
+ }
+ break;
+ }
+ case MESSAGE_WRITE_FILE: {
+ synchronized (mLock) {
+ writeTraceToFileInternal();
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Writes the trace buffer to disk.
+ */
+ private void writeTraceToFileInternal() {
+ try {
+ ProtoOutputStream proto = new ProtoOutputStream();
+ proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
+ mBuffer.writeTraceToFile(mTraceFile, proto);
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to write buffer to file", e);
+ }
+ }
+ }
+
}
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 6bca4843e009..3a0eb397d210 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -978,6 +978,7 @@ class ActivityMetricsLogger {
final TransitionInfoSnapshot infoSnapshot =
new TransitionInfoSnapshot(info, r, (int) startupTimeMs);
BackgroundThread.getHandler().post(() -> logAppFullyDrawn(infoSnapshot));
+ mLastTransitionInfo.remove(r);
if (!info.isInterestingToLoggerAndObserver()) {
return infoSnapshot;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index f29b57ff9305..ccb349b9c5ab 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -6528,7 +6528,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
// Allowing closing {@link ActivityRecord} to participate can lead to an Activity in another
// task being started in the wrong orientation during the transition.
if (!getDisplayContent().mClosingApps.contains(this)
- && (isVisible() || getDisplayContent().mOpeningApps.contains(this))) {
+ && (isVisibleRequested() || getDisplayContent().mOpeningApps.contains(this))) {
return mOrientation;
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 2d6e9b2c68c5..4bcef408d9a0 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -130,6 +130,7 @@ import android.app.ActivityTaskManager;
import android.app.ActivityTaskManager.RootTaskInfo;
import android.app.ActivityThread;
import android.app.AlertDialog;
+import android.app.AnrController;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.Dialog;
@@ -494,6 +495,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
*/
private volatile long mLastStopAppSwitchesTime;
+ private final List<AnrController> mAnrController = new ArrayList<>();
IActivityController mController = null;
boolean mControllerIsAMonkey = false;
@@ -2058,6 +2060,40 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
return mAppSwitchesAllowed;
}
+ /** Register an {@link AnrController} to control the ANR dialog behavior */
+ public void registerAnrController(AnrController controller) {
+ synchronized (mGlobalLock) {
+ mAnrController.add(controller);
+ }
+ }
+
+ /** Unregister an {@link AnrController} */
+ public void unregisterAnrController(AnrController controller) {
+ synchronized (mGlobalLock) {
+ mAnrController.remove(controller);
+ }
+ }
+
+ /** @return the max ANR delay from all registered {@link AnrController} instances */
+ public long getMaxAnrDelayMillis(ApplicationInfo info) {
+ if (info == null || info.packageName == null) {
+ return 0;
+ }
+
+ final ArrayList<AnrController> controllers;
+ synchronized (mGlobalLock) {
+ controllers = new ArrayList<>(mAnrController);
+ }
+
+ final String packageName = info.packageName;
+ long maxDelayMs = 0;
+ for (AnrController controller : controllers) {
+ maxDelayMs = Math.max(maxDelayMs, controller.getAnrDelayMillis(packageName, info.uid));
+ }
+ maxDelayMs = Math.max(maxDelayMs, 0);
+ return maxDelayMs;
+ }
+
@Override
public void setActivityController(IActivityController controller, boolean imAMonkey) {
mAmInternal.enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 4575cf7e9060..9ca7eca07dc6 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -724,8 +724,7 @@ public class AppTransitionController {
final AccessibilityController accessibilityController =
mDisplayContent.mWmService.mAccessibilityController;
if (accessibilityController != null) {
- accessibilityController.onAppWindowTransitionLocked(
- mDisplayContent.getDisplayId(), transit);
+ accessibilityController.onAppWindowTransition(mDisplayContent.getDisplayId(), transit);
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 3ab79525de97..112fe526f0a8 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -685,6 +685,10 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
*/
private boolean mInEnsureActivitiesVisible = false;
+ // Used to indicate that the movement of child tasks to top will not move the display to top as
+ // well and thus won't change the top resumed / focused record
+ boolean mDontMoveToTop;
+
private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
WindowStateAnimator winAnimator = w.mWinAnimator;
final ActivityRecord activity = w.mActivityRecord;
@@ -948,7 +952,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
final ActivityRecord activity = w.mActivityRecord;
- if (activity != null) {
+ if (activity != null && activity.isVisibleRequested()) {
activity.updateLetterboxSurface(w);
final boolean updateAllDrawn = activity.updateDrawnWindowStates(w);
if (updateAllDrawn && !mTmpUpdateAllDrawn.contains(activity)) {
@@ -1226,7 +1230,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (mWmService.mAccessibilityController != null) {
final int prevDisplayId = prevDc != null ? prevDc.getDisplayId() : INVALID_DISPLAY;
- mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked(prevDisplayId,
+ mWmService.mAccessibilityController.onSomeWindowResizedOrMoved(prevDisplayId,
getDisplayId());
}
}
@@ -1447,7 +1451,9 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
config = new Configuration();
computeScreenConfiguration(config);
- } else if (currentConfig != null) {
+ } else if (currentConfig != null
+ // If waiting for a remote rotation, don't prematurely update configuration.
+ && !mDisplayRotation.isWaitingForRemoteRotation()) {
// No obvious action we need to take, but if our current state mismatches the
// activity manager's, update it, disregarding font scale, which should remain set
// to the value of the previous configuration.
@@ -1850,7 +1856,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
if (mWmService.mAccessibilityController != null) {
- mWmService.mAccessibilityController.onRotationChangedLocked(this);
+ mWmService.mAccessibilityController.onRotationChanged(this);
}
}
@@ -3400,7 +3406,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
void updateAccessibilityOnWindowFocusChanged(AccessibilityController accessibilityController) {
- accessibilityController.onWindowFocusChangedNotLocked(getDisplayId());
+ accessibilityController.onWindowFocusChangedNot(getDisplayId());
}
private static void onWindowFocusChanged(WindowState oldFocus, WindowState newFocus) {
@@ -4963,7 +4969,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
if (!mLocationInParentWindow.equals(x, y)) {
mLocationInParentWindow.set(x, y);
if (mWmService.mAccessibilityController != null) {
- mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked(mDisplayId);
+ mWmService.mAccessibilityController.onSomeWindowResizedOrMoved(mDisplayId);
}
notifyLocationInParentDisplayChanged();
}
@@ -5960,36 +5966,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
}
}
- /**
- * Returns the number of window tokens without surface on this display. A {@link WindowToken}
- * won't have its {@link SurfaceControl} until a window is added to a {@link WindowToken}.
- * The purpose of this method is to accumulate non-window containing {@link WindowToken}s and
- * limit the usage if the count exceeds a number.
- *
- * @param callingUid app calling uid
- * @return the number of window tokens without surface on this display
- * @see WindowToken#addWindow(WindowState)
- */
- int getWindowTokensWithoutSurfaceCount(int callingUid) {
- List<WindowToken> tokens = new ArrayList<>(mTokenMap.values());
- int count = 0;
- for (int i = tokens.size() - 1; i >= 0; i--) {
- final WindowToken token = tokens.get(i);
- if (callingUid != token.getOwnerUid()) {
- continue;
- }
- // Skip if token is an Activity
- if (token.asActivityRecord() != null) {
- continue;
- }
- if (token.mSurfaceControl != null) {
- continue;
- }
- count++;
- }
- return count;
- }
-
MagnificationSpec getMagnificationSpec() {
return mMagnificationSpec;
}
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 48e4df7a57ce..35611c055ea5 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -481,12 +481,12 @@ public class DisplayRotation {
mRotation = rotation;
+ mDisplayContent.setLayoutNeeded();
+
mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
mService.mH.sendNewMessageDelayed(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT,
mDisplayContent, WINDOW_FREEZE_TIMEOUT_DURATION);
- mDisplayContent.setLayoutNeeded();
-
if (shouldRotateSeamlessly(oldRotation, rotation, forceUpdate)) {
// The screen rotation animation uses a screenshot to freeze the screen while windows
// resize underneath. When we are rotating seamlessly, we allow the elements to
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index b82fdd237f2b..6d5abe1e2f31 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -16,11 +16,11 @@
package com.android.server.wm;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
+import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
import static android.view.WindowManager.REMOVE_CONTENT_MODE_DESTROY;
import static android.view.WindowManager.REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY;
import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
-import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
-import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
import static com.android.server.wm.DisplayContent.FORCE_SCALING_MODE_AUTO;
import static com.android.server.wm.DisplayContent.FORCE_SCALING_MODE_DISABLED;
@@ -196,6 +196,14 @@ class DisplayWindowSettings {
mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
}
+ void setDontMoveToTop(DisplayContent dc, boolean dontMoveToTop) {
+ DisplayInfo displayInfo = dc.getDisplayInfo();
+ SettingsProvider.SettingsEntry overrideSettings =
+ mSettingsProvider.getSettings(displayInfo);
+ overrideSettings.mDontMoveToTop = dontMoveToTop;
+ mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
+ }
+
boolean shouldShowSystemDecorsLocked(DisplayContent dc) {
if (dc.getDisplayId() == Display.DEFAULT_DISPLAY) {
// Default display should show system decors.
@@ -274,6 +282,10 @@ class DisplayWindowSettings {
final int forcedScalingMode = settings.mForcedScalingMode != null
? settings.mForcedScalingMode : FORCE_SCALING_MODE_AUTO;
dc.mDisplayScalingDisabled = forcedScalingMode == FORCE_SCALING_MODE_DISABLED;
+
+ boolean dontMoveToTop = settings.mDontMoveToTop != null
+ ? settings.mDontMoveToTop : false;
+ dc.mDontMoveToTop = dontMoveToTop;
}
/**
@@ -358,6 +370,8 @@ class DisplayWindowSettings {
Boolean mIgnoreOrientationRequest;
@Nullable
Boolean mIgnoreDisplayCutout;
+ @Nullable
+ Boolean mDontMoveToTop;
SettingsEntry() {}
@@ -432,6 +446,10 @@ class DisplayWindowSettings {
mIgnoreDisplayCutout = other.mIgnoreDisplayCutout;
changed = true;
}
+ if (other.mDontMoveToTop != mDontMoveToTop) {
+ mDontMoveToTop = other.mDontMoveToTop;
+ changed = true;
+ }
return changed;
}
@@ -515,6 +533,11 @@ class DisplayWindowSettings {
mIgnoreDisplayCutout = delta.mIgnoreDisplayCutout;
changed = true;
}
+ if (delta.mDontMoveToTop != null
+ && delta.mDontMoveToTop != mDontMoveToTop) {
+ mDontMoveToTop = delta.mDontMoveToTop;
+ changed = true;
+ }
return changed;
}
@@ -531,7 +554,8 @@ class DisplayWindowSettings {
&& mImePolicy == null
&& mFixedToUserRotation == null
&& mIgnoreOrientationRequest == null
- && mIgnoreDisplayCutout == null;
+ && mIgnoreDisplayCutout == null
+ && mDontMoveToTop == null;
}
@Override
@@ -553,7 +577,8 @@ class DisplayWindowSettings {
&& Objects.equals(mImePolicy, that.mImePolicy)
&& Objects.equals(mFixedToUserRotation, that.mFixedToUserRotation)
&& Objects.equals(mIgnoreOrientationRequest, that.mIgnoreOrientationRequest)
- && Objects.equals(mIgnoreDisplayCutout, that.mIgnoreDisplayCutout);
+ && Objects.equals(mIgnoreDisplayCutout, that.mIgnoreDisplayCutout)
+ && Objects.equals(mDontMoveToTop, that.mDontMoveToTop);
}
@Override
@@ -561,7 +586,8 @@ class DisplayWindowSettings {
return Objects.hash(mWindowingMode, mUserRotationMode, mUserRotation, mForcedWidth,
mForcedHeight, mForcedDensity, mForcedScalingMode, mRemoveContentMode,
mShouldShowWithInsecureKeyguard, mShouldShowSystemDecors, mImePolicy,
- mFixedToUserRotation, mIgnoreOrientationRequest, mIgnoreDisplayCutout);
+ mFixedToUserRotation, mIgnoreOrientationRequest, mIgnoreDisplayCutout,
+ mDontMoveToTop);
}
@Override
@@ -581,6 +607,7 @@ class DisplayWindowSettings {
+ ", mFixedToUserRotation=" + mFixedToUserRotation
+ ", mIgnoreOrientationRequest=" + mIgnoreOrientationRequest
+ ", mIgnoreDisplayCutout=" + mIgnoreDisplayCutout
+ + ", mDontMoveToTop=" + mDontMoveToTop
+ '}';
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
index 5f3ab43eca7c..737f8107f83f 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
@@ -405,6 +405,9 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
"ignoreOrientationRequest", null /* defaultValue */);
settingsEntry.mIgnoreDisplayCutout = getBooleanAttribute(parser,
"ignoreDisplayCutout", null /* defaultValue */);
+ settingsEntry.mDontMoveToTop = getBooleanAttribute(parser,
+ "dontMoveToTop", null /* defaultValue */);
+
fileData.mSettings.put(name, settingsEntry);
}
XmlUtils.skipCurrentTag(parser);
@@ -496,6 +499,10 @@ class DisplayWindowSettingsProvider implements SettingsProvider {
out.attributeBoolean(null, "ignoreDisplayCutout",
settingsEntry.mIgnoreDisplayCutout);
}
+ if (settingsEntry.mDontMoveToTop != null) {
+ out.attributeBoolean(null, "dontMoveToTop",
+ settingsEntry.mDontMoveToTop);
+ }
out.endTag(null, "display");
}
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 803bec8941a8..de4bdaa57efa 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -47,7 +47,7 @@ public class DockedStackDividerController {
mTouchRegion.set(touchRegion);
// We need to report touchable region changes to accessibility.
if (mDisplayContent.mWmService.mAccessibilityController != null) {
- mDisplayContent.mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked(
+ mDisplayContent.mWmService.mAccessibilityController.onSomeWindowResizedOrMoved(
mDisplayContent.getDisplayId());
}
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 07769aeff679..2c97f783e14d 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -847,8 +847,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
Slog.i(TAG,
">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
}
- // Send any pending task-info changes that were queued-up during a layout deferment
- mWmService.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applySurfaceChanges");
mWmService.openSurfaceTransaction();
try {
@@ -865,6 +863,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
}
+ // Send any pending task-info changes that were queued-up during a layout deferment
+ mWmService.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
mWmService.mAnimator.executeAfterPrepareSurfacesRunnables();
checkAppTransitionReady(surfacePlacer);
diff --git a/services/core/java/com/android/server/wm/ShellRoot.java b/services/core/java/com/android/server/wm/ShellRoot.java
index 62c0527dfe1b..0902948bf559 100644
--- a/services/core/java/com/android/server/wm/ShellRoot.java
+++ b/services/core/java/com/android/server/wm/ShellRoot.java
@@ -191,7 +191,7 @@ public class ShellRoot {
}
}
if (mDisplayContent.mWmService.mAccessibilityController != null) {
- mDisplayContent.mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked(
+ mDisplayContent.mWmService.mAccessibilityController.onSomeWindowResizedOrMoved(
mDisplayContent.getDisplayId());
}
}
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index 63732d8d4bdc..40248c43fe5d 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -404,7 +404,11 @@ final class TaskDisplayArea extends DisplayArea<WindowContainer> {
}
// We don't allow untrusted display to top when root task moves to top,
// until user tapping this display to change display position as top intentionally.
- if (!mDisplayContent.isTrusted() && !getParent().isOnTop()) {
+ //
+ // Displays with {@code mDontMoveToTop} property set to {@code true} won't be
+ // allowed to top neither.
+ if ((!mDisplayContent.isTrusted() || mDisplayContent.mDontMoveToTop)
+ && !getParent().isOnTop()) {
includingParents = false;
}
final int targetPosition = findPositionForRootTask(position, child, false /* adding */);
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index f572e8e2f0aa..43303d4a5d7e 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -17,7 +17,6 @@
package com.android.server.wm;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.os.Process.INVALID_UID;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
@@ -51,7 +50,7 @@ class WallpaperWindowToken extends WindowToken {
WallpaperWindowToken(WindowManagerService service, IBinder token, boolean explicit,
DisplayContent dc, boolean ownerCanManageAppTokens, @Nullable Bundle options) {
- super(service, token, TYPE_WALLPAPER, explicit, dc, ownerCanManageAppTokens, INVALID_UID,
+ super(service, token, TYPE_WALLPAPER, explicit, dc, ownerCanManageAppTokens,
false /* roundedCornerOverlay */, false /* fromClientToken */, options);
dc.mWallpaperController.addWallpaperToken(this);
setWindowingMode(WINDOWING_MODE_FULLSCREEN);
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 1a0e16b9c771..91a6664e0b36 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -164,7 +164,7 @@ public class WindowAnimator {
dc.checkAppWindowsReadyToShow();
if (accessibilityController != null) {
- accessibilityController.drawMagnifiedRegionBorderIfNeededLocked(displayId,
+ accessibilityController.drawMagnifiedRegionBorderIfNeeded(displayId,
mTransaction);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index eed3299cc93d..bb04ace423c2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -23,6 +23,7 @@ import android.content.Context;
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.display.DisplayManagerInternal;
+import android.os.Bundle;
import android.os.IBinder;
import android.view.Display;
import android.view.IInputFilter;
@@ -48,6 +49,41 @@ import java.util.List;
public abstract class WindowManagerInternal {
/**
+ * Interface for accessibility features implemented by AccessibilityController inside
+ * WindowManager.
+ */
+ public interface AccessibilityControllerInternal {
+ /**
+ * Enable the accessibility trace logging.
+ */
+ void startTrace();
+
+ /**
+ * Disable the accessibility trace logging.
+ */
+ void stopTrace();
+
+ /**
+ * Is trace enabled or not.
+ */
+ boolean isEnabled();
+
+ /**
+ * Add an accessibility trace entry.
+ *
+ * @param where A string to identify this log entry, which can be used to filter/search
+ * through the tracing file.
+ * @param callingParams The parameters for the method to be logged.
+ * @param a11yDump The proto byte array for a11y state when the entry is generated.
+ * @param callingUid The calling uid.
+ * @param stackTrace The stack trace, null if not needed.
+ */
+ void logTrace(
+ String where, String callingParams, byte[] a11yDump, int callingUid,
+ StackTraceElement[] stackTrace);
+ }
+
+ /**
* Interface to receive a callback when the windows reported for
* accessibility changed.
*/
@@ -224,6 +260,11 @@ public abstract class WindowManagerInternal {
}
/**
+ * Request the interface to access features implemented by AccessibilityController.
+ */
+ public abstract AccessibilityControllerInternal getAccessibilityController();
+
+ /**
* Request that the window manager call
* {@link DisplayManagerInternal#performTraversalInTransactionFromWindowManager}
* within a surface transaction at a later time.
@@ -368,8 +409,10 @@ public abstract class WindowManagerInternal {
* @param token The token to add.
* @param type The window type.
* @param displayId The display to add the token to.
+ * @param options A bundle used to pass window-related options.
*/
- public abstract void addWindowToken(android.os.IBinder token, int type, int displayId);
+ public abstract void addWindowToken(@NonNull android.os.IBinder token, int type, int displayId,
+ @Nullable Bundle options);
/**
* Removes a window token.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8965cab0b725..a41761f529be 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -23,7 +23,6 @@ import static android.Manifest.permission.MANAGE_APP_TOKENS;
import static android.Manifest.permission.READ_FRAME_BUFFER;
import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS;
import static android.Manifest.permission.RESTRICTED_VR_ACCESS;
-import static android.Manifest.permission.STATUS_BAR_SERVICE;
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
@@ -35,7 +34,6 @@ import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEME
import static android.content.pm.PackageManager.FEATURE_PC;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.IInputConstants.DEFAULT_DISPATCHING_TIMEOUT_MILLIS;
-import static android.os.Process.INVALID_UID;
import static android.os.Process.SYSTEM_UID;
import static android.os.Process.myPid;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
@@ -82,7 +80,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.ADD_TOO_MANY_TOKENS;
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;
@@ -457,12 +454,6 @@ public class WindowManagerService extends IWindowManager.Stub
private static final int ANIMATION_COMPLETED_TIMEOUT_MS = 5000;
- /** The maximum count of window tokens without surface that an app can register. */
- private static final int MAXIMUM_WINDOW_TOKEN_COUNT_WITHOUT_SURFACE = 5;
-
- /** System UI can create more window context... */
- private static final int SYSTEM_UI_MULTIPLIER = 2;
-
/**
* Override of task letterbox aspect ratio that is set via ADB with
* set-task-letterbox-aspect-ratio or via {@link
@@ -1610,7 +1601,7 @@ public class WindowManagerService extends IWindowManager.Stub
final Bundle options = mWindowContextListenerController
.getOptions(windowContextToken);
token = new WindowToken(this, binder, type, false /* persistOnEmpty */,
- displayContent, session.mCanAddInternalSystemWindow, callingUid,
+ displayContent, session.mCanAddInternalSystemWindow,
isRoundedCornerOverlay, true /* fromClientToken */, options);
} else {
final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
@@ -2176,6 +2167,7 @@ public class WindowManagerService extends IWindowManager.Stub
void setInsetsWindow(Session session, IWindow client, int touchableInsets, Rect contentInsets,
Rect visibleInsets, Region touchableRegion) {
+ int uid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -2201,8 +2193,8 @@ public class WindowManagerService extends IWindowManager.Stub
// We need to report touchable region changes to accessibility.
if (mAccessibilityController != null) {
- mAccessibilityController.onSomeWindowResizedOrMovedLocked(
- w.getDisplayContent().getDisplayId());
+ mAccessibilityController.onSomeWindowResizedOrMovedWithCallingUid(
+ uid, w.getDisplayContent().getDisplayId());
}
}
}
@@ -2216,7 +2208,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (mAccessibilityController != null) {
WindowState window = mWindowMap.get(token);
if (window != null) {
- mAccessibilityController.onRectangleOnScreenRequestedLocked(
+ mAccessibilityController.onRectangleOnScreenRequested(
window.getDisplayId(), rectangle);
}
}
@@ -2319,8 +2311,8 @@ public class WindowManagerService extends IWindowManager.Stub
if (((attrChanges & LayoutParams.ACCESSIBILITY_TITLE_CHANGED) != 0)
&& (mAccessibilityController != null)) {
// No move or resize, but the controller checks for title changes as well
- mAccessibilityController.onSomeWindowResizedOrMovedLocked(
- win.getDisplayContent().getDisplayId());
+ mAccessibilityController.onSomeWindowResizedOrMovedWithCallingUid(
+ uid, win.getDisplayContent().getDisplayId());
}
if ((privateFlagChanges & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
@@ -2620,7 +2612,7 @@ public class WindowManagerService extends IWindowManager.Stub
win.destroySurface(false, stopped);
}
if (mAccessibilityController != null) {
- mAccessibilityController.onWindowTransitionLocked(win, transit);
+ mAccessibilityController.onWindowTransition(win, transit);
}
return focusMayChange;
@@ -2713,91 +2705,36 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public void addWindowToken(IBinder binder, int type, int displayId) {
- addWindowTokenWithOptions(binder, type, displayId, null /* options */,
- null /* packageName */, false /* fromClientToken */);
- }
-
- @Override
- public int addWindowTokenWithOptions(IBinder binder, int type, int displayId, Bundle options,
- String packageName) {
- if (tokenCountExceed()) {
- return ADD_TOO_MANY_TOKENS;
+ public void addWindowToken(@NonNull IBinder binder, int type, int displayId,
+ @Nullable Bundle options) {
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "addWindowToken()")) {
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
- return addWindowTokenWithOptions(binder, type, displayId, options, packageName,
- true /* fromClientToken */);
- }
- private boolean tokenCountExceed() {
- final int callingUid = Binder.getCallingUid();
- // Don't check if caller is from system server.
- if (callingUid == myPid()) {
- return false;
- }
- final int limit =
- (checkCallingPermission(STATUS_BAR_SERVICE, "addWindowTokenWithOptions"))
- ? MAXIMUM_WINDOW_TOKEN_COUNT_WITHOUT_SURFACE * SYSTEM_UI_MULTIPLIER
- : MAXIMUM_WINDOW_TOKEN_COUNT_WITHOUT_SURFACE;
synchronized (mGlobalLock) {
- int[] count = new int[1];
- mRoot.forAllDisplays(d -> count[0] += d.getWindowTokensWithoutSurfaceCount(callingUid));
- return count[0] >= limit;
- }
- }
-
- private int addWindowTokenWithOptions(IBinder binder, int type, int displayId, Bundle options,
- String packageName, boolean fromClientToken) {
- final boolean callerCanManageAppTokens =
- checkCallingPermission(MANAGE_APP_TOKENS, "addWindowToken()");
- // WindowContext users usually don't hold MANAGE_APP_TOKEN permission. Check permissions
- // by checkAddPermission.
- if (!callerCanManageAppTokens) {
- final int res = mPolicy.checkAddPermission(type, false /* isRoundedCornerOverlay */,
- packageName, new int[1]);
- if (res != ADD_OKAY) {
- return res;
+ final DisplayContent dc = getDisplayContentOrCreate(displayId, null /* token */);
+ if (dc == null) {
+ ProtoLog.w(WM_ERROR, "addWindowToken: Attempted to add token: %s"
+ + " for non-exiting displayId=%d", binder, displayId);
+ return;
}
- }
-
- final int callingUid = Binder.getCallingUid();
- final long origId = Binder.clearCallingIdentity();
- try {
- synchronized (mGlobalLock) {
- if (!callerCanManageAppTokens) {
- if (packageName == null || !unprivilegedAppCanCreateTokenWith(
- null /* parentWindow */, callingUid, type, type, binder,
- packageName)) {
- throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
- }
- }
- final DisplayContent dc = getDisplayContentOrCreate(displayId, null /* token */);
- if (dc == null) {
- ProtoLog.w(WM_ERROR, "addWindowToken: Attempted to add token: %s"
- + " for non-exiting displayId=%d", binder, displayId);
- return WindowManagerGlobal.ADD_INVALID_DISPLAY;
- }
-
- WindowToken token = dc.getWindowToken(binder);
- if (token != null) {
- ProtoLog.w(WM_ERROR, "addWindowToken: Attempted to add binder token: %s"
- + " for already created window token: %s"
- + " displayId=%d", binder, token, displayId);
- return WindowManagerGlobal.ADD_DUPLICATE_ADD;
- }
- // TODO(window-container): Clean up dead tokens
- if (type == TYPE_WALLPAPER) {
- new WallpaperWindowToken(this, binder, true, dc, callerCanManageAppTokens,
- options);
- } else {
- new WindowToken(this, binder, type, true, dc, callerCanManageAppTokens,
- callingUid, false /* roundedCornerOverlay */, fromClientToken, options);
- }
+ WindowToken token = dc.getWindowToken(binder);
+ if (token != null) {
+ ProtoLog.w(WM_ERROR, "addWindowToken: Attempted to add binder token: %s"
+ + " for already created window token: %s"
+ + " displayId=%d", binder, token, displayId);
+ return;
+ }
+ if (type == TYPE_WALLPAPER) {
+ new WallpaperWindowToken(this, binder, true, dc,
+ true /* ownerCanManageAppTokens */, options);
+ } else {
+ new WindowToken(this, binder, type, true /* persistOnEmpty */, dc,
+ true /* ownerCanManageAppTokens */, false /* roundedCornerOverlay */,
+ false /* fromClientToken */, options);
}
- } finally {
- Binder.restoreCallingIdentity(origId);
}
- return WindowManagerGlobal.ADD_OKAY;
}
/**
@@ -2877,38 +2814,26 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void removeWindowToken(IBinder binder, int displayId) {
- final boolean callerCanManageAppTokens =
- checkCallingPermission(MANAGE_APP_TOKENS, "removeWindowToken()");
- final WindowToken windowToken;
- synchronized (mGlobalLock) {
- windowToken = mRoot.getWindowToken(binder);
- }
- if (windowToken == null) {
- ProtoLog.w(WM_ERROR,
- "removeWindowToken: Attempted to remove non-existing token: %s", binder);
- return;
- }
- final int callingUid = Binder.getCallingUid();
-
- // If MANAGE_APP_TOKEN permission is not held(usually from WindowContext), callers can only
- // remove the window tokens which they added themselves.
- if (!callerCanManageAppTokens && (windowToken.getOwnerUid() == INVALID_UID
- || callingUid != windowToken.getOwnerUid())) {
- throw new SecurityException("removeWindowToken: Requires MANAGE_APP_TOKENS permission"
- + " to remove token owned by another uid");
+ if (!checkCallingPermission(MANAGE_APP_TOKENS, "removeWindowToken()")) {
+ throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
}
-
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
final DisplayContent dc = mRoot.getDisplayContent(displayId);
+
if (dc == null) {
ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s"
+ " for non-exiting displayId=%d", binder, displayId);
return;
}
-
- dc.removeWindowToken(binder);
+ final WindowToken token = dc.removeWindowToken(binder);
+ if (token == null) {
+ ProtoLog.w(WM_ERROR,
+ "removeWindowToken: Attempted to remove non-existing token: %s",
+ binder);
+ return;
+ }
dc.getInputMonitor().updateInputWindowsLw(true /*force*/);
}
} finally {
@@ -7151,6 +7076,7 @@ public class WindowManagerService extends IWindowManager.Stub
checkCallerOwnsDisplay(displayId);
synchronized (mGlobalLock) {
+ int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
final WindowState win = windowForClientLocked(null, client, false);
@@ -7162,8 +7088,8 @@ public class WindowManagerService extends IWindowManager.Stub
// Notifies AccessibilityController to re-compute the window observer of
// this embedded display
if (mAccessibilityController != null) {
- mAccessibilityController.handleWindowObserverOfEmbeddedDisplayLocked(displayId,
- win);
+ mAccessibilityController.handleWindowObserverOfEmbeddedDisplay(
+ displayId, win, uid);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -7529,6 +7455,12 @@ public class WindowManagerService extends IWindowManager.Stub
private final class LocalService extends WindowManagerInternal {
@Override
+ public AccessibilityControllerInternal getAccessibilityController() {
+ return AccessibilityController.getAccessibilityControllerInternal(
+ WindowManagerService.this);
+ }
+
+ @Override
public void clearSnapshotCache() {
synchronized (mGlobalLock) {
mTaskSnapshotController.clearSnapshotCache();
@@ -7546,7 +7478,7 @@ public class WindowManagerService extends IWindowManager.Stub
public void setMagnificationSpec(int displayId, MagnificationSpec spec) {
synchronized (mGlobalLock) {
if (mAccessibilityController != null) {
- mAccessibilityController.setMagnificationSpecLocked(displayId, spec);
+ mAccessibilityController.setMagnificationSpec(displayId, spec);
} else {
throw new IllegalStateException("Magnification callbacks not set!");
}
@@ -7557,7 +7489,7 @@ public class WindowManagerService extends IWindowManager.Stub
public void setForceShowMagnifiableBounds(int displayId, boolean show) {
synchronized (mGlobalLock) {
if (mAccessibilityController != null) {
- mAccessibilityController.setForceShowMagnifiableBoundsLocked(displayId, show);
+ mAccessibilityController.setForceShowMagnifiableBounds(displayId, show);
} else {
throw new IllegalStateException("Magnification callbacks not set!");
}
@@ -7568,8 +7500,7 @@ public class WindowManagerService extends IWindowManager.Stub
public void getMagnificationRegion(int displayId, @NonNull Region magnificationRegion) {
synchronized (mGlobalLock) {
if (mAccessibilityController != null) {
- mAccessibilityController.getMagnificationRegionLocked(displayId,
- magnificationRegion);
+ mAccessibilityController.getMagnificationRegion(displayId, magnificationRegion);
} else {
throw new IllegalStateException("Magnification callbacks not set!");
}
@@ -7585,7 +7516,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
MagnificationSpec spec = null;
if (mAccessibilityController != null) {
- spec = mAccessibilityController.getMagnificationSpecForWindowLocked(windowState);
+ spec = mAccessibilityController.getMagnificationSpecForWindow(windowState);
}
if ((spec == null || spec.isNop()) && windowState.mGlobalScale == 1.0f) {
return null;
@@ -7607,9 +7538,9 @@ public class WindowManagerService extends IWindowManager.Stub
mAccessibilityController = new AccessibilityController(
WindowManagerService.this);
}
- boolean result = mAccessibilityController.setMagnificationCallbacksLocked(
+ boolean result = mAccessibilityController.setMagnificationCallbacks(
displayId, callbacks);
- if (!mAccessibilityController.hasCallbacksLocked()) {
+ if (!mAccessibilityController.hasCallbacks()) {
mAccessibilityController = null;
}
return result;
@@ -7625,9 +7556,9 @@ public class WindowManagerService extends IWindowManager.Stub
WindowManagerService.this);
}
final boolean result =
- mAccessibilityController.setWindowsForAccessibilityCallbackLocked(
+ mAccessibilityController.setWindowsForAccessibilityCallback(
displayId, callback);
- if (!mAccessibilityController.hasCallbacksLocked()) {
+ if (!mAccessibilityController.hasCallbacks()) {
mAccessibilityController = null;
}
return result;
@@ -7716,8 +7647,9 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public void addWindowToken(IBinder token, int type, int displayId) {
- WindowManagerService.this.addWindowToken(token, type, displayId);
+ public void addWindowToken(IBinder token, int type, int displayId,
+ @Nullable Bundle options) {
+ WindowManagerService.this.addWindowToken(token, type, displayId, options);
}
@Override
@@ -7825,7 +7757,7 @@ public class WindowManagerService extends IWindowManager.Stub
accessibilityController = mAccessibilityController;
}
if (accessibilityController != null) {
- accessibilityController.performComputeChangedWindowsNotLocked(displayId, true);
+ accessibilityController.performComputeChangedWindowsNot(displayId, true);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 89cb163d5a55..fc1c7edb234c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1721,7 +1721,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
@Override
boolean isVisibleRequested() {
- return isVisible();
+ return isVisible() && (mActivityRecord == null || mActivityRecord.isVisibleRequested());
}
/**
@@ -2020,7 +2020,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
final int winTransit = TRANSIT_EXIT;
mWinAnimator.applyAnimationLocked(winTransit, false /* isEntrance */);
if (accessibilityController != null) {
- accessibilityController.onWindowTransitionLocked(this, winTransit);
+ accessibilityController.onWindowTransition(this, winTransit);
}
}
setDisplayLayoutNeeded();
@@ -2034,7 +2034,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (isVisibleNow()) {
mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false);
if (mWmService.mAccessibilityController != null) {
- mWmService.mAccessibilityController.onWindowTransitionLocked(this, TRANSIT_EXIT);
+ mWmService.mAccessibilityController.onWindowTransition(this, TRANSIT_EXIT);
}
changed = true;
if (displayContent != null) {
@@ -2112,7 +2112,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
if (mWmService.mAccessibilityController != null) {
- mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked(getDisplayId());
+ mWmService.mAccessibilityController.onSomeWindowResizedOrMoved(getDisplayId());
}
updateLocationInParentDisplayIfNeeded();
@@ -2132,7 +2132,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
&& !mAnimatingExit
&& (mWindowFrames.mRelFrame.top != mWindowFrames.mLastRelFrame.top
|| mWindowFrames.mRelFrame.left != mWindowFrames.mLastRelFrame.left)
- && (!mIsChildWindow || !getParentWindow().hasMoved());
+ && (!mIsChildWindow || !getParentWindow().hasMoved())
+ && !mWmService.mAtmService.getTransitionController().isCollecting();
}
boolean isObscuringDisplay() {
@@ -2345,7 +2346,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
mWmService.requestTraversal();
}
if (mWmService.mAccessibilityController != null) {
- mWmService.mAccessibilityController.onWindowTransitionLocked(this, transit);
+ mWmService.mAccessibilityController.onWindowTransition(this, transit);
}
}
final boolean isAnimating = mAnimatingExit || isAnimating(TRANSITION | PARENTS,
@@ -3635,6 +3636,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (mActivityRecord != null && mActivityRecord.isRelaunching()) {
return;
}
+ // If the activity is invisible or going invisible, don't report either since it is going
+ // away. This is likely during a transition so we want to preserve the original state.
+ if (mActivityRecord != null && !mActivityRecord.isVisibleRequested()) {
+ return;
+ }
if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.reportResized_" + getWindowTag());
@@ -3672,7 +3678,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
displayId);
if (mWmService.mAccessibilityController != null) {
- mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked(displayId);
+ mWmService.mAccessibilityController.onSomeWindowResizedOrMoved(displayId);
}
updateLocationInParentDisplayIfNeeded();
} catch (RemoteException e) {
@@ -4775,7 +4781,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return;
}
if (mWmService.mAccessibilityController != null) {
- mWmService.mAccessibilityController.onSomeWindowResizedOrMovedLocked(getDisplayId());
+ mWmService.mAccessibilityController.onSomeWindowResizedOrMoved(getDisplayId());
}
if (!isSelfOrAncestorWindowAnimatingExit()) {
@@ -5304,7 +5310,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
updateSurfacePositionNonOrganized();
// Send information to SufaceFlinger about the priority of the current window.
updateFrameRateSelectionPriorityIfNeeded();
- updateGlobalScaleIfNeeded();
+ if (isVisibleRequested()) updateGlobalScaleIfNeeded();
mWinAnimator.prepareSurfaceLocked(getSyncTransaction());
super.prepareSurfaces();
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index d164f30fde2c..2da3dda831e1 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -817,7 +817,7 @@ class WindowStateAnimator {
}
if (mService.mAccessibilityController != null) {
- mService.mAccessibilityController.onWindowTransitionLocked(mWin, transit);
+ mService.mAccessibilityController.onWindowTransition(mWin, transit);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index cd18311d7d54..c3a4609c02a1 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import static android.os.Process.INVALID_UID;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
@@ -113,8 +112,6 @@ class WindowToken extends WindowContainer<WindowState> {
*/
private final boolean mFromClientToken;
- private final int mOwnerUid;
-
/**
* Used to fix the transform of the token to be rotated to a rotation different than it's
* display. The window frames and surfaces corresponding to this token will be layouted and
@@ -205,27 +202,19 @@ class WindowToken extends WindowContainer<WindowState> {
WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
DisplayContent dc, boolean ownerCanManageAppTokens, boolean roundedCornerOverlay) {
- this(service, _token, type, persistOnEmpty, dc, ownerCanManageAppTokens, INVALID_UID,
- roundedCornerOverlay, false /* fromClientToken */);
- }
-
- WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
- DisplayContent dc, boolean ownerCanManageAppTokens, int ownerUid,
- boolean roundedCornerOverlay, boolean fromClientToken) {
- this(service, _token, type, persistOnEmpty, dc, ownerCanManageAppTokens, ownerUid,
- roundedCornerOverlay, fromClientToken, null /* options */);
+ this(service, _token, type, persistOnEmpty, dc, ownerCanManageAppTokens,
+ roundedCornerOverlay, false /* fromClientToken */, null /* options */);
}
WindowToken(WindowManagerService service, IBinder _token, int type, boolean persistOnEmpty,
- DisplayContent dc, boolean ownerCanManageAppTokens, int ownerUid,
- boolean roundedCornerOverlay, boolean fromClientToken, @Nullable Bundle options) {
+ DisplayContent dc, boolean ownerCanManageAppTokens, boolean roundedCornerOverlay,
+ boolean fromClientToken, @Nullable Bundle options) {
super(service);
token = _token;
windowType = type;
mOptions = options;
mPersistOnEmpty = persistOnEmpty;
mOwnerCanManageAppTokens = ownerCanManageAppTokens;
- mOwnerUid = ownerUid;
mRoundedCornerOverlay = roundedCornerOverlay;
mFromClientToken = fromClientToken;
if (dc != null) {
@@ -739,10 +728,6 @@ class WindowToken extends WindowContainer<WindowState> {
mRoundedCornerOverlay);
}
- int getOwnerUid() {
- return mOwnerUid;
- }
-
boolean isFromClient() {
return mFromClientToken;
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index cc7e00a43a6e..91be0564a26f 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -134,7 +134,7 @@ cc_defaults {
"android.hardware.broadcastradio@1.0",
"android.hardware.broadcastradio@1.1",
"android.hardware.contexthub@1.0",
- "android.hardware.gnss-cpp",
+ "android.hardware.gnss-V1-cpp",
"android.hardware.gnss@1.0",
"android.hardware.gnss@1.1",
"android.hardware.gnss@2.0",
@@ -147,12 +147,12 @@ cc_defaults {
"android.hardware.light@2.0",
"android.hardware.power@1.0",
"android.hardware.power@1.1",
- "android.hardware.power-cpp",
+ "android.hardware.power-V1-cpp",
"android.hardware.power.stats@1.0",
"android.hardware.power.stats-ndk_platform",
"android.hardware.thermal@1.0",
"android.hardware.tv.input@1.0",
- "android.hardware.vibrator-unstable-cpp",
+ "android.hardware.vibrator-V2-cpp",
"android.hardware.vibrator@1.0",
"android.hardware.vibrator@1.1",
"android.hardware.vibrator@1.2",
@@ -162,7 +162,7 @@ cc_defaults {
"android.frameworks.schedulerservice@1.0",
"android.frameworks.sensorservice@1.0",
"android.frameworks.stats@1.0",
- "android.system.suspend.control-cpp",
+ "android.system.suspend.control-V1-cpp",
"android.system.suspend.control.internal-cpp",
"android.system.suspend@1.0",
"service.incremental",
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index 48f8b1505d3a..59b7367102c8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -136,6 +136,8 @@ class ActiveAdmin {
private static final String TAG_PASSWORD_COMPLEXITY = "password-complexity";
private static final String TAG_ORGANIZATION_ID = "organization-id";
private static final String TAG_ENROLLMENT_SPECIFIC_ID = "enrollment-specific-id";
+ private static final String TAG_ADMIN_CAN_GRANT_SENSORS_PERMISSIONS =
+ "admin-can-grant-sensors-permissions";
private static final String ATTR_VALUE = "value";
private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification";
private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications";
@@ -277,6 +279,7 @@ class ActiveAdmin {
boolean mCommonCriteriaMode;
public String mOrganizationId;
public String mEnrollmentSpecificId;
+ public boolean mAdminCanGrantSensorsPermissions;
ActiveAdmin(DeviceAdminInfo info, boolean isParent) {
this.info = info;
@@ -543,6 +546,8 @@ class ActiveAdmin {
if (!TextUtils.isEmpty(mEnrollmentSpecificId)) {
writeTextToXml(out, TAG_ENROLLMENT_SPECIFIC_ID, mEnrollmentSpecificId);
}
+ writeAttributeValueToXml(out, TAG_ADMIN_CAN_GRANT_SENSORS_PERMISSIONS,
+ mAdminCanGrantSensorsPermissions);
}
void writeTextToXml(TypedXmlSerializer out, String tag, String text) throws IOException {
@@ -792,6 +797,9 @@ class ActiveAdmin {
Log.w(DevicePolicyManagerService.LOG_TAG,
"Missing Enrollment-specific ID.");
}
+ } else if (TAG_ADMIN_CAN_GRANT_SENSORS_PERMISSIONS.equals(tag)) {
+ mAdminCanGrantSensorsPermissions = parser.getAttributeBoolean(null, ATTR_VALUE,
+ false);
} else {
Slog.w(DevicePolicyManagerService.LOG_TAG, "Unknown admin tag: " + tag);
XmlUtils.skipCurrentTag(parser);
@@ -1143,5 +1151,8 @@ class ActiveAdmin {
pw.print("mEnrollmentSpecificId=");
pw.println(mEnrollmentSpecificId);
}
+
+ pw.print("mAdminCanGrantSensorsPermissions");
+ pw.println(mAdminCanGrantSensorsPermissions);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 160033edb093..b52347f509f8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -129,6 +129,9 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub {
FullyManagedDeviceProvisioningParams provisioningParams, String callerPackage) {
}
- public void resetDefaultCrossProfileIntentFilters(@UserIdInt int userId) {
+ public void resetDefaultCrossProfileIntentFilters(@UserIdInt int userId) {}
+
+ public boolean canAdminGrantSensorsPermissionsForUser(int userId) {
+ return false;
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
index 8b2beb22bead..8ea21ec74ad6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
@@ -46,11 +46,15 @@ public class DevicePolicyCacheImpl extends DevicePolicyCache {
@GuardedBy("mLock")
private final SparseIntArray mPermissionPolicy = new SparseIntArray();
+ @GuardedBy("mLock")
+ private final SparseBooleanArray mCanGrantSensorsPermissions = new SparseBooleanArray();
+
public void onUserRemoved(int userHandle) {
synchronized (mLock) {
mScreenCaptureDisabled.delete(userHandle);
mPasswordQuality.delete(userHandle);
mPermissionPolicy.delete(userHandle);
+ mCanGrantSensorsPermissions.delete(userHandle);
}
}
@@ -97,6 +101,21 @@ public class DevicePolicyCacheImpl extends DevicePolicyCache {
}
}
+ @Override
+ public boolean canAdminGrantSensorsPermissionsForUser(@UserIdInt int userHandle) {
+ synchronized (mLock) {
+ return mCanGrantSensorsPermissions.get(userHandle, false);
+ }
+ }
+
+ /** Sets ahmin control over permission grants for user. */
+ public void setAdminCanGrantSensorsPermissions(@UserIdInt int userHandle,
+ boolean canGrant) {
+ synchronized (mLock) {
+ mCanGrantSensorsPermissions.put(userHandle, canGrant);
+ }
+ }
+
/** Dump content */
public void dump(IndentingPrintWriter pw) {
pw.println("Device policy cache:");
@@ -104,6 +123,8 @@ public class DevicePolicyCacheImpl extends DevicePolicyCache {
pw.println("Screen capture disabled: " + mScreenCaptureDisabled.toString());
pw.println("Password quality: " + mPasswordQuality.toString());
pw.println("Permission policy: " + mPermissionPolicy.toString());
+ pw.println("Admin can grant sensors permission: "
+ + mCanGrantSensorsPermissions.toString());
pw.decreaseIndent();
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 717e77b22bdc..404b0cf8c7b8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -313,6 +313,7 @@ import com.android.server.PersistentDataBlockManagerInternal;
import com.android.server.SystemServerInitThreadPool;
import com.android.server.SystemService;
import com.android.server.devicepolicy.ActiveAdmin.TrustAgentInfo;
+import com.android.server.devicepolicy.Owners.OwnerDto;
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.pm.RestrictionsSet;
@@ -1130,6 +1131,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mSafetyChecker = new OneTimeSafetyChecker(this, operation, reason);
}
+ // Used by DevicePolicyManagerServiceShellCommand
+ List<OwnerDto> listAllOwners() {
+ Preconditions.checkCallAuthorization(
+ hasCallingOrSelfPermission(permission.MANAGE_DEVICE_ADMINS));
+
+ List<OwnerDto> owners = mOwners.listAllOwners();
+ synchronized (getLockObject()) {
+ for (int i = 0; i < owners.size(); i++) {
+ OwnerDto owner = owners.get(i);
+ owner.isAffiliated = isUserAffiliatedWithDeviceLocked(owner.userId);
+ }
+ }
+
+ return owners;
+ }
+
/**
* Unit test will subclass it to inject mocks.
*/
@@ -2974,6 +2991,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
updatePasswordQualityCacheForUserGroup(
userId == UserHandle.USER_SYSTEM ? UserHandle.USER_ALL : userId);
updatePermissionPolicyCache(userId);
+ updateAdminCanGrantSensorsPermissionCache(userId);
startOwnerService(userId, "start-user");
}
@@ -13466,15 +13484,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (!mOwners.hasDeviceOwner()) {
return false;
}
- if (userId == mOwners.getDeviceOwnerUserId()) {
- // The user that the DO is installed on is always affiliated with the device.
- return true;
- }
if (userId == UserHandle.USER_SYSTEM) {
// The system user is always affiliated in a DO device,
// even if in headless system user mode.
return true;
}
+ if (userId == mOwners.getDeviceOwnerUserId()) {
+ // The user that the DO is installed on is always affiliated with the device.
+ return true;
+ }
final ComponentName profileOwner = getProfileOwnerAsUser(userId);
if (profileOwner == null) {
@@ -16317,6 +16335,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
disallowAddUser();
+ setAdminCanGrantSensorsPermissionForUserUnchecked(caller.getUserId(),
+ provisioningParams.canDeviceOwnerGrantSensorsPermissions());
} catch (Exception e) {
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.PLATFORM_PROVISIONING_ERROR)
@@ -16456,4 +16476,35 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
});
}
+
+ private void setAdminCanGrantSensorsPermissionForUserUnchecked(int userId, boolean canGrant) {
+ synchronized (getLockObject()) {
+ ActiveAdmin owner = getDeviceOrProfileOwnerAdminLocked(userId);
+
+ Preconditions.checkState(
+ isDeviceOwner(owner) && owner.getUserHandle().getIdentifier() == userId,
+ "May only be set on a the user of a device owner.");
+
+ owner.mAdminCanGrantSensorsPermissions = canGrant;
+ mPolicyCache.setAdminCanGrantSensorsPermissions(userId, canGrant);
+ saveSettingsLocked(userId);
+ }
+ }
+
+ private void updateAdminCanGrantSensorsPermissionCache(int userId) {
+ synchronized (getLockObject()) {
+ ActiveAdmin owner = getDeviceOrProfileOwnerAdminLocked(userId);
+ final boolean canGrant = owner != null ? owner.mAdminCanGrantSensorsPermissions : false;
+ mPolicyCache.setAdminCanGrantSensorsPermissions(userId, canGrant);
+ }
+ }
+
+ @Override
+ public boolean canAdminGrantSensorsPermissionsForUser(int userId) {
+ if (!mHasFeature) {
+ return false;
+ }
+
+ return mPolicyCache.canAdminGrantSensorsPermissionsForUser(userId);
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
index fc1d83158801..222c987d906f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerServiceShellCommand.java
@@ -18,13 +18,17 @@ package com.android.server.devicepolicy;
import android.app.admin.DevicePolicyManager;
import android.os.ShellCommand;
+import com.android.server.devicepolicy.Owners.OwnerDto;
+
import java.io.PrintWriter;
+import java.util.List;
import java.util.Objects;
final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
private static final String CMD_IS_SAFE_OPERATION = "is-operation-safe";
private static final String CMD_SET_SAFE_OPERATION = "set-operation-safe";
+ private static final String CMD_LIST_OWNERS = "list-owners";
private final DevicePolicyManagerService mService;
@@ -51,6 +55,8 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
return runIsSafeOperation(pw);
case CMD_SET_SAFE_OPERATION:
return runSetSafeOperation(pw);
+ case CMD_LIST_OWNERS:
+ return runListOwners(pw);
default:
return onInvalidCommand(pw, cmd);
}
@@ -76,6 +82,8 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
pw.printf(" %s <OPERATION_ID> <REASON_ID>\n", CMD_SET_SAFE_OPERATION);
pw.printf(" Emulates the result of the next call to check if the given operation is safe"
+ " \n\n");
+ pw.printf(" %s\n", CMD_LIST_OWNERS);
+ pw.printf(" Lists the device / profile owners per user \n\n");
}
private int runIsSafeOperation(PrintWriter pw) {
@@ -97,4 +105,36 @@ final class DevicePolicyManagerServiceShellCommand extends ShellCommand {
DevicePolicyManager.unsafeOperationReasonToString(reason));
return 0;
}
+
+ private int runListOwners(PrintWriter pw) {
+ List<OwnerDto> owners = mService.listAllOwners();
+ if (owners.isEmpty()) {
+ pw.println("none");
+ return 0;
+ }
+ int size = owners.size();
+ if (size == 1) {
+ pw.println("1 owner:");
+ } else {
+ pw.printf("%d owners:\n", size);
+ }
+
+ for (int i = 0; i < size; i++) {
+ OwnerDto owner = owners.get(i);
+ pw.printf("User %2d: admin=%s", owner.userId, owner.admin.flattenToShortString());
+ if (owner.isDeviceOwner) {
+ pw.print(",DeviceOwner");
+ }
+ if (owner.isProfileOwner) {
+ pw.print(",ProfileOwner");
+ }
+ if (owner.isAffiliated) {
+ pw.print(",Affiliated");
+ }
+ pw.println();
+ }
+
+ 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 809afe01da2d..1e70d59a5fd5 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -17,6 +17,7 @@
package com.android.server.devicepolicy;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.ActivityManagerInternal;
import android.app.AppOpsManagerInternal;
import android.app.admin.SystemUpdateInfo;
@@ -57,6 +58,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -433,6 +435,23 @@ class Owners {
}
}
+ List<OwnerDto> listAllOwners() {
+ List<OwnerDto> owners = new ArrayList<>();
+ synchronized (mLock) {
+ if (mDeviceOwner != null) {
+ owners.add(new OwnerDto(mDeviceOwnerUserId, mDeviceOwner.admin,
+ /* isDeviceOwner= */ true));
+ }
+ for (int i = 0; i < mProfileOwners.size(); i++) {
+ int userId = mProfileOwners.keyAt(i);
+ OwnerInfo info = mProfileOwners.valueAt(i);
+ owners.add(new OwnerDto(userId, info.admin, /* isDeviceOwner= */ false));
+ }
+ }
+ return owners;
+ }
+
+
SystemUpdatePolicy getSystemUpdatePolicy() {
synchronized (mLock) {
return mSystemUpdatePolicy;
@@ -1076,6 +1095,24 @@ class Owners {
}
}
+ /**
+ * Data-transfer object used by {@link DevicePolicyManagerServiceShellCommand}.
+ */
+ static final class OwnerDto {
+ public final @UserIdInt int userId;
+ public final ComponentName admin;
+ public final boolean isDeviceOwner;
+ public final boolean isProfileOwner;
+ public boolean isAffiliated;
+
+ private OwnerDto(@UserIdInt int userId, ComponentName admin, boolean isDeviceOwner) {
+ this.userId = userId;
+ this.admin = Objects.requireNonNull(admin, "admin must not be null");
+ this.isDeviceOwner = isDeviceOwner;
+ this.isProfileOwner = !isDeviceOwner;
+ }
+ }
+
public void dump(IndentingPrintWriter pw) {
boolean needBlank = false;
if (mDeviceOwner != null) {
diff --git a/services/incremental/Android.bp b/services/incremental/Android.bp
index e978ed4000e0..7534c7c40a3d 100644
--- a/services/incremental/Android.bp
+++ b/services/incremental/Android.bp
@@ -51,9 +51,9 @@ cc_defaults {
static_libs: [
"libbase",
"libext2_uuid",
- "libdataloader_aidl-unstable-cpp",
- "libincremental_aidl-unstable-cpp",
- "libincremental_manager_aidl-unstable-cpp",
+ "libdataloader_aidl-cpp",
+ "libincremental_aidl-cpp",
+ "libincremental_manager_aidl-cpp",
"libprotobuf-cpp-lite",
"service.incremental.proto",
"libutils",
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index 6daa381f526e..7a0cb8e5dead 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -59,9 +59,9 @@ android_test {
},
libs: [
- "android.hardware.power-java",
+ "android.hardware.power-V1-java",
"android.hardware.tv.cec-V1.0-java",
- "android.hardware.vibrator-java",
+ "android.hardware.vibrator-V1-java",
"android.hidl.manager-V1.0-java",
"android.test.mock",
"android.test.base",
@@ -88,7 +88,7 @@ android_test {
"libui",
"libunwindstack",
"libutils",
- "netd_aidl_interface-cpp",
+ "netd_aidl_interface-V5-cpp",
],
dxflags: ["--multi-dex"],
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
index 54da6436ad89..1a2266139405 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
@@ -19,10 +19,14 @@ package com.android.server.devicestate;
import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertThrows;
+import android.hardware.devicestate.DeviceStateRequest;
import android.hardware.devicestate.IDeviceStateManagerCallback;
+import android.os.Binder;
+import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
@@ -33,6 +37,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.HashMap;
import java.util.Optional;
import javax.annotation.Nullable;
@@ -61,87 +66,69 @@ public final class DeviceStateManagerServiceTest {
}
@Test
- public void requestStateChange() {
+ public void baseStateChanged() {
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getRequestedState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
DEFAULT_DEVICE_STATE.getIdentifier());
- mProvider.notifyRequestState(OTHER_DEVICE_STATE.getIdentifier());
+ mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getRequestedState().get(), OTHER_DEVICE_STATE);
+ assertEquals(mService.getBaseState().get(), OTHER_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
OTHER_DEVICE_STATE.getIdentifier());
}
@Test
- public void requestStateChange_pendingState() {
+ public void baseStateChanged_withStatePendingPolicyCallback() {
mPolicy.blockConfigure();
- mProvider.notifyRequestState(OTHER_DEVICE_STATE.getIdentifier());
+ mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState().get(), OTHER_DEVICE_STATE);
- assertEquals(mService.getRequestedState().get(), OTHER_DEVICE_STATE);
+ assertEquals(mService.getBaseState().get(), OTHER_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
OTHER_DEVICE_STATE.getIdentifier());
- mProvider.notifyRequestState(DEFAULT_DEVICE_STATE.getIdentifier());
+ mProvider.setState(DEFAULT_DEVICE_STATE.getIdentifier());
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState().get(), OTHER_DEVICE_STATE);
- assertEquals(mService.getRequestedState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
OTHER_DEVICE_STATE.getIdentifier());
mPolicy.resumeConfigure();
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getRequestedState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
DEFAULT_DEVICE_STATE.getIdentifier());
}
@Test
- public void requestStateChange_unsupportedState() {
- mProvider.notifyRequestState(UNSUPPORTED_DEVICE_STATE.getIdentifier());
+ public void baseStateChanged_unsupportedState() {
+ assertThrows(IllegalArgumentException.class, () -> {
+ mProvider.setState(UNSUPPORTED_DEVICE_STATE.getIdentifier());
+ });
+
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getRequestedState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
DEFAULT_DEVICE_STATE.getIdentifier());
}
@Test
- public void requestStateChange_invalidState() {
+ public void baseStateChanged_invalidState() {
assertThrows(IllegalArgumentException.class, () -> {
- mProvider.notifyRequestState(INVALID_DEVICE_STATE);
+ mProvider.setState(INVALID_DEVICE_STATE);
});
- }
-
- @Test
- public void requestOverrideState() {
- mService.setOverrideState(OTHER_DEVICE_STATE.getIdentifier());
- // Committed state changes as there is a requested override.
- assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
- assertEquals(mService.getRequestedState().get(), DEFAULT_DEVICE_STATE);
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- OTHER_DEVICE_STATE.getIdentifier());
-
- // Committed state is set back to the requested state once the override is cleared.
- mService.clearOverrideState();
- assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
- assertEquals(mService.getRequestedState().get(), DEFAULT_DEVICE_STATE);
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- DEFAULT_DEVICE_STATE.getIdentifier());
- }
- @Test
- public void requestOverrideState_unsupportedState() {
- mService.setOverrideState(UNSUPPORTED_DEVICE_STATE.getIdentifier());
- // Committed state remains the same as the override state is unsupported.
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
- assertEquals(mService.getRequestedState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getPendingState(), Optional.empty());
+ assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
DEFAULT_DEVICE_STATE.getIdentifier());
}
@@ -150,7 +137,7 @@ public final class DeviceStateManagerServiceTest {
public void supportedStatesChanged() {
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getRequestedState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
mProvider.notifySupportedDeviceStates(new DeviceState[]{ DEFAULT_DEVICE_STATE });
@@ -158,46 +145,27 @@ public final class DeviceStateManagerServiceTest {
// supported.
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getRequestedState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
}
@Test
- public void supportedStatesChanged_unsupportedRequestedState() {
+ public void supportedStatesChanged_unsupportedBaseState() {
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getRequestedState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
mProvider.notifySupportedDeviceStates(new DeviceState[]{ OTHER_DEVICE_STATE });
// The current requested state is cleared because it is no longer supported.
assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getRequestedState(), Optional.empty());
+ assertEquals(mService.getBaseState(), Optional.empty());
- mProvider.notifyRequestState(OTHER_DEVICE_STATE.getIdentifier());
+ mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
assertEquals(mService.getPendingState(), Optional.empty());
- assertEquals(mService.getRequestedState().get(), OTHER_DEVICE_STATE);
- }
-
- @Test
- public void supportedStatesChanged_unsupportedOverrideState() {
- mService.setOverrideState(OTHER_DEVICE_STATE.getIdentifier());
- // Committed state changes as there is a requested override.
- assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
- assertEquals(mService.getRequestedState().get(), DEFAULT_DEVICE_STATE);
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- OTHER_DEVICE_STATE.getIdentifier());
-
- mProvider.notifySupportedDeviceStates(new DeviceState[]{ DEFAULT_DEVICE_STATE });
-
- // Committed state is set back to the requested state as the override state is no longer
- // supported.
- assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
- assertEquals(mService.getRequestedState().get(), DEFAULT_DEVICE_STATE);
- assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
- DEFAULT_DEVICE_STATE.getIdentifier());
+ assertEquals(mService.getBaseState().get(), OTHER_DEVICE_STATE);
}
@Test
@@ -205,17 +173,17 @@ public final class DeviceStateManagerServiceTest {
TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
mService.getBinderService().registerCallback(callback);
- mProvider.notifyRequestState(OTHER_DEVICE_STATE.getIdentifier());
+ mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
assertNotNull(callback.getLastNotifiedValue());
assertEquals(callback.getLastNotifiedValue().intValue(),
OTHER_DEVICE_STATE.getIdentifier());
- mProvider.notifyRequestState(DEFAULT_DEVICE_STATE.getIdentifier());
+ mProvider.setState(DEFAULT_DEVICE_STATE.getIdentifier());
assertEquals(callback.getLastNotifiedValue().intValue(),
DEFAULT_DEVICE_STATE.getIdentifier());
mPolicy.blockConfigure();
- mProvider.notifyRequestState(OTHER_DEVICE_STATE.getIdentifier());
+ mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
// The callback should not have been notified of the state change as the policy is still
// pending callback.
assertEquals(callback.getLastNotifiedValue().intValue(),
@@ -237,6 +205,148 @@ public final class DeviceStateManagerServiceTest {
DEFAULT_DEVICE_STATE.getIdentifier());
}
+ @Test
+ public void getSupportedDeviceStates() throws RemoteException {
+ final int[] expectedStates = new int[] { 0, 1 };
+ assertEquals(mService.getBinderService().getSupportedDeviceStates(), expectedStates);
+ }
+
+ @Test
+ public void requestState() throws RemoteException {
+ TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ mService.getBinderService().registerCallback(callback);
+
+ final IBinder token = new Binder();
+ assertEquals(callback.getLastNotifiedStatus(token),
+ TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+
+ mService.getBinderService().requestState(token, OTHER_DEVICE_STATE.getIdentifier(),
+ 0 /* flags */);
+
+ assertEquals(callback.getLastNotifiedStatus(token),
+ TestDeviceStateManagerCallback.STATUS_ACTIVE);
+ // Committed state changes as there is a requested override.
+ assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
+ assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
+ assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
+ OTHER_DEVICE_STATE.getIdentifier());
+
+
+ mService.getBinderService().cancelRequest(token);
+
+ assertEquals(callback.getLastNotifiedStatus(token),
+ TestDeviceStateManagerCallback.STATUS_CANCELED);
+ // Committed state is set back to the requested state once the override is cleared.
+ assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertFalse(mService.getOverrideState().isPresent());
+ assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
+ DEFAULT_DEVICE_STATE.getIdentifier());
+ }
+
+ @Test
+ public void requestState_flagCancelWhenBaseChanges() throws RemoteException {
+ TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ mService.getBinderService().registerCallback(callback);
+
+ final IBinder token = new Binder();
+ assertEquals(callback.getLastNotifiedStatus(token),
+ TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+
+ mService.getBinderService().requestState(token, OTHER_DEVICE_STATE.getIdentifier(),
+ DeviceStateRequest.FLAG_CANCEL_WHEN_BASE_CHANGES);
+
+ assertEquals(callback.getLastNotifiedStatus(token),
+ TestDeviceStateManagerCallback.STATUS_ACTIVE);
+
+ // Committed state changes as there is a requested override.
+ assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
+ assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
+ assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
+ OTHER_DEVICE_STATE.getIdentifier());
+
+ mProvider.setState(OTHER_DEVICE_STATE.getIdentifier());
+
+ // Request is canceled because the base state changed.
+ assertEquals(callback.getLastNotifiedStatus(token),
+ TestDeviceStateManagerCallback.STATUS_CANCELED);
+ // Committed state is set back to the requested state once the override is cleared.
+ assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
+ assertEquals(mService.getBaseState().get(), OTHER_DEVICE_STATE);
+ assertFalse(mService.getOverrideState().isPresent());
+ assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
+ OTHER_DEVICE_STATE.getIdentifier());
+ }
+
+ @Test
+ public void requestState_becomesUnsupported() throws RemoteException {
+ TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ mService.getBinderService().registerCallback(callback);
+
+ final IBinder token = new Binder();
+ assertEquals(callback.getLastNotifiedStatus(token),
+ TestDeviceStateManagerCallback.STATUS_UNKNOWN);
+
+ mService.getBinderService().requestState(token, OTHER_DEVICE_STATE.getIdentifier(),
+ 0 /* flags */);
+
+ assertEquals(callback.getLastNotifiedStatus(token),
+ TestDeviceStateManagerCallback.STATUS_ACTIVE);
+ // Committed state changes as there is a requested override.
+ assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
+ assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getOverrideState().get(), OTHER_DEVICE_STATE);
+ assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
+ OTHER_DEVICE_STATE.getIdentifier());
+
+ mProvider.notifySupportedDeviceStates(new DeviceState[]{ DEFAULT_DEVICE_STATE });
+
+ // Request is canceled because the state is no longer supported.
+ assertEquals(callback.getLastNotifiedStatus(token),
+ TestDeviceStateManagerCallback.STATUS_CANCELED);
+ // Committed state is set back to the requested state as the override state is no longer
+ // supported.
+ assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getBaseState().get(), DEFAULT_DEVICE_STATE);
+ assertFalse(mService.getOverrideState().isPresent());
+ assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(),
+ DEFAULT_DEVICE_STATE.getIdentifier());
+ }
+
+ @Test
+ public void requestState_unsupportedState() throws RemoteException {
+ TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ mService.getBinderService().registerCallback(callback);
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ final IBinder token = new Binder();
+ mService.getBinderService().requestState(token,
+ UNSUPPORTED_DEVICE_STATE.getIdentifier(), 0 /* flags */);
+ });
+ }
+
+ @Test
+ public void requestState_invalidState() throws RemoteException {
+ TestDeviceStateManagerCallback callback = new TestDeviceStateManagerCallback();
+ mService.getBinderService().registerCallback(callback);
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ final IBinder token = new Binder();
+ mService.getBinderService().requestState(token, INVALID_DEVICE_STATE, 0 /* flags */);
+ });
+ }
+
+ @Test
+ public void requestState_beforeRegisteringCallback() {
+ assertThrows(IllegalStateException.class, () -> {
+ final IBinder token = new Binder();
+ mService.getBinderService().requestState(token, DEFAULT_DEVICE_STATE.getIdentifier(),
+ 0 /* flags */);
+ });
+ }
+
private static final class TestDeviceStatePolicy implements DeviceStatePolicy {
private final DeviceStateProvider mProvider;
private int mLastDeviceStateRequestedToConfigure = INVALID_DEVICE_STATE;
@@ -306,23 +416,48 @@ public final class DeviceStateManagerServiceTest {
mListener.onSupportedDeviceStatesChanged(supportedDeviceStates);
}
- public void notifyRequestState(int identifier) {
+ public void setState(int identifier) {
mListener.onStateChanged(identifier);
}
}
private static final class TestDeviceStateManagerCallback extends
IDeviceStateManagerCallback.Stub {
- Integer mLastNotifiedValue;
+ public static final int STATUS_UNKNOWN = 0;
+ public static final int STATUS_ACTIVE = 1;
+ public static final int STATUS_SUSPENDED = 2;
+ public static final int STATUS_CANCELED = 3;
+
+ private Integer mLastNotifiedValue;
+ private final HashMap<IBinder, Integer> mLastNotifiedStatus = new HashMap<>();
@Override
public void onDeviceStateChanged(int deviceState) {
mLastNotifiedValue = deviceState;
}
+ @Override
+ public void onRequestActive(IBinder token) {
+ mLastNotifiedStatus.put(token, STATUS_ACTIVE);
+ }
+
+ @Override
+ public void onRequestSuspended(IBinder token) {
+ mLastNotifiedStatus.put(token, STATUS_SUSPENDED);
+ }
+
+ @Override
+ public void onRequestCanceled(IBinder token) {
+ mLastNotifiedStatus.put(token, STATUS_CANCELED);
+ }
+
@Nullable
Integer getLastNotifiedValue() {
return mLastNotifiedValue;
}
+
+ int getLastNotifiedStatus(IBinder requestToken) {
+ return mLastNotifiedStatus.getOrDefault(requestToken, STATUS_UNKNOWN);
+ }
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java b/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java
index 9ba096766be2..7b9a00d582be 100644
--- a/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/IncrementalStatesTest.java
@@ -71,12 +71,12 @@ public class IncrementalStatesTest {
@Before
public void setUp() {
mIncrementalStates = new IncrementalStates();
- assertFalse(mIncrementalStates.isStartable());
+ assertFalse(mIncrementalStates.getIncrementalStatesInfo().isStartable());
mIncrementalStates.setCallback(mCallback);
mIncrementalStates.onCommit(true);
// Test that package is now startable and loading
- assertTrue(mIncrementalStates.isStartable());
- assertTrue(mIncrementalStates.isLoading());
+ assertTrue(mIncrementalStates.getIncrementalStatesInfo().isStartable());
+ assertTrue(mIncrementalStates.getIncrementalStatesInfo().isLoading());
mUnstartableCalled.close();
mFullyLoadedCalled.close();
}
@@ -90,7 +90,7 @@ public class IncrementalStatesTest {
IStorageHealthListener.HEALTH_STATUS_UNHEALTHY);
// Test that package is still startable
assertFalse(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertTrue(mIncrementalStates.isStartable());
+ assertTrue(mIncrementalStates.getIncrementalStatesInfo().isStartable());
assertEquals(PackageManager.UNSTARTABLE_REASON_UNKNOWN, mUnstartableReason.get());
}
@@ -104,7 +104,7 @@ public class IncrementalStatesTest {
IStorageHealthListener.HEALTH_STATUS_READS_PENDING);
// Test that package is still startable
assertFalse(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertTrue(mIncrementalStates.isStartable());
+ assertTrue(mIncrementalStates.getIncrementalStatesInfo().isStartable());
}
/**
@@ -116,7 +116,7 @@ public class IncrementalStatesTest {
IStorageHealthListener.HEALTH_STATUS_UNHEALTHY_STORAGE);
// Test that package is still startable
assertFalse(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertTrue(mIncrementalStates.isStartable());
+ assertTrue(mIncrementalStates.getIncrementalStatesInfo().isStartable());
assertEquals(PackageManager.UNSTARTABLE_REASON_UNKNOWN,
mUnstartableReason.get());
}
@@ -130,7 +130,7 @@ public class IncrementalStatesTest {
IStorageHealthListener.HEALTH_STATUS_UNHEALTHY_TRANSPORT);
// Test that package is still startable
assertFalse(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertTrue(mIncrementalStates.isStartable());
+ assertTrue(mIncrementalStates.getIncrementalStatesInfo().isStartable());
assertEquals(PackageManager.UNSTARTABLE_REASON_UNKNOWN,
mUnstartableReason.get());
}
@@ -145,12 +145,12 @@ public class IncrementalStatesTest {
mIncrementalStates.setProgress(1.0f);
// Test that package is now fully loaded
assertTrue(mFullyLoadedCalled.block(WAIT_TIMEOUT_MILLIS));
- assertFalse(mIncrementalStates.isLoading());
+ assertFalse(mIncrementalStates.getIncrementalStatesInfo().isLoading());
mIncrementalStates.onStorageHealthStatusChanged(
IStorageHealthListener.HEALTH_STATUS_UNHEALTHY);
// Test that package is still startable
assertFalse(mUnstartableCalled.block(WAIT_TIMEOUT_MILLIS));
- assertTrue(mIncrementalStates.isStartable());
+ assertTrue(mIncrementalStates.getIncrementalStatesInfo().isStartable());
}
/**
@@ -159,6 +159,6 @@ public class IncrementalStatesTest {
@Test
public void testStartableTransition_AppCrashOrAnr() {
mIncrementalStates.onCrashOrAnr();
- assertTrue(mIncrementalStates.isStartable());
+ assertTrue(mIncrementalStates.getIncrementalStatesInfo().isStartable());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java
index e6c3d7c3fc5b..b21b04979424 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java
@@ -18,6 +18,7 @@ package com.android.server.pm;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.array;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertContains;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertHaveIds;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertSuccess;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith;
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
@@ -25,6 +26,8 @@ import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.resultContains;
import android.content.ComponentName;
+import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutManager;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.Process;
@@ -47,6 +50,9 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
@SmallTest
public class ShortcutManagerTest7 extends BaseShortcutManagerTest {
+
+ private static final int CACHE_OWNER = LauncherApps.FLAG_CACHE_NOTIFICATION_SHORTCUTS;
+
private List<String> callShellCommand(String... args) throws IOException, RemoteException {
// For reset to work, the current time needs to be incrementing.
@@ -215,11 +221,13 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest {
// This command is deprecated. Will remove the test later.
public void testLauncherCommands() throws Exception {
+ prepareGetRoleHoldersAsUser(getSystemLauncher().activityInfo.packageName, USER_0);
prepareGetHomeActivitiesAsUser(
/* preferred */ getSystemLauncher().activityInfo.getComponentName(),
list(getSystemLauncher(), getFallbackLauncher()),
USER_0);
+ prepareGetRoleHoldersAsUser(CALLING_PACKAGE_2, USER_10);
prepareGetHomeActivitiesAsUser(
/* preferred */ cn(CALLING_PACKAGE_2, "name"),
list(getSystemLauncher(), getFallbackLauncher(),
@@ -241,6 +249,7 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest {
"Launcher: ComponentInfo{com.android.test.2/name}");
// Change user-0's launcher.
+ prepareGetRoleHoldersAsUser(CALLING_PACKAGE_1, USER_0);
prepareGetHomeActivitiesAsUser(
/* preferred */ cn(CALLING_PACKAGE_1, "name"),
list(ri(CALLING_PACKAGE_1, "name", false, 0)),
@@ -323,6 +332,72 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest {
});
}
+ public void testGetShortcuts() throws Exception {
+
+ mRunningUsers.put(USER_10, true);
+
+ // Add two manifests and two dynamics.
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_2);
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.mPackageMonitor.onReceive(getTestContext(),
+ genPackageAddIntent(CALLING_PACKAGE_1, USER_10));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertTrue(mManager.addDynamicShortcuts(list(
+ makeLongLivedShortcut("s1"), makeShortcut("s2"))));
+ });
+ runWithCaller(LAUNCHER_1, USER_10, () -> {
+ mInjectCheckAccessShortcutsPermission = true;
+ mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_10,
+ CACHE_OWNER);
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2", "s2"), HANDLE_USER_10);
+ });
+
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms2", "s1", "s2")
+ .areAllEnabled()
+
+ .selectPinned()
+ .haveIds("ms2", "s2");
+ });
+
+
+ mRunningUsers.put(USER_10, true);
+ mUnlockedUsers.put(USER_10, true);
+
+ mInjectedCallingUid = Process.SHELL_UID;
+
+ assertHaveIds(callShellCommand("get-shortcuts", "--user", "10", "--flags",
+ Integer.toString(ShortcutManager.FLAG_MATCH_CACHED), CALLING_PACKAGE_1),
+ "s1");
+
+ assertHaveIds(callShellCommand("get-shortcuts", "--user", "10", "--flags",
+ Integer.toString(ShortcutManager.FLAG_MATCH_DYNAMIC), CALLING_PACKAGE_1),
+ "s1", "s2");
+
+ assertHaveIds(callShellCommand("get-shortcuts", "--user", "10", "--flags",
+ Integer.toString(ShortcutManager.FLAG_MATCH_MANIFEST), CALLING_PACKAGE_1),
+ "ms1", "ms2");
+
+ assertHaveIds(callShellCommand("get-shortcuts", "--user", "10", "--flags",
+ Integer.toString(ShortcutManager.FLAG_MATCH_PINNED), CALLING_PACKAGE_1),
+ "ms2", "s2");
+
+ assertHaveIds(callShellCommand("get-shortcuts", "--user", "10", "--flags",
+ Integer.toString(ShortcutManager.FLAG_MATCH_DYNAMIC
+ | ShortcutManager.FLAG_MATCH_PINNED), CALLING_PACKAGE_1),
+ "ms2", "s1", "s2");
+
+ assertHaveIds(callShellCommand("get-shortcuts", "--user", "10", "--flags",
+ Integer.toString(ShortcutManager.FLAG_MATCH_MANIFEST
+ | ShortcutManager.FLAG_MATCH_CACHED), CALLING_PACKAGE_1),
+ "ms1", "ms2", "s1");
+
+ }
+
public void testDumpsysArgs() {
checkDumpsysArgs(null, true, false, false);
checkDumpsysArgs(array("-u"), true, true, false);
diff --git a/services/tests/shortcutmanagerutils/Android.bp b/services/tests/shortcutmanagerutils/Android.bp
index c2cb688175b2..35ca3544d62e 100644
--- a/services/tests/shortcutmanagerutils/Android.bp
+++ b/services/tests/shortcutmanagerutils/Android.bp
@@ -22,5 +22,9 @@ java_library {
"android.test.runner.stubs",
],
+ static_libs: [
+ "compatibility-device-util-axt",
+ ],
+
sdk_version: "test_current",
}
diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
index 907f887ec228..5182b3b69655 100644
--- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
+++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
@@ -15,6 +15,8 @@
*/
package com.android.server.pm.shortcutmanagertest;
+import static com.android.compatibility.common.util.SystemUtil.callWithShellPermissionIdentity;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
@@ -34,6 +36,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.app.Instrumentation;
+import android.app.role.RoleManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.LocusId;
@@ -50,6 +53,7 @@ import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.UserHandle;
+import android.os.UserManager;
import android.test.MoreAsserts;
import android.util.Log;
@@ -136,6 +140,20 @@ public class ShortcutManagerTestUtils {
return sb.toString();
}
+ public static List<String> extractShortcutIds(List<String> result) {
+ final String prefix = "ShortcutInfo {id=";
+ final String postfix = ", ";
+
+ List<String> ids = new ArrayList<>();
+ for (String line : result) {
+ if (line.contains(prefix)) {
+ ids.add(line.substring(
+ line.indexOf(prefix) + prefix.length(), line.indexOf(postfix)));
+ }
+ }
+ return ids;
+ }
+
public static boolean resultContains(List<String> result, String expected) {
for (String line : result) {
if (line.contains(expected)) {
@@ -160,6 +178,16 @@ public class ShortcutManagerTestUtils {
return result;
}
+ public static List<String> assertHaveIds(List<String> result, String... expectedIds) {
+ assertSuccess(result);
+
+ final SortedSet<String> expected = new TreeSet<>(list(expectedIds));
+ final SortedSet<String> actual = new TreeSet<>(extractShortcutIds(result));
+ assertEquals(expected, actual);
+
+ return result;
+ }
+
public static List<String> runCommand(Instrumentation instrumentation, String command) {
return runCommand(instrumentation, command, null);
}
@@ -193,30 +221,60 @@ public class ShortcutManagerTestUtils {
return runShortcutCommand(instrumentation, command, result -> result.contains("Success"));
}
- public static String getDefaultLauncher(Instrumentation instrumentation) {
- final String PREFIX = "Launcher: ComponentInfo{";
- final String POSTFIX = "}";
- final List<String> result = runShortcutCommandForSuccess(
- instrumentation, "get-default-launcher --user "
- + instrumentation.getContext().getUserId());
- for (String s : result) {
- if (s.startsWith(PREFIX) && s.endsWith(POSTFIX)) {
- return s.substring(PREFIX.length(), s.length() - POSTFIX.length());
+ private static UserHandle getParentUser(Context context) {
+ final UserHandle user = context.getUser();
+ final UserManager userManager = context.getSystemService(UserManager.class);
+ if (!userManager.isManagedProfile(user.getIdentifier())) {
+ return user;
+ }
+
+ final List<UserHandle> profiles = userManager.getUserProfiles();
+ for (UserHandle handle : profiles) {
+ if (!userManager.isManagedProfile(handle.getIdentifier())) {
+ return handle;
}
}
- fail("Default launcher not found");
return null;
}
- public static void setDefaultLauncher(Instrumentation instrumentation, String component) {
- runCommand(instrumentation, "cmd package set-home-activity --user "
- + instrumentation.getContext().getUserId() + " " + component,
- result -> result.contains("Success"));
+ public static String getDefaultLauncher(Instrumentation instrumentation) throws Exception {
+ final Context context = instrumentation.getContext();
+ final RoleManager roleManager = context.getSystemService(RoleManager.class);
+ final UserHandle user = getParentUser(context);
+ List<String> roleHolders = callWithShellPermissionIdentity(
+ () -> roleManager.getRoleHoldersAsUser(RoleManager.ROLE_HOME, user));
+ if (roleHolders.size() == 1) {
+ return roleHolders.get(0);
+ }
+ fail("Failed to get the default launcher for user " + context.getUserId());
+ return null;
+ }
+
+ public static void setDefaultLauncher(Instrumentation instrumentation, String packageName) {
+ runCommandForNoOutput(instrumentation, "cmd role add-role-holder --user "
+ + instrumentation.getContext().getUserId() + " " + RoleManager.ROLE_HOME + " "
+ + packageName + " 0");
+ waitUntil("Failed to get shortcut access",
+ () -> hasShortcutAccess(instrumentation, packageName), 20);
}
public static void setDefaultLauncher(Instrumentation instrumentation, Context packageContext) {
- setDefaultLauncher(instrumentation, packageContext.getPackageName()
- + "/android.content.pm.cts.shortcutmanager.packages.Launcher");
+ setDefaultLauncher(instrumentation, packageContext.getPackageName());
+ }
+
+ public static boolean hasShortcutAccess(Instrumentation instrumentation, String packageName) {
+ final List<String> result = runShortcutCommandForSuccess(instrumentation,
+ "has-shortcut-access --user " + instrumentation.getContext().getUserId()
+ + " " + packageName);
+ for (String s : result) {
+ if (s.startsWith("true")) {
+ return true;
+ } else if (s.startsWith("false")) {
+ return false;
+ }
+ }
+ fail("Failed to check shortcut access");
+ return false;
}
public static void overrideConfig(Instrumentation instrumentation, String config) {
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index e5646db7731f..1dd42127ec06 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -60,6 +60,6 @@ android_test {
"libui",
"libunwindstack",
"libutils",
- "netd_aidl_interface-cpp",
+ "netd_aidl_interface-V5-cpp",
],
}
diff --git a/services/tests/wmtests/Android.bp b/services/tests/wmtests/Android.bp
index cf977b4a18db..ddf2844012e0 100644
--- a/services/tests/wmtests/Android.bp
+++ b/services/tests/wmtests/Android.bp
@@ -51,7 +51,7 @@ android_test {
],
libs: [
- "android.hardware.power-java",
+ "android.hardware.power-V1-java",
"android.test.mock",
"android.test.base",
"android.test.runner",
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 6b69ee921c8b..002859e3366b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -96,6 +96,8 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
.setTask(mTrampolineActivity.getTask())
.setComponent(createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, "TopActivity"))
.build();
+ // becomes invisible when covered by mTopActivity
+ mTrampolineActivity.mVisibleRequested = false;
}
@After
@@ -230,7 +232,6 @@ public class ActivityMetricsLaunchObserverTests extends WindowTestsBase {
@Test
public void testOnActivityLaunchCancelled_finishedBeforeDrawn() {
- mTopActivity.mVisibleRequested = true;
doReturn(true).when(mTopActivity).isReportedDrawn();
// Create an activity with different process that meets process switch.
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 93851109200b..72b84396e985 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -2180,6 +2180,7 @@ public class ActivityRecordTests extends WindowTestsBase {
activity.setOccludesParent(true);
activity.setVisible(false);
+ activity.mVisibleRequested = false;
// Can not specify orientation if app isn't visible even though it occludes parent.
assertEquals(SCREEN_ORIENTATION_UNSET, activity.getOrientation());
// Can specify orientation if the current orientation candidate is orientation behind.
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 22ee886c46fe..3a7954b3a5ce 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -1424,6 +1424,9 @@ public class ActivityStackTests extends WindowTestsBase {
final ActivityRecord nonTopVisibleActivity =
new ActivityBuilder(mAtm).setTask(task).build();
new ActivityBuilder(mAtm).setTask(task).build();
+ // The scenario we are testing is when the app isn't visible yet.
+ nonTopVisibleActivity.setVisible(false);
+ nonTopVisibleActivity.mVisibleRequested = false;
doReturn(false).when(nonTopVisibleActivity).attachedToProcess();
doReturn(true).when(nonTopVisibleActivity).shouldBeVisibleUnchecked();
doNothing().when(mSupervisor).startSpecificActivity(any(), anyBoolean(),
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 36adf28b276a..37bc23e6a17d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -844,6 +844,9 @@ public class ActivityStarterTests extends WindowTestsBase {
final ActivityRecord singleTaskActivity = createSingleTaskActivityOn(
secondaryTaskContainer.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */));
+ // Activity should start invisible since we are bringing it to front.
+ singleTaskActivity.setVisible(false);
+ singleTaskActivity.mVisibleRequested = false;
// Create another activity on top of the secondary display.
final Task topStack = secondaryTaskContainer.createRootTask(WINDOWING_MODE_FULLSCREEN,
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
index 2f4c8e256760..d13e4dcaf9fd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
@@ -15,7 +15,7 @@
*/
package com.android.server.wm;
-import static android.os.Process.INVALID_UID;
+
import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
@@ -587,7 +587,7 @@ public class DisplayAreaPolicyBuilderTest {
final WindowToken token = new WindowToken(mWms, mock(IBinder.class),
TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
- true /* ownerCanManageAppTokens */, INVALID_UID, false /* roundedCornerOverlay */,
+ true /* ownerCanManageAppTokens */, false /* roundedCornerOverlay */,
false /* fromClientToken */, null /* options */);
policy.addWindow(token);
@@ -621,11 +621,11 @@ public class DisplayAreaPolicyBuilderTest {
final WindowToken token1 = new WindowToken(mWms, mock(IBinder.class),
TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
- true /* ownerCanManageAppTokens */, INVALID_UID, false /* roundedCornerOverlay */,
+ true /* ownerCanManageAppTokens */, false /* roundedCornerOverlay */,
false /* fromClientToken */, null /* options */);
final WindowToken token2 = new WindowToken(mWms, mock(IBinder.class),
TYPE_WALLPAPER, true /* persistOnEmpty */, mDisplayContent,
- true /* ownerCanManageAppTokens */, INVALID_UID, false /* roundedCornerOverlay */,
+ true /* ownerCanManageAppTokens */, false /* roundedCornerOverlay */,
false /* fromClientToken */, null /* options */);
policy.addWindow(token1);
policy.addWindow(token2);
@@ -672,15 +672,15 @@ public class DisplayAreaPolicyBuilderTest {
options2.putInt("HIERARCHY_ROOT_ID", mGroupRoot2.mFeatureId);
final WindowToken token0 = new WindowToken(mWms, mock(IBinder.class),
TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
- true /* ownerCanManageAppTokens */, INVALID_UID, false /* roundedCornerOverlay */,
+ true /* ownerCanManageAppTokens */, false /* roundedCornerOverlay */,
false /* fromClientToken */, null /* options */);
final WindowToken token1 = new WindowToken(mWms, mock(IBinder.class),
TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
- true /* ownerCanManageAppTokens */, INVALID_UID, false /* roundedCornerOverlay */,
+ true /* ownerCanManageAppTokens */, false /* roundedCornerOverlay */,
false /* fromClientToken */, options1);
final WindowToken token2 = new WindowToken(mWms, mock(IBinder.class),
TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
- true /* ownerCanManageAppTokens */, INVALID_UID, false /* roundedCornerOverlay */,
+ true /* ownerCanManageAppTokens */, false /* roundedCornerOverlay */,
false /* fromClientToken */, options2);
policy.addWindow(token0);
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 4bea9a2eea45..4c2d12436858 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -1608,6 +1608,16 @@ public class DisplayContentTests extends WindowTestsBase {
}
@Test
+ public void testGetOrCreateRootHomeTask_dontMoveToTop() {
+ DisplayContent display = createNewDisplay();
+ display.mDontMoveToTop = true;
+ TaskDisplayArea taskDisplayArea = display.getDefaultTaskDisplayArea();
+
+ assertNull(taskDisplayArea.getRootHomeTask());
+ assertNull(taskDisplayArea.getOrCreateRootHomeTask());
+ }
+
+ @Test
public void testValidWindowingLayer() {
final SurfaceControl windowingLayer = mDisplayContent.getWindowingLayer();
assertNotNull(windowingLayer);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
index 33e8fc0bd94b..3e05c86898e2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsProviderTests.java
@@ -217,6 +217,7 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
SettingsEntry overrideSettings = provider.getOverrideSettings(secondaryDisplayInfo);
overrideSettings.mShouldShowSystemDecors = true;
overrideSettings.mImePolicy = DISPLAY_IME_POLICY_LOCAL;
+ overrideSettings.mDontMoveToTop = true;
provider.updateOverrideSettings(secondaryDisplayInfo, overrideSettings);
assertTrue(mOverrideSettingsStorage.wasWriteSuccessful());
@@ -227,6 +228,8 @@ public class DisplayWindowSettingsProviderTests extends WindowTestsBase {
getStoredDisplayAttributeValue(mOverrideSettingsStorage, "shouldShowSystemDecors"));
assertEquals("Attribute value must be stored", "0",
getStoredDisplayAttributeValue(mOverrideSettingsStorage, "imePolicy"));
+ assertEquals("Attribute value must be stored", "true",
+ getStoredDisplayAttributeValue(mOverrideSettingsStorage, "dontMoveToTop"));
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
index d83e9c21fae7..e22cda60d423 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
@@ -156,6 +156,9 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
spyOn(mDisplayContent);
doReturn(true).when(mDisplayContent).isTrusted();
+ // Allow child stack to move to top.
+ mDisplayContent.mDontMoveToTop = false;
+
// The display contains pinned stack that was added in {@link #setUp}.
final Task stack = createTaskStackOnDisplay(mDisplayContent);
final Task task = createTaskInStack(stack, 0 /* userId */);
@@ -173,6 +176,65 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
}
@Test
+ public void testMovingChildTaskOnTop() {
+ // Make sure the display is trusted display which capable to move the stack to top.
+ spyOn(mDisplayContent);
+ doReturn(true).when(mDisplayContent).isTrusted();
+
+ // Allow child stack to move to top.
+ mDisplayContent.mDontMoveToTop = false;
+
+ // The display contains pinned stack that was added in {@link #setUp}.
+ Task stack = createTaskStackOnDisplay(mDisplayContent);
+ Task task = createTaskInStack(stack, 0 /* userId */);
+
+ // Add another display at top.
+ mWm.mRoot.positionChildAt(WindowContainer.POSITION_TOP, createNewDisplay(),
+ false /* includingParents */);
+
+ // Ensure that original display ({@code mDisplayContent}) is not on top.
+ assertEquals("Testing DisplayContent should not be on the top",
+ mWm.mRoot.getChildCount() - 2, mWm.mRoot.mChildren.indexOf(mDisplayContent));
+
+ // Move the task of {@code mDisplayContent} to top.
+ stack.positionChildAt(WindowContainer.POSITION_TOP, task, true /* includingParents */);
+
+ // Ensure that original display ({@code mDisplayContent}) is now on the top.
+ assertEquals("The testing DisplayContent should be moved to top with task",
+ mWm.mRoot.getChildCount() - 1, mWm.mRoot.mChildren.indexOf(mDisplayContent));
+ }
+
+ @Test
+ public void testDontMovingChildTaskOnTop() {
+ // Make sure the display is trusted display which capable to move the stack to top.
+ spyOn(mDisplayContent);
+ doReturn(true).when(mDisplayContent).isTrusted();
+
+ // Allow child stack to move to top.
+ mDisplayContent.mDontMoveToTop = true;
+
+ // The display contains pinned stack that was added in {@link #setUp}.
+ Task stack = createTaskStackOnDisplay(mDisplayContent);
+ Task task = createTaskInStack(stack, 0 /* userId */);
+
+ // Add another display at top.
+ mWm.mRoot.positionChildAt(WindowContainer.POSITION_TOP, createNewDisplay(),
+ false /* includingParents */);
+
+ // Ensure that original display ({@code mDisplayContent}) is not on top.
+ assertEquals("Testing DisplayContent should not be on the top",
+ mWm.mRoot.getChildCount() - 2, mWm.mRoot.mChildren.indexOf(mDisplayContent));
+
+ // Try moving the task of {@code mDisplayContent} to top.
+ stack.positionChildAt(WindowContainer.POSITION_TOP, task, true /* includingParents */);
+
+ // Ensure that original display ({@code mDisplayContent}) hasn't moved and is not
+ // on the top.
+ assertEquals("The testing DisplayContent should not be moved to top with task",
+ mWm.mRoot.getChildCount() - 2, mWm.mRoot.mChildren.indexOf(mDisplayContent));
+ }
+
+ @Test
public void testReuseTaskAsRootTask() {
final Task candidateTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, mDisplayContent);
@@ -233,7 +295,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase {
homeActivity.mVisibleRequested = true;
assertFalse(rootHomeTask.isVisible());
- assertEquals(rootWindowContainer.getOrientation(), rootHomeTask.getOrientation());
+ assertEquals(defaultTaskDisplayArea.getOrientation(), rootHomeTask.getOrientation());
}
@Test
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 f8a89c6f89aa..6d0e510ba626 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -20,7 +20,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
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.os.Process.INVALID_UID;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
@@ -37,12 +36,10 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import android.content.pm.PackageManager;
import android.os.IBinder;
@@ -75,7 +72,7 @@ public class WindowManagerServiceTests extends WindowTestsBase {
@Test
public void testAddWindowToken() {
IBinder token = mock(IBinder.class);
- mWm.addWindowToken(token, TYPE_TOAST, mDisplayContent.getDisplayId());
+ mWm.addWindowToken(token, TYPE_TOAST, mDisplayContent.getDisplayId(), null /* options */);
WindowToken windowToken = mWm.mRoot.getWindowToken(token);
assertFalse(windowToken.mRoundedCornerOverlay);
@@ -83,32 +80,6 @@ public class WindowManagerServiceTests extends WindowTestsBase {
}
@Test
- public void testAddWindowTokenWithOptions() {
- IBinder token = mock(IBinder.class);
- mWm.addWindowTokenWithOptions(token, TYPE_TOAST, mDisplayContent.getDisplayId(),
- null /* options */, null /* options */);
-
- WindowToken windowToken = mWm.mRoot.getWindowToken(token);
- assertFalse(windowToken.mRoundedCornerOverlay);
- assertTrue(windowToken.isFromClient());
- }
-
- @Test(expected = SecurityException.class)
- public void testRemoveWindowToken_ownerUidNotMatch_throwException() {
- IBinder token = mock(IBinder.class);
- mWm.addWindowTokenWithOptions(token, TYPE_TOAST, mDisplayContent.getDisplayId(),
- null /* options */, null /* options */);
-
- spyOn(mWm);
- when(mWm.checkCallingPermission(anyString(), anyString())).thenReturn(false);
- WindowToken windowToken = mWm.mRoot.getWindowToken(token);
- spyOn(windowToken);
- when(windowToken.getOwnerUid()).thenReturn(INVALID_UID);
-
- mWm.removeWindowToken(token, mDisplayContent.getDisplayId());
- }
-
- @Test
public void testTaskFocusChange_stackNotHomeType_focusChanges() throws RemoteException {
DisplayContent display = createNewDisplay();
// Current focused window
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 3492d90cc0f3..eb6c6ed349de 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -890,6 +890,7 @@ class WindowTestsBase extends SystemServiceTestsBase {
mTask.moveToFront("createActivity");
}
// Make visible by default...
+ activity.mVisibleRequested = true;
activity.setVisible(true);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
index 2d273312ab81..e2585e5ebfba 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import static android.os.Process.INVALID_UID;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
@@ -201,7 +200,7 @@ public class WindowTokenTests extends WindowTestsBase {
token = new WindowToken(mDisplayContent.mWmService, mock(IBinder.class), TYPE_TOAST,
true /* persistOnEmpty */, mDisplayContent, true /* ownerCanManageAppTokens */,
- INVALID_UID, true /* roundedCornerOverlay */, true /* fromClientToken */);
+ true /* roundedCornerOverlay */, true /* fromClientToken */, null /* options */);
assertTrue(token.mRoundedCornerOverlay);
assertTrue(token.isFromClient());
}
@@ -215,8 +214,8 @@ public class WindowTokenTests extends WindowTestsBase {
public void testSurfaceCreatedForWindowToken() {
final WindowToken fromClientToken = new WindowToken(mDisplayContent.mWmService,
mock(IBinder.class), TYPE_APPLICATION_OVERLAY, true /* persistOnEmpty */,
- mDisplayContent, true /* ownerCanManageAppTokens */, INVALID_UID,
- true /* roundedCornerOverlay */, true /* fromClientToken */);
+ mDisplayContent, true /* ownerCanManageAppTokens */,
+ true /* roundedCornerOverlay */, true /* fromClientToken */, null /* options */);
assertNull(fromClientToken.mSurfaceControl);
createWindow(null, TYPE_APPLICATION_OVERLAY, fromClientToken, "window");
@@ -224,8 +223,8 @@ public class WindowTokenTests extends WindowTestsBase {
final WindowToken nonClientToken = new WindowToken(mDisplayContent.mWmService,
mock(IBinder.class), TYPE_TOAST, true /* persistOnEmpty */, mDisplayContent,
- true /* ownerCanManageAppTokens */, INVALID_UID, true /* roundedCornerOverlay */,
- false /* fromClientToken */);
+ true /* ownerCanManageAppTokens */, true /* roundedCornerOverlay */,
+ false /* fromClientToken */, null /* options */);
assertNotNull(nonClientToken.mSurfaceControl);
}
@@ -238,7 +237,7 @@ public class WindowTokenTests extends WindowTestsBase {
final WindowToken token1 = new WindowToken(mDisplayContent.mWmService, mock(IBinder.class),
TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
- true /* ownerCanManageAppTokens */, INVALID_UID, true /* roundedCornerOverlay */,
+ true /* ownerCanManageAppTokens */, true /* roundedCornerOverlay */,
false /* fromClientToken */, null /* options */);
verify(selectFunc).apply(token1.windowType, null);
@@ -246,7 +245,7 @@ public class WindowTokenTests extends WindowTestsBase {
final Bundle options = new Bundle();
final WindowToken token2 = new WindowToken(mDisplayContent.mWmService, mock(IBinder.class),
TYPE_STATUS_BAR, true /* persistOnEmpty */, mDisplayContent,
- true /* ownerCanManageAppTokens */, INVALID_UID, true /* roundedCornerOverlay */,
+ true /* ownerCanManageAppTokens */, true /* roundedCornerOverlay */,
false /* fromClientToken */, options /* options */);
verify(selectFunc).apply(token2.windowType, options);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index cfdc5682a117..84f4f6a017d1 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -165,7 +165,8 @@ final class VoiceInteractionSessionConnection implements ServiceConnection,
| Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS, new UserHandle(mUser));
if (mBound) {
try {
- mIWindowManager.addWindowToken(mToken, TYPE_VOICE_INTERACTION, DEFAULT_DISPLAY);
+ mIWindowManager.addWindowToken(mToken, TYPE_VOICE_INTERACTION, DEFAULT_DISPLAY,
+ null /* options */);
} catch (RemoteException e) {
Slog.w(TAG, "Failed adding window token", e);
}
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index f48ddb0aaca6..bd4bf0740ca1 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -136,7 +136,7 @@ public final class DataCallResponse implements Parcelable {
private final @HandoverFailureMode int mHandoverFailureMode;
private final int mPduSessionId;
private final Qos mDefaultQos;
- private final List<QosSession> mQosSessions;
+ private final List<QosBearerSession> mQosBearerSessions;
private final SliceInfo mSliceInfo;
/**
@@ -187,7 +187,7 @@ public final class DataCallResponse implements Parcelable {
mHandoverFailureMode = HANDOVER_FAILURE_MODE_LEGACY;
mPduSessionId = PDU_SESSION_ID_NOT_SET;
mDefaultQos = null;
- mQosSessions = new ArrayList<>();
+ mQosBearerSessions = new ArrayList<>();
mSliceInfo = null;
}
@@ -197,7 +197,7 @@ public final class DataCallResponse implements Parcelable {
@Nullable List<InetAddress> dnsAddresses, @Nullable List<InetAddress> gatewayAddresses,
@Nullable List<InetAddress> pcscfAddresses, int mtu, int mtuV4, int mtuV6,
@HandoverFailureMode int handoverFailureMode, int pduSessionId,
- @Nullable Qos defaultQos, @Nullable List<QosSession> qosSessions,
+ @Nullable Qos defaultQos, @Nullable List<QosBearerSession> qosBearerSessions,
@Nullable SliceInfo sliceInfo) {
mCause = cause;
mSuggestedRetryTime = suggestedRetryTime;
@@ -219,7 +219,7 @@ public final class DataCallResponse implements Parcelable {
mHandoverFailureMode = handoverFailureMode;
mPduSessionId = pduSessionId;
mDefaultQos = defaultQos;
- mQosSessions = qosSessions;
+ mQosBearerSessions = qosBearerSessions;
mSliceInfo = sliceInfo;
}
@@ -246,8 +246,8 @@ public final class DataCallResponse implements Parcelable {
mHandoverFailureMode = source.readInt();
mPduSessionId = source.readInt();
mDefaultQos = source.readParcelable(Qos.class.getClassLoader());
- mQosSessions = new ArrayList<>();
- source.readList(mQosSessions, QosSession.class.getClassLoader());
+ mQosBearerSessions = new ArrayList<>();
+ source.readList(mQosBearerSessions, QosBearerSession.class.getClassLoader());
mSliceInfo = source.readParcelable(SliceInfo.class.getClassLoader());
}
@@ -394,8 +394,8 @@ public final class DataCallResponse implements Parcelable {
* @hide
*/
@NonNull
- public List<QosSession> getQosSessions() {
- return mQosSessions;
+ public List<QosBearerSession> getQosBearerSessions() {
+ return mQosBearerSessions;
}
/**
@@ -427,7 +427,7 @@ public final class DataCallResponse implements Parcelable {
.append(" handoverFailureMode=").append(failureModeToString(mHandoverFailureMode))
.append(" pduSessionId=").append(getPduSessionId())
.append(" defaultQos=").append(mDefaultQos)
- .append(" qosSessions=").append(mQosSessions)
+ .append(" qosBearerSessions=").append(mQosBearerSessions)
.append(" sliceInfo=").append(mSliceInfo)
.append("}");
return sb.toString();
@@ -447,10 +447,10 @@ public final class DataCallResponse implements Parcelable {
mDefaultQos == other.mDefaultQos :
mDefaultQos.equals(other.mDefaultQos);
- final boolean isQosSessionsSame = (mQosSessions == null || mQosSessions == null) ?
- mQosSessions == other.mQosSessions :
- mQosSessions.size() == other.mQosSessions.size()
- && mQosSessions.containsAll(other.mQosSessions);
+ final boolean isQosBearerSessionsSame = (mQosBearerSessions == null || mQosBearerSessions == null) ?
+ mQosBearerSessions == other.mQosBearerSessions :
+ mQosBearerSessions.size() == other.mQosBearerSessions.size()
+ && mQosBearerSessions.containsAll(other.mQosBearerSessions);
return mCause == other.mCause
&& mSuggestedRetryTime == other.mSuggestedRetryTime
@@ -472,7 +472,7 @@ public final class DataCallResponse implements Parcelable {
&& mHandoverFailureMode == other.mHandoverFailureMode
&& mPduSessionId == other.mPduSessionId
&& isQosSame
- && isQosSessionsSame
+ && isQosBearerSessionsSame
&& Objects.equals(mSliceInfo, other.mSliceInfo);
}
@@ -481,7 +481,7 @@ public final class DataCallResponse implements Parcelable {
return Objects.hash(mCause, mSuggestedRetryTime, mId, mLinkStatus, mProtocolType,
mInterfaceName, mAddresses, mDnsAddresses, mGatewayAddresses, mPcscfAddresses,
mMtu, mMtuV4, mMtuV6, mHandoverFailureMode, mPduSessionId, mDefaultQos,
- mQosSessions, mSliceInfo);
+ mQosBearerSessions, mSliceInfo);
}
@Override
@@ -515,7 +515,7 @@ public final class DataCallResponse implements Parcelable {
} else {
dest.writeParcelable(null, flags);
}
- dest.writeList(mQosSessions);
+ dest.writeList(mQosBearerSessions);
dest.writeParcelable(mSliceInfo, flags);
}
@@ -598,7 +598,7 @@ public final class DataCallResponse implements Parcelable {
private Qos mDefaultQos;
- private List<QosSession> mQosSessions = new ArrayList<>();
+ private List<QosBearerSession> mQosBearerSessions = new ArrayList<>();
private SliceInfo mSliceInfo;
@@ -812,15 +812,16 @@ public final class DataCallResponse implements Parcelable {
/**
* Set the dedicated bearer QOS sessions for this data connection.
*
- * @param qosSessions Dedicated bearer QOS (Quality Of Service) sessions received
+ * @param qosBearerSessions Dedicated bearer QOS (Quality Of Service) sessions received
* from network.
*
* @return The same instance of the builder.
*
* @hide
*/
- public @NonNull Builder setQosSessions(@NonNull List<QosSession> qosSessions) {
- mQosSessions = qosSessions;
+ public @NonNull Builder setQosBearerSessions(
+ @NonNull List<QosBearerSession> qosBearerSessions) {
+ mQosBearerSessions = qosBearerSessions;
return this;
}
@@ -848,7 +849,7 @@ public final class DataCallResponse implements Parcelable {
return new DataCallResponse(mCause, mSuggestedRetryTime, mId, mLinkStatus,
mProtocolType, mInterfaceName, mAddresses, mDnsAddresses, mGatewayAddresses,
mPcscfAddresses, mMtu, mMtuV4, mMtuV6, mHandoverFailureMode, mPduSessionId,
- mDefaultQos, mQosSessions, mSliceInfo);
+ mDefaultQos, mQosBearerSessions, mSliceInfo);
}
}
}
diff --git a/telephony/java/android/telephony/data/EpsQos.java b/telephony/java/android/telephony/data/EpsQos.java
index ad43068b2f11..22c8b0a0a74f 100644
--- a/telephony/java/android/telephony/data/EpsQos.java
+++ b/telephony/java/android/telephony/data/EpsQos.java
@@ -48,6 +48,10 @@ public final class EpsQos extends Qos implements Parcelable {
qosClassId = source.readInt();
}
+ public int getQci() {
+ return qosClassId;
+ }
+
public static @NonNull EpsQos createFromParcelBody(@NonNull Parcel in) {
return new EpsQos(in);
}
diff --git a/telephony/java/android/telephony/data/Qos.java b/telephony/java/android/telephony/data/Qos.java
index c8bb91e28bf2..c286c6217450 100644
--- a/telephony/java/android/telephony/data/Qos.java
+++ b/telephony/java/android/telephony/data/Qos.java
@@ -56,7 +56,15 @@ public abstract class Qos {
this.uplink = new QosBandwidth(uplink.maxBitrateKbps, uplink.guaranteedBitrateKbps);
}
- static class QosBandwidth implements Parcelable {
+ public QosBandwidth getDownlinkBandwidth() {
+ return downlink;
+ }
+
+ public QosBandwidth getUplinkBandwidth() {
+ return uplink;
+ }
+
+ public static class QosBandwidth implements Parcelable {
int maxBitrateKbps;
int guaranteedBitrateKbps;
@@ -73,6 +81,14 @@ public abstract class Qos {
guaranteedBitrateKbps = source.readInt();
}
+ public int getMaxBitrateKbps() {
+ return maxBitrateKbps;
+ }
+
+ public int getGuaranteedBitrateKbps() {
+ return guaranteedBitrateKbps;
+ }
+
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(maxBitrateKbps);
diff --git a/telephony/java/android/telephony/data/QosFilter.java b/telephony/java/android/telephony/data/QosBearerFilter.java
index 69277445634d..6c1c653f13d0 100644
--- a/telephony/java/android/telephony/data/QosFilter.java
+++ b/telephony/java/android/telephony/data/QosBearerFilter.java
@@ -38,7 +38,7 @@ import java.util.Objects;
*
* @hide
*/
-public final class QosFilter implements Parcelable {
+public final class QosBearerFilter implements Parcelable {
private List<LinkAddress> localAddresses;
private List<LinkAddress> remoteAddresses;
@@ -74,7 +74,7 @@ public final class QosFilter implements Parcelable {
@IntDef(prefix = "QOS_FILTER_DIRECTION_",
value = {QOS_FILTER_DIRECTION_DOWNLINK, QOS_FILTER_DIRECTION_UPLINK,
QOS_FILTER_DIRECTION_BIDIRECTIONAL})
- public @interface QosFilterDirection {}
+ public @interface QosBearerFilterDirection {}
public static final int QOS_FILTER_DIRECTION_DOWNLINK =
android.hardware.radio.V1_6.QosFilterDirection.DOWNLINK;
@@ -83,7 +83,7 @@ public final class QosFilter implements Parcelable {
public static final int QOS_FILTER_DIRECTION_BIDIRECTIONAL =
android.hardware.radio.V1_6.QosFilterDirection.BIDIRECTIONAL;
- @QosFilterDirection
+ @QosBearerFilterDirection
private int filterDirection;
/**
@@ -92,7 +92,7 @@ public final class QosFilter implements Parcelable {
*/
private int precedence;
- QosFilter() {
+ QosBearerFilter() {
localAddresses = new ArrayList<>();
remoteAddresses = new ArrayList<>();
localPort = new PortRange();
@@ -101,7 +101,7 @@ public final class QosFilter implements Parcelable {
filterDirection = QOS_FILTER_DIRECTION_BIDIRECTIONAL;
}
- public QosFilter(List<LinkAddress> localAddresses, List<LinkAddress> remoteAddresses,
+ public QosBearerFilter(List<LinkAddress> localAddresses, List<LinkAddress> remoteAddresses,
PortRange localPort, PortRange remotePort, int protocol, int tos,
long flowLabel, long spi, int direction, int precedence) {
this.localAddresses = localAddresses;
@@ -116,10 +116,30 @@ public final class QosFilter implements Parcelable {
this.precedence = precedence;
}
+ public List<LinkAddress> getLocalAddresses() {
+ return localAddresses;
+ }
+
+ public List<LinkAddress> getRemoteAddresses() {
+ return remoteAddresses;
+ }
+
+ public PortRange getLocalPortRange() {
+ return localPort;
+ }
+
+ public PortRange getRemotePortRange() {
+ return remotePort;
+ }
+
+ public int getPrecedence() {
+ return precedence;
+ }
+
/** @hide */
- public static @NonNull QosFilter create(
+ public static @NonNull QosBearerFilter create(
@NonNull android.hardware.radio.V1_6.QosFilter qosFilter) {
- QosFilter ret = new QosFilter();
+ QosBearerFilter ret = new QosBearerFilter();
String[] localAddresses = qosFilter.localAddresses.stream().toArray(String[]::new);
if (localAddresses != null) {
@@ -202,6 +222,14 @@ public final class QosFilter implements Parcelable {
this.end = end;
}
+ public int getStart() {
+ return start;
+ }
+
+ public int getEnd() {
+ return end;
+ }
+
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(start);
@@ -254,7 +282,7 @@ public final class QosFilter implements Parcelable {
@Override
public String toString() {
- return "QosFilter {"
+ return "QosBearerFilter {"
+ " localAddresses=" + localAddresses
+ " remoteAddresses=" + remoteAddresses
+ " localPort=" + localPort
@@ -278,11 +306,11 @@ public final class QosFilter implements Parcelable {
public boolean equals(Object o) {
if (this == o) return true;
- if (o == null || !(o instanceof QosFilter)) {
+ if (o == null || !(o instanceof QosBearerFilter)) {
return false;
}
- QosFilter other = (QosFilter) o;
+ QosBearerFilter other = (QosBearerFilter) o;
return localAddresses.size() == other.localAddresses.size()
&& localAddresses.containsAll(other.localAddresses)
@@ -324,7 +352,7 @@ public final class QosFilter implements Parcelable {
LinkAddress.LIFETIME_UNKNOWN, LinkAddress.LIFETIME_UNKNOWN);
}
- private QosFilter(Parcel source) {
+ private QosBearerFilter(Parcel source) {
localAddresses = new ArrayList<>();
source.readList(localAddresses, LinkAddress.class.getClassLoader());
remoteAddresses = new ArrayList<>();
@@ -358,16 +386,16 @@ public final class QosFilter implements Parcelable {
return 0;
}
- public static final @NonNull Parcelable.Creator<QosFilter> CREATOR =
- new Parcelable.Creator<QosFilter>() {
+ public static final @NonNull Parcelable.Creator<QosBearerFilter> CREATOR =
+ new Parcelable.Creator<QosBearerFilter>() {
@Override
- public QosFilter createFromParcel(Parcel source) {
- return new QosFilter(source);
+ public QosBearerFilter createFromParcel(Parcel source) {
+ return new QosBearerFilter(source);
}
@Override
- public QosFilter[] newArray(int size) {
- return new QosFilter[size];
+ public QosBearerFilter[] newArray(int size) {
+ return new QosBearerFilter[size];
}
};
}
diff --git a/telephony/java/android/telephony/data/QosBearerSession.java b/telephony/java/android/telephony/data/QosBearerSession.java
new file mode 100644
index 000000000000..30effc9273d7
--- /dev/null
+++ b/telephony/java/android/telephony/data/QosBearerSession.java
@@ -0,0 +1,137 @@
+/**
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony.data;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+
+/**
+ * Class that stores information specific to QOS session.
+ *
+ * @hide
+ */
+public final class QosBearerSession implements Parcelable{
+
+ final int qosBearerSessionId;
+ final Qos qos;
+ final List<QosBearerFilter> qosBearerFilterList;
+
+ public QosBearerSession(int qosBearerSessionId, @NonNull Qos qos, @NonNull List<QosBearerFilter> qosBearerFilterList) {
+ this.qosBearerSessionId = qosBearerSessionId;
+ this.qos = qos;
+ this.qosBearerFilterList = qosBearerFilterList;
+ }
+
+ private QosBearerSession(Parcel source) {
+ qosBearerSessionId = source.readInt();
+ qos = source.readParcelable(Qos.class.getClassLoader());
+ qosBearerFilterList = new ArrayList<>();
+ source.readList(qosBearerFilterList, QosBearerFilter.class.getClassLoader());
+ }
+
+ public int getQosBearerSessionId() {
+ return qosBearerSessionId;
+ }
+
+ public Qos getQos() {
+ return qos;
+ }
+
+ public List<QosBearerFilter> getQosBearerFilterList() {
+ return qosBearerFilterList;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(qosBearerSessionId);
+ if (qos.getType() == Qos.QOS_TYPE_EPS) {
+ dest.writeParcelable((EpsQos)qos, flags);
+ } else {
+ dest.writeParcelable((NrQos)qos, flags);
+ }
+ dest.writeList(qosBearerFilterList);
+ }
+
+ public static @NonNull QosBearerSession create(
+ @NonNull android.hardware.radio.V1_6.QosSession qosSession) {
+ List<QosBearerFilter> qosBearerFilters = new ArrayList<>();
+
+ if (qosSession.qosFilters != null) {
+ for (android.hardware.radio.V1_6.QosFilter filter : qosSession.qosFilters) {
+ qosBearerFilters.add(QosBearerFilter.create(filter));
+ }
+ }
+
+ return new QosBearerSession(
+ qosSession.qosSessionId,
+ Qos.create(qosSession.qos),
+ qosBearerFilters);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public String toString() {
+ return "QosBearerSession {"
+ + " qosBearerSessionId=" + qosBearerSessionId
+ + " qos=" + qos
+ + " qosBearerFilterList=" + qosBearerFilterList + "}";
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(qosBearerSessionId, qos, qosBearerFilterList);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+
+ if (o == null || !(o instanceof QosBearerSession)) {
+ return false;
+ }
+
+ QosBearerSession other = (QosBearerSession) o;
+ return this.qosBearerSessionId == other.qosBearerSessionId
+ && this.qos.equals(other.qos)
+ && this.qosBearerFilterList.size() == other.qosBearerFilterList.size()
+ && this.qosBearerFilterList.containsAll(other.qosBearerFilterList);
+ }
+
+
+ public static final @NonNull Parcelable.Creator<QosBearerSession> CREATOR =
+ new Parcelable.Creator<QosBearerSession>() {
+ @Override
+ public QosBearerSession createFromParcel(Parcel source) {
+ return new QosBearerSession(source);
+ }
+
+ @Override
+ public QosBearerSession[] newArray(int size) {
+ return new QosBearerSession[size];
+ }
+ };
+}
diff --git a/telephony/java/android/telephony/data/QosSession.java b/telephony/java/android/telephony/data/QosSession.java
deleted file mode 100644
index f07b6a9f6725..000000000000
--- a/telephony/java/android/telephony/data/QosSession.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/**
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.data;
-
-import android.annotation.NonNull;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-
-/**
- * Class that stores information specific to QOS session.
- *
- * @hide
- */
-public final class QosSession implements Parcelable{
-
- final int qosSessionId;
- final Qos qos;
- final List<QosFilter> qosFilterList;
-
- public QosSession(int qosSessionId, @NonNull Qos qos, @NonNull List<QosFilter> qosFilterList) {
- this.qosSessionId = qosSessionId;
- this.qos = qos;
- this.qosFilterList = qosFilterList;
- }
-
- private QosSession(Parcel source) {
- qosSessionId = source.readInt();
- qos = source.readParcelable(Qos.class.getClassLoader());
- qosFilterList = new ArrayList<>();
- source.readList(qosFilterList, QosFilter.class.getClassLoader());
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(qosSessionId);
- if (qos.getType() == Qos.QOS_TYPE_EPS) {
- dest.writeParcelable((EpsQos)qos, flags);
- } else {
- dest.writeParcelable((NrQos)qos, flags);
- }
- dest.writeList(qosFilterList);
- }
-
- public static @NonNull QosSession create(
- @NonNull android.hardware.radio.V1_6.QosSession qosSession) {
- List<QosFilter> qosFilters = new ArrayList<>();
-
- if (qosSession.qosFilters != null) {
- for (android.hardware.radio.V1_6.QosFilter filter : qosSession.qosFilters) {
- qosFilters.add(QosFilter.create(filter));
- }
- }
-
- return new QosSession(
- qosSession.qosSessionId,
- Qos.create(qosSession.qos),
- qosFilters);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public String toString() {
- return "QosSession {"
- + " qosSessionId=" + qosSessionId
- + " qos=" + qos
- + " qosFilterList=" + qosFilterList + "}";
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(qosSessionId, qos, qosFilterList);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
-
- if (o == null || !(o instanceof QosSession)) {
- return false;
- }
-
- QosSession other = (QosSession) o;
- return this.qosSessionId == other.qosSessionId
- && this.qos.equals(other.qos)
- && this.qosFilterList.size() == other.qosFilterList.size()
- && this.qosFilterList.containsAll(other.qosFilterList);
- }
-
-
- public static final @NonNull Parcelable.Creator<QosSession> CREATOR =
- new Parcelable.Creator<QosSession>() {
- @Override
- public QosSession createFromParcel(Parcel source) {
- return new QosSession(source);
- }
-
- @Override
- public QosSession[] newArray(int size) {
- return new QosSession[size];
- }
- };
-}
diff --git a/tests/net/common/java/android/net/OemNetworkPreferencesTest.java b/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
index cade5ba3771f..d232a507454d 100644
--- a/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
+++ b/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,22 +20,20 @@ import static com.android.testutils.MiscAsserts.assertThrows;
import static com.android.testutils.ParcelUtils.assertParcelSane;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.os.Build;
-import android.util.SparseArray;
import androidx.test.filters.SmallTest;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
import com.android.testutils.DevSdkIgnoreRunner;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Map;
@IgnoreUpTo(Build.VERSION_CODES.R)
@RunWith(DevSdkIgnoreRunner.class)
@@ -45,51 +43,51 @@ public class OemNetworkPreferencesTest {
private static final int TEST_PREF = OemNetworkPreferences.OEM_NETWORK_PREFERENCE_DEFAULT;
private static final String TEST_PACKAGE = "com.google.apps.contacts";
- private final List<String> mPackages = new ArrayList<>();
private final OemNetworkPreferences.Builder mBuilder = new OemNetworkPreferences.Builder();
- @Before
- public void beforeEachTestMethod() {
- mPackages.add(TEST_PACKAGE);
+ @Test
+ public void testBuilderAddNetworkPreferenceRequiresNonNullPackageName() {
+ assertThrows(NullPointerException.class,
+ () -> mBuilder.addNetworkPreference(null, TEST_PREF));
}
@Test
- public void builderAddNetworkPreferenceRequiresNonNullPackages() {
+ public void testBuilderRemoveNetworkPreferenceRequiresNonNullPackageName() {
assertThrows(NullPointerException.class,
- () -> mBuilder.addNetworkPreference(TEST_PREF, null));
+ () -> mBuilder.removeNetworkPreference(null));
}
@Test
- public void getNetworkPreferencesReturnsCorrectValue() {
+ public void testGetNetworkPreferenceReturnsCorrectValue() {
final int expectedNumberOfMappings = 1;
- mBuilder.addNetworkPreference(TEST_PREF, mPackages);
+ mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
- final SparseArray<List<String>> networkPreferences =
+ final Map<String, Integer> networkPreferences =
mBuilder.build().getNetworkPreferences();
assertEquals(expectedNumberOfMappings, networkPreferences.size());
- assertEquals(mPackages.size(), networkPreferences.get(TEST_PREF).size());
- assertEquals(mPackages.get(0), networkPreferences.get(TEST_PREF).get(0));
+ assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
}
@Test
- public void getNetworkPreferencesReturnsUnmodifiableValue() {
+ public void testGetNetworkPreferenceReturnsUnmodifiableValue() {
final String newPackage = "new.com.google.apps.contacts";
- mBuilder.addNetworkPreference(TEST_PREF, mPackages);
+ mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
- final SparseArray<List<String>> networkPreferences =
+ final Map<String, Integer> networkPreferences =
mBuilder.build().getNetworkPreferences();
assertThrows(UnsupportedOperationException.class,
- () -> networkPreferences.get(TEST_PREF).set(mPackages.size() - 1, newPackage));
+ () -> networkPreferences.put(newPackage, TEST_PREF));
assertThrows(UnsupportedOperationException.class,
- () -> networkPreferences.get(TEST_PREF).add(newPackage));
+ () -> networkPreferences.remove(TEST_PACKAGE));
+
}
@Test
- public void toStringReturnsCorrectValue() {
- mBuilder.addNetworkPreference(TEST_PREF, mPackages);
+ public void testToStringReturnsCorrectValue() {
+ mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
final String networkPreferencesString = mBuilder.build().getNetworkPreferences().toString();
@@ -99,10 +97,56 @@ public class OemNetworkPreferencesTest {
@Test
public void testOemNetworkPreferencesParcelable() {
- mBuilder.addNetworkPreference(TEST_PREF, mPackages);
+ mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
final OemNetworkPreferences prefs = mBuilder.build();
assertParcelSane(prefs, 1 /* fieldCount */);
}
+
+ @Test
+ public void testAddNetworkPreferenceOverwritesPriorPreference() {
+ final int newPref = OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID;
+ mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
+ Map<String, Integer> networkPreferences =
+ mBuilder.build().getNetworkPreferences();
+
+ assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
+ assertEquals(networkPreferences.get(TEST_PACKAGE).intValue(), TEST_PREF);
+
+ mBuilder.addNetworkPreference(TEST_PACKAGE, newPref);
+ networkPreferences = mBuilder.build().getNetworkPreferences();
+
+ assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
+ assertEquals(networkPreferences.get(TEST_PACKAGE).intValue(), newPref);
+ }
+
+ @Test
+ public void testRemoveNetworkPreferenceRemovesValue() {
+ mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
+ Map<String, Integer> networkPreferences =
+ mBuilder.build().getNetworkPreferences();
+
+ assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
+
+ mBuilder.removeNetworkPreference(TEST_PACKAGE);
+ networkPreferences = mBuilder.build().getNetworkPreferences();
+
+ assertFalse(networkPreferences.containsKey(TEST_PACKAGE));
+ }
+
+ @Test
+ public void testConstructorByOemNetworkPreferencesSetsValue() {
+ mBuilder.addNetworkPreference(TEST_PACKAGE, TEST_PREF);
+ OemNetworkPreferences networkPreference = mBuilder.build();
+
+ final Map<String, Integer> networkPreferences =
+ new OemNetworkPreferences
+ .Builder(networkPreference)
+ .build()
+ .getNetworkPreferences();
+
+ assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
+ assertEquals(networkPreferences.get(TEST_PACKAGE).intValue(), TEST_PREF);
+ }
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 0674138044ff..bcbc9e0d6007 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -331,11 +331,12 @@ public class ConnectivityServiceTest {
private static final String TAG = "ConnectivityServiceTest";
private static final int TIMEOUT_MS = 500;
- private static final int TEST_LINGER_DELAY_MS = 300;
- // Chosen to be less than the linger timeout. This ensures that we can distinguish between a
- // LOST callback that arrives immediately and a LOST callback that arrives after the linger
- // timeout. For this, our assertions should run fast enough to leave less than
- // (mService.mLingerDelayMs - TEST_CALLBACK_TIMEOUT_MS) between the time callbacks are
+ private static final int TEST_LINGER_DELAY_MS = 400;
+ private static final int TEST_NASCENT_DELAY_MS = 300;
+ // Chosen to be less than the linger and nascent timeout. This ensures that we can distinguish
+ // between a LOST callback that arrives immediately and a LOST callback that arrives after
+ // the linger/nascent timeout. For this, our assertions should run fast enough to leave
+ // less than (mService.mLingerDelayMs - TEST_CALLBACK_TIMEOUT_MS) between the time callbacks are
// supposedly fired, and the time we call expectCallback.
private static final int TEST_CALLBACK_TIMEOUT_MS = 250;
// Chosen to be less than TEST_CALLBACK_TIMEOUT_MS. This ensures that requests have time to
@@ -1262,6 +1263,13 @@ public class ConnectivityServiceTest {
}
}
+ private void processBroadcastForVpn(Intent intent) {
+ // The BroadcastReceiver for this broadcast checks it is being run on the handler thread.
+ final Handler handler = new Handler(mCsHandlerThread.getLooper());
+ handler.post(() -> mServiceContext.sendBroadcast(intent));
+ waitForIdle();
+ }
+
private void mockUidNetworkingBlocked() {
doAnswer(i -> mContext.getSystemService(NetworkPolicyManager.class)
.checkUidNetworkingBlocked(i.getArgument(0) /* uid */, mUidRules,
@@ -1395,6 +1403,7 @@ public class ConnectivityServiceTest {
mMockNetd,
mDeps);
mService.mLingerDelayMs = TEST_LINGER_DELAY_MS;
+ mService.mNascentDelayMs = TEST_NASCENT_DELAY_MS;
verify(mDeps).makeMultinetworkPolicyTracker(any(), any(), any());
final ArgumentCaptor<INetworkPolicyListener> policyListenerCaptor =
@@ -1737,6 +1746,108 @@ public class ConnectivityServiceTest {
verifyNoNetwork();
}
+ /**
+ * Verify a newly created network will be inactive instead of torn down even if no one is
+ * requesting.
+ */
+ @Test
+ public void testNewNetworkInactive() throws Exception {
+ // Create a callback that monitoring the testing network.
+ final TestNetworkCallback listenCallback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(new NetworkRequest.Builder().build(), listenCallback);
+
+ // 1. Create a network that is not requested by anyone, and does not satisfy any of the
+ // default requests. Verify that the network will be inactive instead of torn down.
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connectWithoutInternet();
+ listenCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ listenCallback.assertNoCallback();
+
+ // Verify that the network will be torn down after nascent expiry. A small period of time
+ // is added in case of flakiness.
+ final int nascentTimeoutMs =
+ mService.mNascentDelayMs + mService.mNascentDelayMs / 4;
+ listenCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent, nascentTimeoutMs);
+
+ // 2. Create a network that is satisfied by a request comes later.
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connectWithoutInternet();
+ listenCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ final NetworkRequest wifiRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI).build();
+ final TestNetworkCallback wifiCallback = new TestNetworkCallback();
+ mCm.requestNetwork(wifiRequest, wifiCallback);
+ wifiCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+
+ // Verify that the network will be kept since the request is still satisfied. And is able
+ // to get disconnected as usual if the request is released after the nascent timer expires.
+ listenCallback.assertNoCallback(nascentTimeoutMs);
+ mCm.unregisterNetworkCallback(wifiCallback);
+ listenCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+
+ // 3. Create a network that is satisfied by a request comes later.
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connectWithoutInternet();
+ listenCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ mCm.requestNetwork(wifiRequest, wifiCallback);
+ wifiCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+
+ // Verify that the network will still be torn down after the request gets removed.
+ mCm.unregisterNetworkCallback(wifiCallback);
+ listenCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+
+ // There is no need to ensure that LOSING is never sent in the common case that the
+ // network immediately satisfies a request that was already present, because it is already
+ // verified anywhere whenever {@code TestNetworkCallback#expectAvailable*} is called.
+
+ mCm.unregisterNetworkCallback(listenCallback);
+ }
+
+ /**
+ * Verify a newly created network will be inactive and switch to background if only background
+ * request is satisfied.
+ */
+ @Test
+ public void testNewNetworkInactive_bgNetwork() throws Exception {
+ // Create a callback that monitoring the wifi network.
+ final TestNetworkCallback wifiListenCallback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI).build(), wifiListenCallback);
+
+ // Create callbacks that can monitor background and foreground mobile networks.
+ // This is done by granting using background networks permission before registration. Thus,
+ // the service will not add {@code NET_CAPABILITY_FOREGROUND} by default.
+ grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid());
+ final TestNetworkCallback bgMobileListenCallback = new TestNetworkCallback();
+ final TestNetworkCallback fgMobileListenCallback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR).build(), bgMobileListenCallback);
+ mCm.registerNetworkCallback(new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_FOREGROUND).build(), fgMobileListenCallback);
+
+ // Connect wifi, which satisfies default request.
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(true);
+ wifiListenCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
+
+ // Connect a cellular network, verify that satisfies only the background callback.
+ setAlwaysOnNetworks(true);
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+ bgMobileListenCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ fgMobileListenCallback.assertNoCallback();
+ assertFalse(isForegroundNetwork(mCellNetworkAgent));
+
+ mCellNetworkAgent.disconnect();
+ bgMobileListenCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ fgMobileListenCallback.assertNoCallback();
+
+ mCm.unregisterNetworkCallback(wifiListenCallback);
+ mCm.unregisterNetworkCallback(bgMobileListenCallback);
+ mCm.unregisterNetworkCallback(fgMobileListenCallback);
+ }
+
@Test
public void testValidatedCellularOutscoresUnvalidatedWiFi() throws Exception {
// Test bringing up unvalidated WiFi
@@ -3894,8 +4005,9 @@ public class ConnectivityServiceTest {
setAlwaysOnNetworks(false);
testFactory.expectRequestRemove();
- // ... and cell data to be torn down.
- cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ // ... and cell data to be torn down after nascent network timeout.
+ cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent,
+ mService.mNascentDelayMs + TEST_CALLBACK_TIMEOUT_MS);
assertLength(1, mCm.getAllNetworks());
} finally {
testFactory.terminate();
@@ -5300,20 +5412,20 @@ public class ConnectivityServiceTest {
// MOBILE_IFNAME even though the default network is wifi.
// TODO: fix this to pass in the actual default network interface. Whether or not the VPN
// applies to the system server UID should not have any bearing on network stats.
- mService.setUnderlyingNetworksForVpn(onlyCell);
+ mMockVpn.setUnderlyingNetworks(onlyCell);
waitForIdle();
expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
new String[]{MOBILE_IFNAME});
reset(mStatsService);
- mService.setUnderlyingNetworksForVpn(cellAndWifi);
+ mMockVpn.setUnderlyingNetworks(cellAndWifi);
waitForIdle();
expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
new String[]{MOBILE_IFNAME, WIFI_IFNAME});
reset(mStatsService);
// Null underlying networks are ignored.
- mService.setUnderlyingNetworksForVpn(cellNullAndWifi);
+ mMockVpn.setUnderlyingNetworks(cellNullAndWifi);
waitForIdle();
expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
new String[]{MOBILE_IFNAME, WIFI_IFNAME});
@@ -5362,25 +5474,25 @@ public class ConnectivityServiceTest {
// is probably a performance improvement (though it's very unlikely that a VPN would declare
// no underlying networks).
// Also, for the same reason as above, the active interface passed in is null.
- mService.setUnderlyingNetworksForVpn(new Network[0]);
+ mMockVpn.setUnderlyingNetworks(new Network[0]);
waitForIdle();
expectForceUpdateIfaces(wifiAndVpn, null);
reset(mStatsService);
// Specifying only a null underlying network is the same as no networks.
- mService.setUnderlyingNetworksForVpn(onlyNull);
+ mMockVpn.setUnderlyingNetworks(onlyNull);
waitForIdle();
expectForceUpdateIfaces(wifiAndVpn, null);
reset(mStatsService);
// Specifying networks that are all disconnected is the same as specifying no networks.
- mService.setUnderlyingNetworksForVpn(onlyCell);
+ mMockVpn.setUnderlyingNetworks(onlyCell);
waitForIdle();
expectForceUpdateIfaces(wifiAndVpn, null);
reset(mStatsService);
// Passing in null again means follow the default network again.
- mService.setUnderlyingNetworksForVpn(null);
+ mMockVpn.setUnderlyingNetworks(null);
waitForIdle();
expectForceUpdateIfaces(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
new String[]{WIFI_IFNAME});
@@ -5855,7 +5967,7 @@ public class ConnectivityServiceTest {
mMockVpn.establishForMyUid(false, true, false);
assertUidRangesUpdatedForMyUid(true);
final Network wifiNetwork = new Network(mNetIdManager.peekNextNetId());
- mService.setUnderlyingNetworksForVpn(new Network[]{wifiNetwork});
+ mMockVpn.setUnderlyingNetworks(new Network[]{wifiNetwork});
callback.expectAvailableCallbacksUnvalidated(mMockVpn);
assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
.hasTransport(TRANSPORT_VPN));
@@ -6049,7 +6161,7 @@ public class ConnectivityServiceTest {
final Set<UidRange> ranges = uidRangesForUid(uid);
mMockVpn.registerAgent(ranges);
- mService.setUnderlyingNetworksForVpn(new Network[0]);
+ mMockVpn.setUnderlyingNetworks(new Network[0]);
// VPN networks do not satisfy the default request and are automatically validated
// by NetworkMonitor
@@ -6297,7 +6409,7 @@ public class ConnectivityServiceTest {
mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
mCellNetworkAgent.connect(true);
- mService.setUnderlyingNetworksForVpn(
+ mMockVpn.setUnderlyingNetworks(
new Network[] { mCellNetworkAgent.getNetwork() });
vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
@@ -6312,7 +6424,7 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
mWiFiNetworkAgent.connect(true);
- mService.setUnderlyingNetworksForVpn(
+ mMockVpn.setUnderlyingNetworks(
new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
@@ -6323,7 +6435,7 @@ public class ConnectivityServiceTest {
assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
// Don't disconnect, but note the VPN is not using wifi any more.
- mService.setUnderlyingNetworksForVpn(
+ mMockVpn.setUnderlyingNetworks(
new Network[] { mCellNetworkAgent.getNetwork() });
vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
@@ -6354,7 +6466,7 @@ public class ConnectivityServiceTest {
vpnNetworkCallback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
// Use Wifi but not cell. Note the VPN is now unmetered and not suspended.
- mService.setUnderlyingNetworksForVpn(
+ mMockVpn.setUnderlyingNetworks(
new Network[] { mWiFiNetworkAgent.getNetwork() });
vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
@@ -6365,7 +6477,7 @@ public class ConnectivityServiceTest {
assertDefaultNetworkCapabilities(userId, mWiFiNetworkAgent);
// Use both again.
- mService.setUnderlyingNetworksForVpn(
+ mMockVpn.setUnderlyingNetworks(
new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
@@ -6380,7 +6492,7 @@ public class ConnectivityServiceTest {
vpnNetworkCallback.assertNoCallback();
// Stop using WiFi. The VPN is suspended again.
- mService.setUnderlyingNetworksForVpn(
+ mMockVpn.setUnderlyingNetworks(
new Network[] { mCellNetworkAgent.getNetwork() });
vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
(caps) -> caps.hasTransport(TRANSPORT_VPN)
@@ -6391,7 +6503,7 @@ public class ConnectivityServiceTest {
assertDefaultNetworkCapabilities(userId, mCellNetworkAgent, mWiFiNetworkAgent);
// Use both again.
- mService.setUnderlyingNetworksForVpn(
+ mMockVpn.setUnderlyingNetworks(
new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
@@ -6526,9 +6638,7 @@ public class ConnectivityServiceTest {
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
// Send a USER_ADDED broadcast for it.
- // The BroadcastReceiver for this broadcast checks that is being run on the handler thread.
- final Handler handler = new Handler(mCsHandlerThread.getLooper());
- handler.post(() -> mServiceContext.sendBroadcast(addedIntent));
+ processBroadcastForVpn(addedIntent);
// Expect that the VPN UID ranges contain both |uid| and the UID range for the newly-added
// restricted user.
@@ -6552,7 +6662,7 @@ public class ConnectivityServiceTest {
// Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
- handler.post(() -> mServiceContext.sendBroadcast(removedIntent));
+ processBroadcastForVpn(removedIntent);
// Expect that the VPN gains the UID range for the restricted user, and that the capability
// change made just before that (i.e., loss of TRANSPORT_WIFI) is preserved.
@@ -6609,9 +6719,7 @@ public class ConnectivityServiceTest {
// TODO: check that VPN app within restricted profile still has access, etc.
final Intent addedIntent = new Intent(ACTION_USER_ADDED);
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
- final Handler handler = new Handler(mCsHandlerThread.getLooper());
- handler.post(() -> mServiceContext.sendBroadcast(addedIntent));
- waitForIdle();
+ processBroadcastForVpn(addedIntent);
assertNull(mCm.getActiveNetworkForUid(uid));
assertNull(mCm.getActiveNetworkForUid(restrictedUid));
@@ -6621,8 +6729,7 @@ public class ConnectivityServiceTest {
// Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER);
- handler.post(() -> mServiceContext.sendBroadcast(removedIntent));
- waitForIdle();
+ processBroadcastForVpn(removedIntent);
assertNull(mCm.getActiveNetworkForUid(uid));
assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
@@ -6724,7 +6831,7 @@ public class ConnectivityServiceTest {
// Ensure VPN is now the active network.
assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
// VPN is using Cell
- mService.setUnderlyingNetworksForVpn(
+ mMockVpn.setUnderlyingNetworks(
new Network[] { mCellNetworkAgent.getNetwork() });
waitForIdle();
@@ -6732,7 +6839,7 @@ public class ConnectivityServiceTest {
assertTrue(mCm.isActiveNetworkMetered());
// VPN is now using WiFi
- mService.setUnderlyingNetworksForVpn(
+ mMockVpn.setUnderlyingNetworks(
new Network[] { mWiFiNetworkAgent.getNetwork() });
waitForIdle();
@@ -6740,7 +6847,7 @@ public class ConnectivityServiceTest {
assertFalse(mCm.isActiveNetworkMetered());
// VPN is using Cell | WiFi.
- mService.setUnderlyingNetworksForVpn(
+ mMockVpn.setUnderlyingNetworks(
new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
waitForIdle();
@@ -6748,7 +6855,7 @@ public class ConnectivityServiceTest {
assertTrue(mCm.isActiveNetworkMetered());
// VPN is using WiFi | Cell.
- mService.setUnderlyingNetworksForVpn(
+ mMockVpn.setUnderlyingNetworks(
new Network[] { mWiFiNetworkAgent.getNetwork(), mCellNetworkAgent.getNetwork() });
waitForIdle();
@@ -6756,7 +6863,7 @@ public class ConnectivityServiceTest {
assertTrue(mCm.isActiveNetworkMetered());
// VPN is not using any underlying networks.
- mService.setUnderlyingNetworksForVpn(new Network[0]);
+ mMockVpn.setUnderlyingNetworks(new Network[0]);
waitForIdle();
// VPN without underlying networks is treated as metered.
@@ -6783,7 +6890,7 @@ public class ConnectivityServiceTest {
assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
// VPN is tracking current platform default (WiFi).
- mService.setUnderlyingNetworksForVpn(null);
+ mMockVpn.setUnderlyingNetworks(null);
waitForIdle();
// Despite VPN using WiFi (which is unmetered), VPN itself is marked as always metered.
@@ -6791,7 +6898,7 @@ public class ConnectivityServiceTest {
// VPN explicitly declares WiFi as its underlying network.
- mService.setUnderlyingNetworksForVpn(
+ mMockVpn.setUnderlyingNetworks(
new Network[] { mWiFiNetworkAgent.getNetwork() });
waitForIdle();
@@ -7199,9 +7306,7 @@ public class ConnectivityServiceTest {
final int userId = UserHandle.getUserId(Process.myUid());
final Intent addedIntent = new Intent(ACTION_USER_UNLOCKED);
addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
- final Handler handler = new Handler(mCsHandlerThread.getLooper());
- handler.post(() -> mServiceContext.sendBroadcast(addedIntent));
- waitForIdle();
+ processBroadcastForVpn(addedIntent);
// Lockdown VPN disables teardown and enables lockdown.
assertFalse(mMockVpn.getEnableTeardown());
@@ -8643,7 +8748,7 @@ public class ConnectivityServiceTest {
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {naiWithoutUid.network}));
+ assertTrue(mMockVpn.setUnderlyingNetworks(new Network[] {naiWithoutUid.network}));
waitForIdle();
assertTrue(
"Active VPN permission not applied",
@@ -8651,7 +8756,7 @@ public class ConnectivityServiceTest {
Process.myPid(), Process.myUid(), naiWithoutUid,
mContext.getOpPackageName()));
- assertTrue(mService.setUnderlyingNetworksForVpn(null));
+ assertTrue(mMockVpn.setUnderlyingNetworks(null));
waitForIdle();
assertFalse(
"VPN shouldn't receive callback on non-underlying network",
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 32c6a75bd904..73cc9f129e79 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -953,14 +953,7 @@ public class VpnTest {
}
private Vpn startLegacyVpn(final Vpn vpn, final VpnProfile vpnProfile) throws Exception {
- // TODO(b/175883995): once these tests have been updated for the changes to the UserManager
- // API, remove this ad-hoc setup code and use setMockedUsers(primaryUser) again.
- // setMockedUsers(primaryUser);
- final ArrayList<UserInfo> users = new ArrayList<>();
- users.add(primaryUser);
- when(mUserManager.getAliveUsers()).thenReturn(users);
- when(mUserManager.getUserInfo(primaryUser.id)).thenReturn(primaryUser);
- when(mUserManager.canHaveRestrictedProfile()).thenReturn(false);
+ setMockedUsers(primaryUser);
// Dummy egress interface
final LinkProperties lp = new LinkProperties();
@@ -1159,10 +1152,6 @@ public class VpnTest {
doReturn(UserHandle.of(userId)).when(asUserContext).getUser();
when(mContext.createContextAsUser(eq(UserHandle.of(userId)), anyInt()))
.thenReturn(asUserContext);
- when(asUserContext.getSystemServiceName(UserManager.class))
- .thenReturn(Context.USER_SERVICE);
- when(asUserContext.getSystemService(UserManager.class))
- .thenReturn(mUserManager);
final TestLooper testLooper = new TestLooper();
final Vpn vpn = new Vpn(testLooper.getLooper(), mContext, new TestDeps(), mNetService,
mNetd, userId, mKeyStore, mSystemServices, mIkev2SessionCreator);
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index aeb142b901d2..1fe13fe97fbe 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -28,8 +28,6 @@ import android.view.IWindowManager;
import junit.framework.TestCase;
-import org.junit.Test;
-
/**
* TODO: Remove this. This is only a placeholder, need to implement this.
*/
@@ -56,7 +54,7 @@ public class WindowManagerPermissionTests extends TestCase {
}
try {
- mWm.addWindowToken(null, TYPE_APPLICATION, DEFAULT_DISPLAY);
+ mWm.addWindowToken(null, TYPE_APPLICATION, DEFAULT_DISPLAY, null /* options */);
fail("IWindowManager.addWindowToken did not throw SecurityException as"
+ " expected");
} catch (SecurityException e) {
@@ -155,29 +153,4 @@ public class WindowManagerPermissionTests extends TestCase {
fail("Unexpected remote exception");
}
}
-
- @Test
- public void testADD_WINDOW_TOKEN_WITH_OPTIONS() {
- // Verify if addWindowTokenWithOptions throw SecurityException for privileged window type.
- try {
- mWm.addWindowTokenWithOptions(null, TYPE_APPLICATION, DEFAULT_DISPLAY, null, "");
- fail("IWindowManager.addWindowTokenWithOptions did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
-
- // Verify if addWindowTokenWithOptions throw SecurityException for null packageName.
- try {
- mWm.addWindowTokenWithOptions(null, TYPE_APPLICATION, DEFAULT_DISPLAY, null, null);
- fail("IWindowManager.addWindowTokenWithOptions did not throw SecurityException as"
- + " expected");
- } catch (SecurityException e) {
- // expected
- } catch (RemoteException e) {
- fail("Unexpected remote exception");
- }
- }
}