summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--StubLibraries.bp4
-rw-r--r--apct-tests/perftests/autofill/src/android/view/autofill/AutofillTestHelper.java81
-rw-r--r--apct-tests/perftests/autofill/src/android/view/autofill/AutofillTestWatcher.java36
-rw-r--r--apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java34
-rw-r--r--apct-tests/perftests/autofill/src/android/view/autofill/MyAutofillService.java49
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java25
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java220
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl16
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java237
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/exceptions/IllegalSchemaException.java (renamed from apex/appsearch/framework/java/android/app/appsearch/IllegalSchemaException.java)6
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/exceptions/IllegalSearchSpecException.java (renamed from apex/appsearch/framework/java/android/app/appsearch/IllegalSearchSpecException.java)8
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java73
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/converter/SchemaToProtoConverter.java127
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/converter/SearchSpecToProtoConverter.java111
-rw-r--r--apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java36
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java14
-rw-r--r--apex/statsd/framework/java/android/app/StatsManager.java2
-rw-r--r--api/Android.bp14
-rw-r--r--api/current.txt13
-rwxr-xr-xapi/gen_combined_removed_dex.sh11
-rw-r--r--api/module-lib-current.txt4
-rw-r--r--api/system-current.txt1
-rw-r--r--api/system-lint-baseline.txt2
-rw-r--r--api/test-current.txt3
-rw-r--r--cmds/statsd/src/atoms.proto63
-rw-r--r--core/java/android/app/ActivityManagerInternal.java5
-rw-r--r--core/java/android/app/ActivityThread.java37
-rw-r--r--core/java/android/app/AppOpsManager.java109
-rw-r--r--core/java/android/app/UiAutomation.java4
-rw-r--r--core/java/android/app/backup/BackupAgent.java32
-rw-r--r--core/java/android/app/role/RoleControllerManager.java4
-rw-r--r--core/java/android/app/role/RoleManager.java4
-rw-r--r--core/java/android/bluetooth/BluetoothHidDevice.java56
-rw-r--r--core/java/android/bluetooth/le/AdvertiseData.java54
-rw-r--r--core/java/android/bluetooth/le/BluetoothLeAdvertiser.java27
-rw-r--r--core/java/android/content/ContentProvider.java1
-rw-r--r--core/java/android/content/Intent.java11
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl3
-rw-r--r--core/java/android/content/pm/UserInfo.java5
-rw-r--r--core/java/android/hardware/camera2/impl/CameraDeviceImpl.java3
-rw-r--r--core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java3
-rw-r--r--core/java/android/hardware/hdmi/HdmiControlManager.java24
-rw-r--r--core/java/android/hardware/input/InputManager.java27
-rw-r--r--core/java/android/inputmethodservice/AbstractInputMethodService.java12
-rw-r--r--core/java/android/inputmethodservice/IInputMethodWrapper.java19
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java86
-rw-r--r--core/java/android/inputmethodservice/SoftInputWindow.java19
-rw-r--r--core/java/android/net/NetworkScoreManager.java24
-rw-r--r--core/java/android/net/NetworkSpecifier.java8
-rw-r--r--core/java/android/os/Binder.java4
-rw-r--r--core/java/android/os/Looper.java2
-rw-r--r--core/java/android/os/NullVibrator.java4
-rw-r--r--core/java/android/os/SystemVibrator.java10
-rw-r--r--core/java/android/os/VibrationAttributes.java59
-rw-r--r--core/java/android/os/Vibrator.java20
-rw-r--r--core/java/android/permission/PermissionControllerManager.java8
-rw-r--r--core/java/android/provider/Settings.java15
-rw-r--r--core/java/android/telephony/CellBroadcastIntents.java3
-rw-r--r--core/java/android/telephony/PhoneStateListener.java19
-rw-r--r--core/java/android/text/TextUtils.java2
-rw-r--r--core/java/android/text/style/SuggestionSpan.java42
-rw-r--r--core/java/android/util/IconDrawableFactory.java2
-rw-r--r--core/java/android/uwb/UwbManager.java269
-rw-r--r--core/java/android/view/InsetsSource.java8
-rw-r--r--core/java/android/view/InsetsSourceControl.java8
-rw-r--r--core/java/android/view/SurfaceControl.java49
-rw-r--r--core/java/android/view/accessibility/AccessibilityInteractionClient.java12
-rw-r--r--core/java/android/view/accessibility/AccessibilityManager.java2
-rw-r--r--core/java/android/view/textservice/SuggestionsInfo.java8
-rw-r--r--core/java/android/widget/Editor.java43
-rw-r--r--core/java/android/widget/SpellChecker.java16
-rw-r--r--core/java/android/widget/ToastPresenter.java25
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java9
-rw-r--r--core/java/com/android/internal/app/ChooserFlags.java19
-rw-r--r--core/java/com/android/internal/app/IAppOpsService.aidl7
-rw-r--r--core/java/com/android/internal/app/chooser/SelectableTargetInfo.java3
-rw-r--r--core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java8
-rw-r--r--core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java33
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java31
-rw-r--r--core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java96
-rw-r--r--core/java/com/android/internal/os/SystemServerCpuThreadReader.java66
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java16
-rw-r--r--core/java/com/android/internal/util/LocationPermissionChecker.java2
-rw-r--r--core/proto/android/telephony/enums.proto16
-rw-r--r--core/res/AndroidManifest.xml2
-rw-r--r--core/res/res/values-af/strings.xml18
-rw-r--r--core/res/res/values-am/strings.xml18
-rw-r--r--core/res/res/values-ar/strings.xml18
-rw-r--r--core/res/res/values-as/strings.xml18
-rw-r--r--core/res/res/values-az/strings.xml34
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml18
-rw-r--r--core/res/res/values-be/strings.xml26
-rw-r--r--core/res/res/values-bg/strings.xml18
-rw-r--r--core/res/res/values-bn/strings.xml18
-rw-r--r--core/res/res/values-bs/strings.xml18
-rw-r--r--core/res/res/values-ca/strings.xml18
-rw-r--r--core/res/res/values-cs/strings.xml18
-rw-r--r--core/res/res/values-da/strings.xml18
-rw-r--r--core/res/res/values-de/strings.xml18
-rw-r--r--core/res/res/values-el/strings.xml18
-rw-r--r--core/res/res/values-es-rUS/strings.xml18
-rw-r--r--core/res/res/values-es/strings.xml18
-rw-r--r--core/res/res/values-et/strings.xml18
-rw-r--r--core/res/res/values-eu/strings.xml18
-rw-r--r--core/res/res/values-fa/strings.xml18
-rw-r--r--core/res/res/values-fi/strings.xml22
-rw-r--r--core/res/res/values-fr-rCA/strings.xml18
-rw-r--r--core/res/res/values-fr/strings.xml18
-rw-r--r--core/res/res/values-gl/strings.xml18
-rw-r--r--core/res/res/values-gu/strings.xml18
-rw-r--r--core/res/res/values-hi/strings.xml18
-rw-r--r--core/res/res/values-hr/strings.xml18
-rw-r--r--core/res/res/values-hu/strings.xml18
-rw-r--r--core/res/res/values-hy/strings.xml18
-rw-r--r--core/res/res/values-in/strings.xml18
-rw-r--r--core/res/res/values-is/strings.xml18
-rw-r--r--core/res/res/values-it/strings.xml18
-rw-r--r--core/res/res/values-iw/strings.xml18
-rw-r--r--core/res/res/values-ja/strings.xml18
-rw-r--r--core/res/res/values-ka/strings.xml18
-rw-r--r--core/res/res/values-kk/strings.xml18
-rw-r--r--core/res/res/values-km/strings.xml18
-rw-r--r--core/res/res/values-kn/strings.xml18
-rw-r--r--core/res/res/values-ko/strings.xml18
-rw-r--r--core/res/res/values-ky/strings.xml18
-rw-r--r--core/res/res/values-lo/strings.xml18
-rw-r--r--core/res/res/values-lt/strings.xml18
-rw-r--r--core/res/res/values-lv/strings.xml18
-rw-r--r--core/res/res/values-mk/strings.xml18
-rw-r--r--core/res/res/values-ml/strings.xml18
-rw-r--r--core/res/res/values-mn/strings.xml18
-rw-r--r--core/res/res/values-mr/strings.xml18
-rw-r--r--core/res/res/values-ms/strings.xml18
-rw-r--r--core/res/res/values-my/strings.xml20
-rw-r--r--core/res/res/values-nb/strings.xml20
-rw-r--r--core/res/res/values-ne/strings.xml18
-rw-r--r--core/res/res/values-nl/strings.xml18
-rw-r--r--core/res/res/values-or/strings.xml18
-rw-r--r--core/res/res/values-pl/strings.xml18
-rw-r--r--core/res/res/values-pt-rPT/strings.xml18
-rw-r--r--core/res/res/values-ro/strings.xml18
-rw-r--r--core/res/res/values-ru/strings.xml18
-rw-r--r--core/res/res/values-si/strings.xml18
-rw-r--r--core/res/res/values-sk/strings.xml18
-rw-r--r--core/res/res/values-sl/strings.xml18
-rw-r--r--core/res/res/values-sq/strings.xml18
-rw-r--r--core/res/res/values-sr/strings.xml18
-rw-r--r--core/res/res/values-sv/strings.xml18
-rw-r--r--core/res/res/values-sw/strings.xml18
-rw-r--r--core/res/res/values-ta/strings.xml18
-rw-r--r--core/res/res/values-te/strings.xml18
-rw-r--r--core/res/res/values-th/strings.xml18
-rw-r--r--core/res/res/values-tl/strings.xml18
-rw-r--r--core/res/res/values-tr/strings.xml18
-rw-r--r--core/res/res/values-uk/strings.xml20
-rw-r--r--core/res/res/values-ur/strings.xml18
-rw-r--r--core/res/res/values-uz/strings.xml18
-rw-r--r--core/res/res/values-vi/strings.xml18
-rw-r--r--core/res/res/values-zh-rCN/strings.xml18
-rw-r--r--core/res/res/values-zh-rHK/strings.xml18
-rw-r--r--core/res/res/values-zh-rTW/strings.xml18
-rw-r--r--core/res/res/values-zu/strings.xml18
-rw-r--r--core/res/res/values/attrs.xml3
-rw-r--r--core/res/res/values/styles.xml4
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/res/res/values/themes.xml1
-rw-r--r--core/tests/coretests/AndroidManifest.xml3
-rw-r--r--core/tests/coretests/src/android/app/activity/ActivityThreadTest.java50
-rw-r--r--core/tests/coretests/src/android/app/appsearch/AppSearchSchemaTest.java171
-rw-r--r--core/tests/coretests/src/android/app/appsearch/SearchResultsTest.java2
-rw-r--r--core/tests/coretests/src/android/app/appsearch/external/app/AppSearchSchemaTest.java74
-rw-r--r--core/tests/coretests/src/android/os/VibratorTest.java124
-rw-r--r--core/tests/coretests/src/android/text/TextUtilsTest.java1
-rw-r--r--core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java26
-rw-r--r--core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java10
-rw-r--r--data/etc/services.core.protolog.json18
-rw-r--r--drm/jni/Android.bp1
-rw-r--r--errorprone/java/com/google/errorprone/bugpatterns/android/PendingIntentMutabilityChecker.java81
-rw-r--r--errorprone/tests/java/com/google/errorprone/bugpatterns/android/PendingIntentMutabilityCheckerTest.java292
-rw-r--r--errorprone/tests/res/android/app/PendingIntent.java69
-rw-r--r--errorprone/tests/res/android/content/Intent.java20
-rw-r--r--errorprone/tests/res/android/os/Bundle.java20
-rw-r--r--graphics/java/android/graphics/GraphicsStatsService.java4
-rw-r--r--graphics/java/android/graphics/RuntimeShader.java44
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java80
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java80
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt53
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt217
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml9
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_ime.xml27
-rw-r--r--libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/ImeActivity.java33
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java231
-rw-r--r--libs/hwui/jni/Shader.cpp18
-rw-r--r--libs/hwui/pipeline/skia/ShaderCache.cpp4
-rw-r--r--libs/hwui/pipeline/skia/ShaderCache.h2
-rw-r--r--libs/hwui/renderthread/CacheManager.cpp2
-rw-r--r--libs/hwui/renderthread/CacheManager.h6
-rw-r--r--libs/hwui/renderthread/IRenderPipeline.h2
-rw-r--r--libs/hwui/renderthread/VulkanSurface.cpp5
-rw-r--r--libs/hwui/renderthread/VulkanSurface.h6
-rw-r--r--media/java/android/media/midi/MidiDeviceServer.java14
-rw-r--r--media/java/android/media/permission/ClearCallingIdentityContext.java2
-rw-r--r--media/java/android/media/session/ISessionManager.aidl4
-rw-r--r--media/java/android/media/session/MediaSessionManager.java80
-rw-r--r--non-updatable-api/current.txt9
-rw-r--r--non-updatable-api/module-lib-current.txt4
-rw-r--r--packages/CarSystemUI/res/layout/sysui_overlay_window.xml3
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java27
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java13
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java8
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/window/SystemUIOverlayWindowController.java6
-rw-r--r--packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml51
-rw-r--r--packages/SettingsLib/res/layout/restricted_popup_menu_item.xml47
-rw-r--r--packages/SettingsLib/res/layout/user_creation_progress_dialog.xml27
-rw-r--r--packages/SettingsLib/res/values/dimens.xml4
-rw-r--r--packages/SettingsLib/res/values/strings.xml12
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/users/ActivityStarter.java31
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/users/EditUserInfoController.java219
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java509
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/users/PhotoCapabilityUtils.java76
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/users/UserCreatingDialog.java58
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java270
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java1
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java1
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--packages/SystemUI/AndroidManifest.xml15
-rw-r--r--packages/SystemUI/docs/plugin_hooks.md30
-rw-r--r--packages/SystemUI/plugin/src/com/android/systemui/plugins/ToastPlugin.java107
-rw-r--r--packages/SystemUI/res/drawable/people_space_tile_view_card.xml28
-rw-r--r--packages/SystemUI/res/layout/activity_create_new_user.xml23
-rw-r--r--packages/SystemUI/res/layout/people_space_activity.xml45
-rw-r--r--packages/SystemUI/res/layout/people_space_tile_view.xml65
-rw-r--r--packages/SystemUI/res/values/strings.xml14
-rw-r--r--packages/SystemUI/res/values/styles.xml7
-rw-r--r--packages/SystemUI/res/xml/fileprovider.xml1
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java35
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/dagger/ToastLog.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java169
-rw-r--r--packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java83
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java82
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplies.java223
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartRepliesAndActionsInflater.kt462
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java316
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java67
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/SmartRepliesInflationModule.kt34
-rw-r--r--packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java139
-rw-r--r--packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java83
-rw-r--r--packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt59
-rw-r--r--packages/SystemUI/src/com/android/systemui/toast/ToastUI.java74
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java161
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/UserCreator.java82
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/UserModule.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java56
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java63
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java202
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java1
-rw-r--r--packages/Tethering/src/android/net/ip/IpServer.java8
-rw-r--r--packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java76
-rw-r--r--packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java18
-rw-r--r--packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java162
-rw-r--r--services/Android.bp1
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java4
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java6
-rw-r--r--services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java43
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java27
-rw-r--r--services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java15
-rw-r--r--services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java2
-rw-r--r--services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java11
-rw-r--r--services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java43
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java4
-rw-r--r--services/backup/java/com/android/server/backup/UserBackupManagerService.java42
-rw-r--r--services/backup/java/com/android/server/backup/internal/BackupHandler.java2
-rw-r--r--services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java8
-rw-r--r--services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java3
-rw-r--r--services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java9
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java2
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java46
-rw-r--r--services/core/java/com/android/server/BatteryService.java6
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java6
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java1
-rw-r--r--services/core/java/com/android/server/MmsServiceBroker.java2
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java2
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java8
-rw-r--r--services/core/java/com/android/server/UpdateLockService.java2
-rw-r--r--services/core/java/com/android/server/VibratorService.java67
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java110
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java29
-rw-r--r--services/core/java/com/android/server/am/AppErrors.java6
-rw-r--r--services/core/java/com/android/server/am/AppExitInfoTracker.java2
-rw-r--r--services/core/java/com/android/server/am/BatteryStatsService.java6
-rw-r--r--services/core/java/com/android/server/am/ContentProviderHelper.java4
-rw-r--r--services/core/java/com/android/server/am/PendingIntentController.java10
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java6
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java13
-rw-r--r--services/core/java/com/android/server/am/ProcessStatsService.java2
-rw-r--r--services/core/java/com/android/server/am/UserController.java2
-rw-r--r--services/core/java/com/android/server/appop/AppOpsService.java286
-rw-r--r--services/core/java/com/android/server/attention/AttentionManagerService.java45
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java2
-rw-r--r--services/core/java/com/android/server/connectivity/PacManager.java2
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java23
-rw-r--r--services/core/java/com/android/server/content/ContentService.java38
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java2
-rw-r--r--services/core/java/com/android/server/devicestate/DeviceStateManagerService.java270
-rw-r--r--services/core/java/com/android/server/devicestate/DeviceStatePolicy.java40
-rw-r--r--services/core/java/com/android/server/devicestate/DeviceStateProvider.java69
-rw-r--r--services/core/java/com/android/server/devicestate/OWNERS3
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceRepository.java62
-rw-r--r--services/core/java/com/android/server/display/DisplayManagerService.java386
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplayMapper.java243
-rw-r--r--services/core/java/com/android/server/display/PersistentDataStore.java24
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java2
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java22
-rw-r--r--services/core/java/com/android/server/inputmethod/InputContentUriTokenHandler.java2
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java450
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodMenuController.java354
-rw-r--r--services/core/java/com/android/server/location/AbstractLocationProvider.java8
-rw-r--r--services/core/java/com/android/server/location/LocationProviderManager.java26
-rw-r--r--services/core/java/com/android/server/location/PassiveLocationProviderManager.java2
-rw-r--r--services/core/java/com/android/server/location/geofence/GeofenceManager.java4
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java4
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssLocationProvider.java2
-rw-r--r--services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java4
-rw-r--r--services/core/java/com/android/server/location/timezone/NullLocationTimeZoneProvider.java2
-rw-r--r--services/core/java/com/android/server/location/util/SystemAppForegroundHelper.java2
-rw-r--r--services/core/java/com/android/server/location/util/SystemAppOpsHelper.java10
-rw-r--r--services/core/java/com/android/server/location/util/SystemLocationPermissionsHelper.java2
-rw-r--r--services/core/java/com/android/server/location/util/SystemSettingsHelper.java16
-rw-r--r--services/core/java/com/android/server/location/util/SystemUserInfoHelper.java6
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java6
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java4
-rw-r--r--services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java4
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java8
-rw-r--r--services/core/java/com/android/server/net/TEST_MAPPING3
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java50
-rw-r--r--services/core/java/com/android/server/notification/NotificationShellCmd.java2
-rw-r--r--services/core/java/com/android/server/notification/ScheduleConditionProvider.java2
-rw-r--r--services/core/java/com/android/server/notification/SnoozeHelper.java2
-rw-r--r--services/core/java/com/android/server/pm/DumpState.java1
-rw-r--r--services/core/java/com/android/server/pm/InstantAppRegistry.java4
-rw-r--r--services/core/java/com/android/server/pm/InstantAppResolverConnection.java2
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java14
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java7
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java9
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java160
-rw-r--r--services/core/java/com/android/server/pm/ProcessLoggingHandler.java187
-rw-r--r--services/core/java/com/android/server/pm/Settings.java2
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java192
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java14
-rw-r--r--services/core/java/com/android/server/pm/dex/ArtManagerService.java2
-rw-r--r--services/core/java/com/android/server/pm/dex/ViewCompiler.java2
-rw-r--r--services/core/java/com/android/server/pm/permission/OWNERS2
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java8
-rw-r--r--services/core/java/com/android/server/policy/DeviceStatePolicyImpl.java44
-rw-r--r--services/core/java/com/android/server/policy/DeviceStateProviderImpl.java45
-rw-r--r--services/core/java/com/android/server/power/AttentionDetector.java23
-rw-r--r--services/core/java/com/android/server/role/RoleManagerService.java4
-rw-r--r--services/core/java/com/android/server/search/Searchables.java2
-rw-r--r--services/core/java/com/android/server/slice/SliceManagerService.java6
-rw-r--r--services/core/java/com/android/server/slice/SliceShellCommand.java2
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java6
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java44
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorService.java2
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java6
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java6
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java4
-rw-r--r--services/core/java/com/android/server/webkit/WebViewUpdateService.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java2
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java1
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java79
-rw-r--r--services/core/java/com/android/server/wm/AppTaskImpl.java6
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java37
-rw-r--r--services/core/java/com/android/server/wm/DisplayFrames.java7
-rw-r--r--services/core/java/com/android/server/wm/DisplayPolicy.java1
-rw-r--r--services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java2
-rw-r--r--services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java15
-rw-r--r--services/core/java/com/android/server/wm/InsetsSourceProvider.java45
-rw-r--r--services/core/java/com/android/server/wm/KeyguardController.java2
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java14
-rw-r--r--services/core/java/com/android/server/wm/Session.java16
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotController.java3
-rw-r--r--services/core/java/com/android/server/wm/VrController.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java61
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowProcessController.java88
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java2
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java39
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfaceController.java21
-rw-r--r--services/core/jni/com_android_server_input_InputManagerService.cpp28
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java4
-rw-r--r--services/java/com/android/server/SystemServer.java5
-rw-r--r--services/midi/java/com/android/server/midi/MidiService.java4
-rw-r--r--services/net/java/android/net/ip/IpClientManager.java2
-rw-r--r--services/restrictions/java/com/android/server/restrictions/RestrictionsManagerService.java8
-rw-r--r--services/robotests/backup/src/com/android/server/backup/BackupAgentTimeoutParametersTest.java34
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java8
-rw-r--r--services/tests/servicestests/src/com/android/server/VibratorServiceTest.java73
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java5
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/appsearch/external/localbackend/converter/SchemaToProtoConverterTest.java119
-rw-r--r--services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java34
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java224
-rw-r--r--services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java19
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java18
-rw-r--r--services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java17
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java14
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java78
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java32
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java26
-rw-r--r--services/usb/java/com/android/server/usb/UsbSerialReader.java2
-rw-r--r--services/usb/java/com/android/server/usb/UsbService.java4
-rw-r--r--services/usb/java/com/android/server/usb/UsbUserPermissionManager.java31
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java4
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java4
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java2
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java2
-rwxr-xr-xtelecomm/java/android/telecom/Call.java8
-rw-r--r--telecomm/java/android/telecom/CallScreeningService.java52
-rw-r--r--telecomm/java/android/telecom/DefaultDialerManager.java4
-rw-r--r--telephony/common/android/telephony/LocationAccessPolicy.java2
-rw-r--r--telephony/common/com/android/internal/telephony/util/TelephonyUtils.java4
-rw-r--r--telephony/java/android/telephony/ims/ImsMmTelManager.java2
-rw-r--r--telephony/java/android/telephony/ims/ImsRcsManager.java2
-rw-r--r--telephony/java/android/telephony/ims/ProvisioningManager.java4
-rw-r--r--telephony/java/android/telephony/ims/RcsUceAdapter.java6
-rw-r--r--telephony/java/android/telephony/ims/RegistrationManager.java10
-rw-r--r--telephony/java/android/telephony/mbms/InternalDownloadProgressListener.java2
-rw-r--r--telephony/java/android/telephony/mbms/InternalDownloadSessionCallback.java6
-rw-r--r--telephony/java/android/telephony/mbms/InternalDownloadStatusListener.java2
-rw-r--r--telephony/java/android/telephony/mbms/InternalGroupCallCallback.java6
-rw-r--r--telephony/java/android/telephony/mbms/InternalGroupCallSessionCallback.java8
-rw-r--r--telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java10
-rw-r--r--telephony/java/android/telephony/mbms/InternalStreamingSessionCallback.java6
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java13
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java20
-rw-r--r--tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java41
-rw-r--r--tests/net/java/com/android/server/connectivity/VpnTest.java2
-rw-r--r--tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java3
-rw-r--r--tools/codegen/src/com/android/codegen/Generators.kt7
-rw-r--r--tools/codegen/src/com/android/codegen/SharedConstants.kt2
-rw-r--r--tools/stringslint/stringslint.py12
-rwxr-xr-xtools/stringslint/stringslint_sha.sh2
-rw-r--r--tools/xmlpersistence/src/main/kotlin/Generator.kt6
-rw-r--r--wifi/api/current.txt2
-rw-r--r--wifi/api/system-current.txt1
-rw-r--r--wifi/api/system-lint-baseline.txt7
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java32
-rw-r--r--wifi/java/android/net/wifi/WifiNetworkSuggestion.java56
-rw-r--r--wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java33
-rw-r--r--wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java75
-rw-r--r--wifi/tests/src/android/net/wifi/WifiConfigurationTest.java76
-rw-r--r--wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java26
-rw-r--r--wifi/tests/src/android/net/wifi/hotspot2/PasspointTestUtils.java2
480 files changed, 11742 insertions, 4673 deletions
diff --git a/Android.bp b/Android.bp
index 06f3666c9aab..ae717f17b09f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -601,6 +601,7 @@ java_library {
],
errorprone: {
javacflags: [
+ "-Xep:AndroidFrameworkBinderIdentity:ERROR",
"-Xep:AndroidFrameworkCompatChange:ERROR",
"-Xep:AndroidFrameworkUid:ERROR",
],
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 53053ce87bbe..be24bd716d1c 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -311,6 +311,10 @@ droidstubs {
api_file: "non-updatable-api/module-lib-current.txt",
removed_api_file: "non-updatable-api/module-lib-removed.txt",
},
+ last_released: {
+ api_file: ":android-non-updatable.api.module-lib.latest",
+ removed_api_file: ":android-non-updatable-removed.api.module-lib.latest",
+ },
api_lint: {
enabled: true,
new_since: ":android-non-updatable.api.module-lib.latest",
diff --git a/apct-tests/perftests/autofill/src/android/view/autofill/AutofillTestHelper.java b/apct-tests/perftests/autofill/src/android/view/autofill/AutofillTestHelper.java
new file mode 100644
index 000000000000..0763729c7803
--- /dev/null
+++ b/apct-tests/perftests/autofill/src/android/view/autofill/AutofillTestHelper.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.autofill;
+
+import android.app.assist.AssistStructure;
+import android.app.assist.AssistStructure.ViewNode;
+import android.app.assist.AssistStructure.WindowNode;
+import android.service.autofill.FillContext;
+import android.util.Log;
+
+import java.util.List;
+
+/**
+ * Helper for common funcionalities.
+ */
+public class AutofillTestHelper {
+ private static final String TAG = "AutofillTestHelper";
+
+ /**
+ * Gets a node given its Android resource id, or {@code null} if not found.
+ */
+ public static ViewNode findNodeByResourceId(List<FillContext> contexts, String resourceId) {
+ for (FillContext context : contexts) {
+ ViewNode node = findNodeByResourceId(context.getStructure(), resourceId);
+ if (node != null) {
+ return node;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets a node if it matches the filter criteria for the given id.
+ */
+ private static ViewNode findNodeByResourceId(AssistStructure structure, String id) {
+ Log.v(TAG, "Parsing request for activity " + structure.getActivityComponent());
+ final int nodes = structure.getWindowNodeCount();
+ for (int i = 0; i < nodes; i++) {
+ final WindowNode windowNode = structure.getWindowNodeAt(i);
+ final ViewNode rootNode = windowNode.getRootViewNode();
+ final ViewNode node = findNodeByResourceId(rootNode, id);
+ if (node != null) {
+ return node;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets a node if it matches the filter criteria for the given id.
+ */
+ private static ViewNode findNodeByResourceId(ViewNode node, String id) {
+ if (id.equals(node.getIdEntry())) {
+ return node;
+ }
+ final int childrenSize = node.getChildCount();
+ if (childrenSize > 0) {
+ for (int i = 0; i < childrenSize; i++) {
+ final ViewNode found = findNodeByResourceId(node.getChildAt(i), id);
+ if (found != null) {
+ return found;
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/apct-tests/perftests/autofill/src/android/view/autofill/AutofillTestWatcher.java b/apct-tests/perftests/autofill/src/android/view/autofill/AutofillTestWatcher.java
index 2475d988f107..f65067fe2d92 100644
--- a/apct-tests/perftests/autofill/src/android/view/autofill/AutofillTestWatcher.java
+++ b/apct-tests/perftests/autofill/src/android/view/autofill/AutofillTestWatcher.java
@@ -26,6 +26,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.test.InstrumentationRegistry;
+import com.android.compatibility.common.util.Timeout;
+
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
@@ -50,6 +52,7 @@ final class AutofillTestWatcher extends TestWatcher {
final String testName = description.getDisplayName();
Log.i(TAG, "Starting " + testName);
+ prepareDevice();
enableVerboseLog();
// Prepare the service before each test.
// Disable the current AutofillService.
@@ -81,10 +84,21 @@ final class AutofillTestWatcher extends TestWatcher {
* Uses the {@code settings} binary to set the autofill service.
*/
void setAutofillService() {
+ String serviceName = MyAutofillService.COMPONENT_NAME;
SettingsHelper.syncSet(InstrumentationRegistry.getTargetContext(),
SettingsHelper.NAMESPACE_SECURE,
Settings.Secure.AUTOFILL_SERVICE,
- MyAutofillService.COMPONENT_NAME);
+ serviceName);
+ // Waits until the service is actually enabled.
+ Timeout timeout = new Timeout("CONNECTION_TIMEOUT", GENERIC_TIMEOUT_MS, 2F,
+ GENERIC_TIMEOUT_MS);
+ try {
+ timeout.run("Enabling Autofill service", () -> {
+ return isAutofillServiceEnabled(serviceName) ? serviceName : null;
+ });
+ } catch (Exception e) {
+ throw new AssertionError("Enabling Autofill service failed.");
+ }
}
/**
@@ -96,6 +110,26 @@ final class AutofillTestWatcher extends TestWatcher {
Settings.Secure.AUTOFILL_SERVICE);
}
+ /**
+ * Checks whether the given service is set as the autofill service for the default user.
+ */
+ private boolean isAutofillServiceEnabled(String serviceName) {
+ String actualName = SettingsHelper.get(SettingsHelper.NAMESPACE_SECURE,
+ Settings.Secure.AUTOFILL_SERVICE);
+ return serviceName.equals(actualName);
+ }
+
+ private void prepareDevice() {
+ // Unlock screen.
+ runShellCommand("input keyevent KEYCODE_WAKEUP");
+
+ // Dismiss keyguard, in case it's set as "Swipe to unlock".
+ runShellCommand("wm dismiss-keyguard");
+
+ // Collapse notifications.
+ runShellCommand("cmd statusbar collapse");
+ }
+
private void enableMyAutofillService() {
MyAutofillService.resetStaticState();
MyAutofillService.setEnabled(true);
diff --git a/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java b/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java
index 37b4bde034df..a5d1e00139b5 100644
--- a/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java
+++ b/apct-tests/perftests/autofill/src/android/view/autofill/LoginTest.java
@@ -28,12 +28,14 @@ import androidx.test.filters.LargeTest;
import com.android.perftests.autofill.R;
-import org.junit.Ignore;
import org.junit.Test;
@LargeTest
public class LoginTest extends AbstractAutofillPerfTestCase {
+ public static final String ID_USERNAME = "username";
+ public static final String ID_PASSWORD = "password";
+
private EditText mUsername;
private EditText mPassword;
private AutofillManager mAfm;
@@ -78,6 +80,7 @@ public class LoginTest extends AbstractAutofillPerfTestCase {
// Must first focus in a field to trigger autofill and wait for service response
// outside the loop
mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
+ mTestWatcher.waitServiceConnect();
MyAutofillService.getLastFillRequest();
// Then focus on password so loop start with focus away from username
mActivityRule.runOnUiThread(() -> mPassword.requestFocus());
@@ -94,13 +97,11 @@ public class LoginTest extends AbstractAutofillPerfTestCase {
/**
* Now the service returns autofill data, for both username and password.
*/
- // TODO(b/162216576): fix fail test and re-enable it
- @Ignore
@Test
public void testFocus_autofillBothFields() throws Throwable {
MyAutofillService.newCannedResponse()
- .setUsername(mUsername.getAutofillId(), "user")
- .setPassword(mPassword.getAutofillId(), "pass")
+ .setUsername(ID_USERNAME, "user")
+ .setPassword(ID_PASSWORD, "pass")
.reply();
mTestWatcher.setAutofillService();
@@ -112,6 +113,7 @@ public class LoginTest extends AbstractAutofillPerfTestCase {
// Must first trigger autofill and wait for service response outside the loop
mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
+ mTestWatcher.waitServiceConnect();
MyAutofillService.getLastFillRequest();
callback.expectEvent(mUsername, EVENT_INPUT_SHOWN);
@@ -148,14 +150,12 @@ public class LoginTest extends AbstractAutofillPerfTestCase {
/**
* Now the service returns autofill data, but just for username.
*/
- // TODO(b/162216576): fix fail test and re-enable it
- @Ignore
@Test
public void testFocus_autofillUsernameOnly() throws Throwable {
// Must set ignored ids so focus on password does not trigger new requests
MyAutofillService.newCannedResponse()
- .setUsername(mUsername.getAutofillId(), "user")
- .setIgnored(mPassword.getAutofillId())
+ .setUsername(ID_USERNAME, "user")
+ .setIgnored(ID_PASSWORD)
.reply();
mTestWatcher.setAutofillService();
@@ -167,6 +167,7 @@ public class LoginTest extends AbstractAutofillPerfTestCase {
// Must first trigger autofill and wait for service response outside the loop
mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
+ mTestWatcher.waitServiceConnect();
MyAutofillService.getLastFillRequest();
callback.expectEvent(mUsername, EVENT_INPUT_SHOWN);
@@ -224,8 +225,8 @@ public class LoginTest extends AbstractAutofillPerfTestCase {
@Test
public void testChange_autofillBothFields() throws Throwable {
MyAutofillService.newCannedResponse()
- .setUsername(mUsername.getAutofillId(), "user")
- .setPassword(mPassword.getAutofillId(), "pass")
+ .setUsername(ID_USERNAME, "user")
+ .setPassword(ID_PASSWORD, "pass")
.reply();
mTestWatcher.setAutofillService();
@@ -239,8 +240,8 @@ public class LoginTest extends AbstractAutofillPerfTestCase {
public void testChange_autofillUsernameOnly() throws Throwable {
// Must set ignored ids so focus on password does not trigger new requests
MyAutofillService.newCannedResponse()
- .setUsername(mUsername.getAutofillId(), "user")
- .setIgnored(mPassword.getAutofillId())
+ .setUsername(ID_USERNAME, "user")
+ .setIgnored(ID_PASSWORD)
.reply();
mTestWatcher.setAutofillService();
@@ -266,13 +267,11 @@ public class LoginTest extends AbstractAutofillPerfTestCase {
}
}
- // TODO(b/162216576): fix fail test and re-enable it
- @Ignore
@Test
public void testCallbacks() throws Throwable {
MyAutofillService.newCannedResponse()
- .setUsername(mUsername.getAutofillId(), "user")
- .setPassword(mPassword.getAutofillId(), "pass")
+ .setUsername(ID_USERNAME, "user")
+ .setPassword(ID_PASSWORD, "pass")
.reply();
mTestWatcher.setAutofillService();
@@ -282,6 +281,7 @@ public class LoginTest extends AbstractAutofillPerfTestCase {
// Must first focus in a field to trigger autofill and wait for service response
// outside the loop
mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
+ mTestWatcher.waitServiceConnect();
MyAutofillService.getLastFillRequest();
callback.expectEvent(mUsername, EVENT_INPUT_SHOWN);
diff --git a/apct-tests/perftests/autofill/src/android/view/autofill/MyAutofillService.java b/apct-tests/perftests/autofill/src/android/view/autofill/MyAutofillService.java
index ddac68b93ebd..5db659796e5f 100644
--- a/apct-tests/perftests/autofill/src/android/view/autofill/MyAutofillService.java
+++ b/apct-tests/perftests/autofill/src/android/view/autofill/MyAutofillService.java
@@ -15,6 +15,7 @@
*/
package android.view.autofill;
+import android.app.assist.AssistStructure.ViewNode;
import android.os.CancellationSignal;
import android.service.autofill.AutofillService;
import android.service.autofill.Dataset;
@@ -126,25 +127,31 @@ public class MyAutofillService extends AutofillService {
onError("ignoring onFillRequest(): response not set", callback);
return;
}
- // TODO(b/162216576): fix error FillResponse
Dataset.Builder dataset = new Dataset.Builder(newDatasetPresentation("dataset"));
boolean hasData = false;
if (response.mUsername != null) {
hasData = true;
- dataset.setValue(response.mUsername.first,
- AutofillValue.forText(response.mUsername.second));
+ AutofillId autofillId = getAutofillIdByResourceId(request, response.mUsername.first);
+ AutofillValue value = AutofillValue.forText(response.mUsername.second);
+ dataset.setValue(autofillId, value, newDatasetPresentation("dataset"));
}
if (response.mPassword != null) {
hasData = true;
- dataset.setValue(response.mPassword.first,
- AutofillValue.forText(response.mPassword.second));
+ AutofillId autofillId = getAutofillIdByResourceId(request, response.mPassword.first);
+ AutofillValue value = AutofillValue.forText(response.mPassword.second);
+ dataset.setValue(autofillId, value, newDatasetPresentation("dataset"));
}
if (hasData) {
FillResponse.Builder fillResponse = new FillResponse.Builder();
if (response.mIgnoredIds != null) {
- fillResponse.setIgnoredIds(response.mIgnoredIds);
+ int length = response.mIgnoredIds.length;
+ AutofillId[] requiredIds = new AutofillId[length];
+ for (int i = 0; i < length; i++) {
+ String resourceId = response.mIgnoredIds[i];
+ requiredIds[i] = getAutofillIdByResourceId(request, resourceId);
+ }
+ fillResponse.setIgnoredIds(requiredIds);
}
-
callback.onSuccess(fillResponse.addDataset(dataset.build()).build());
} else {
callback.onSuccess(null);
@@ -154,6 +161,16 @@ public class MyAutofillService extends AutofillService {
}
}
+ private AutofillId getAutofillIdByResourceId(FillRequest request, String resourceId)
+ throws Exception {
+ ViewNode node = AutofillTestHelper.findNodeByResourceId(request.getFillContexts(),
+ resourceId);
+ if (node == null) {
+ throw new AssertionError("No node with resource id " + resourceId);
+ }
+ return node.getAutofillId();
+ }
+
@Override
public void onSaveRequest(SaveRequest request, SaveCallback callback) {
// No current test should have triggered it...
@@ -162,9 +179,9 @@ public class MyAutofillService extends AutofillService {
}
static final class CannedResponse {
- private final Pair<AutofillId, String> mUsername;
- private final Pair<AutofillId, String> mPassword;
- private final AutofillId[] mIgnoredIds;
+ private final Pair<String, String> mUsername;
+ private final Pair<String, String> mPassword;
+ private final String[] mIgnoredIds;
private CannedResponse(@NonNull Builder builder) {
mUsername = builder.mUsername;
@@ -173,24 +190,24 @@ public class MyAutofillService extends AutofillService {
}
static class Builder {
- private Pair<AutofillId, String> mUsername;
- private Pair<AutofillId, String> mPassword;
- private AutofillId[] mIgnoredIds;
+ private Pair<String, String> mUsername;
+ private Pair<String, String> mPassword;
+ private String[] mIgnoredIds;
@NonNull
- Builder setUsername(@NonNull AutofillId id, @NonNull String value) {
+ Builder setUsername(@NonNull String id, @NonNull String value) {
mUsername = new Pair<>(id, value);
return this;
}
@NonNull
- Builder setPassword(@NonNull AutofillId id, @NonNull String value) {
+ Builder setPassword(@NonNull String id, @NonNull String value) {
mPassword = new Pair<>(id, value);
return this;
}
@NonNull
- Builder setIgnored(AutofillId... ids) {
+ Builder setIgnored(String... ids) {
mIgnoredIds = ids;
return this;
}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
index 64264c03f79e..ad51a5c4158e 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
@@ -18,14 +18,13 @@ package android.app.appsearch;
import android.annotation.NonNull;
import android.annotation.SystemService;
import android.content.Context;
+import android.os.Bundle;
import android.os.RemoteException;
import com.android.internal.infra.AndroidFuture;
import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.SchemaProto;
import com.google.android.icing.proto.SearchResultProto;
-import com.google.android.icing.proto.SearchSpecProto;
import com.google.android.icing.proto.StatusProto;
import com.google.protobuf.InvalidProtocolBufferException;
@@ -133,19 +132,15 @@ public class AppSearchManager {
@NonNull
public AppSearchResult<Void> setSchema(
@NonNull List<AppSearchSchema> schemas, boolean forceOverride) {
- // Prepare the merged schema for transmission.
- SchemaProto.Builder schemaProtoBuilder = SchemaProto.newBuilder();
- for (AppSearchSchema schema : schemas) {
- schemaProtoBuilder.addTypes(schema.getProto());
- }
-
- // Serialize and send the schema.
// TODO: This should use com.android.internal.infra.RemoteStream or another mechanism to
// avoid binder limits.
- byte[] schemaBytes = schemaProtoBuilder.build().toByteArray();
+ List<Bundle> schemaBundles = new ArrayList<>(schemas.size());
+ for (AppSearchSchema schema : schemas) {
+ schemaBundles.add(schema.getBundle());
+ }
AndroidFuture<AppSearchResult> future = new AndroidFuture<>();
try {
- mService.setSchema(schemaBytes, forceOverride, future);
+ mService.setSchema(schemaBundles, forceOverride, future);
} catch (RemoteException e) {
future.completeExceptionally(e);
}
@@ -298,13 +293,7 @@ public class AppSearchManager {
// them in one big list.
AndroidFuture<AppSearchResult> searchResultFuture = new AndroidFuture<>();
try {
- SearchSpecProto searchSpecProto = searchSpec.getSearchSpecProto();
- searchSpecProto = searchSpecProto.toBuilder().setQuery(queryExpression).build();
- mService.query(
- searchSpecProto.toByteArray(),
- searchSpec.getResultSpecProto().toByteArray(),
- searchSpec.getScoringSpecProto().toByteArray(),
- searchResultFuture);
+ mService.query(queryExpression, searchSpec.getBundle(), searchResultFuture);
} catch (RemoteException e) {
searchResultFuture.completeExceptionally(e);
}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java
index 4b0b41b1a282..90e4df68f734 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchSchema.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -16,18 +16,18 @@
package android.app.appsearch;
+import android.os.Bundle;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.util.ArraySet;
-import com.android.internal.annotations.VisibleForTesting;
-
-import com.google.android.icing.proto.PropertyConfigProto;
-import com.google.android.icing.proto.SchemaTypeConfigProto;
-import com.google.android.icing.proto.TermMatchType;
+import android.app.appsearch.exceptions.IllegalSchemaException;
+import android.util.ArraySet;
+import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
import java.util.Set;
/**
@@ -36,45 +36,64 @@ import java.util.Set;
* <p>For example, an e-mail message or a music recording could be a schema type.
*
* <p>The schema consists of type information, properties, and config (like tokenization type).
- *
* @hide
*/
public final class AppSearchSchema {
- private final SchemaTypeConfigProto mProto;
+ /** @hide */
+
+ public static final String SCHEMA_TYPE_FIELD = "schemaType";
+
+ /** @hide */
+
+ public static final String PROPERTIES_FIELD = "properties";
- private AppSearchSchema(SchemaTypeConfigProto proto) {
- mProto = proto;
+ private final Bundle mBundle;
+
+ /** @hide */
+
+ public AppSearchSchema(@NonNull Bundle bundle) {
+ Preconditions.checkNotNull(bundle);
+ mBundle = bundle;
}
/**
- * Returns the {@link SchemaTypeConfigProto} populated by this builder.
+ * Returns the {@link Bundle} populated by this builder.
* @hide
*/
+
@NonNull
- @VisibleForTesting
- public SchemaTypeConfigProto getProto() {
- return mProto;
+ public Bundle getBundle() {
+ return mBundle;
}
@Override
public String toString() {
- return mProto.toString();
+ return mBundle.toString();
}
/** Builder for {@link AppSearchSchema objects}. */
public static final class Builder {
- private final SchemaTypeConfigProto.Builder mProtoBuilder =
- SchemaTypeConfigProto.newBuilder();
+ private final String mTypeName;
+ private final ArrayList<Bundle> mProperties = new ArrayList<>();
+ private final Set<String> mPropertyNames = new ArraySet<>();
+ private boolean mBuilt = false;
/** Creates a new {@link AppSearchSchema.Builder}. */
public Builder(@NonNull String typeName) {
- mProtoBuilder.setSchemaType(typeName);
+ Preconditions.checkNotNull(typeName);
+ mTypeName = typeName;
}
/** Adds a property to the given type. */
@NonNull
public AppSearchSchema.Builder addProperty(@NonNull PropertyConfig propertyConfig) {
- mProtoBuilder.addProperties(propertyConfig.mProto);
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkNotNull(propertyConfig);
+ if (!mPropertyNames.add(propertyConfig.mName)) {
+ throw new IllegalSchemaException(
+ "Property defined more than once: " + propertyConfig.mName);
+ }
+ mProperties.add(propertyConfig.mBundle);
return this;
}
@@ -85,15 +104,12 @@ public final class AppSearchSchema {
*/
@NonNull
public AppSearchSchema build() {
- Set<String> propertyNames = new ArraySet<>();
- for (PropertyConfigProto propertyConfigProto : mProtoBuilder.getPropertiesList()) {
- if (!propertyNames.add(propertyConfigProto.getPropertyName())) {
- throw new IllegalSchemaException(
- "Property defined more than once: "
- + propertyConfigProto.getPropertyName());
- }
- }
- return new AppSearchSchema(mProtoBuilder.build());
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Bundle bundle = new Bundle();
+ bundle.putString(AppSearchSchema.SCHEMA_TYPE_FIELD, mTypeName);
+ bundle.putParcelableArrayList(AppSearchSchema.PROPERTIES_FIELD, mProperties);
+ mBuilt = true;
+ return new AppSearchSchema(bundle);
}
}
@@ -104,10 +120,37 @@ public final class AppSearchSchema {
* a property.
*/
public static final class PropertyConfig {
- /** Physical data-types of the contents of the property. */
+ /** @hide */
+
+ public static final String NAME_FIELD = "name";
+
+ /** @hide */
+
+ public static final String DATA_TYPE_FIELD = "dataType";
+
+ /** @hide */
+
+ public static final String SCHEMA_TYPE_FIELD = "schemaType";
+
+ /** @hide */
+
+ public static final String CARDINALITY_FIELD = "cardinality";
+
+ /** @hide */
+
+ public static final String INDEXING_TYPE_FIELD = "indexingType";
+
+ /** @hide */
+
+ public static final String TOKENIZER_TYPE_FIELD = "tokenizerType";
+
+ /**
+ * Physical data-types of the contents of the property.
+ * @hide
+ */
// NOTE: The integer values of these constants must match the proto enum constants in
// com.google.android.icing.proto.PropertyConfigProto.DataType.Code.
- @IntDef(prefix = {"DATA_TYPE_"}, value = {
+ @IntDef(value = {
DATA_TYPE_STRING,
DATA_TYPE_INT64,
DATA_TYPE_DOUBLE,
@@ -133,10 +176,13 @@ public final class AppSearchSchema {
*/
public static final int DATA_TYPE_DOCUMENT = 6;
- /** The cardinality of the property (whether it is required, optional or repeated). */
+ /**
+ * The cardinality of the property (whether it is required, optional or repeated).
+ * @hide
+ */
// NOTE: The integer values of these constants must match the proto enum constants in
// com.google.android.icing.proto.PropertyConfigProto.Cardinality.Code.
- @IntDef(prefix = {"CARDINALITY_"}, value = {
+ @IntDef(value = {
CARDINALITY_REPEATED,
CARDINALITY_OPTIONAL,
CARDINALITY_REQUIRED,
@@ -153,8 +199,11 @@ public final class AppSearchSchema {
/** Exactly one value [1]. */
public static final int CARDINALITY_REQUIRED = 3;
- /** Encapsulates the configurations on how AppSearch should query/index these terms. */
- @IntDef(prefix = {"INDEXING_TYPE_"}, value = {
+ /**
+ * Encapsulates the configurations on how AppSearch should query/index these terms.
+ * @hide
+ */
+ @IntDef(value = {
INDEXING_TYPE_NONE,
INDEXING_TYPE_EXACT_TERMS,
INDEXING_TYPE_PREFIXES,
@@ -188,10 +237,13 @@ public final class AppSearchSchema {
*/
public static final int INDEXING_TYPE_PREFIXES = 2;
- /** Configures how tokens should be extracted from this property. */
+ /**
+ * Configures how tokens should be extracted from this property.
+ * @hide
+ */
// NOTE: The integer values of these constants must match the proto enum constants in
// com.google.android.icing.proto.IndexingConfig.TokenizerType.Code.
- @IntDef(prefix = {"TOKENIZER_TYPE_"}, value = {
+ @IntDef(value = {
TOKENIZER_TYPE_NONE,
TOKENIZER_TYPE_PLAIN,
})
@@ -207,15 +259,17 @@ public final class AppSearchSchema {
/** Tokenization for plain text. */
public static final int TOKENIZER_TYPE_PLAIN = 1;
- private final PropertyConfigProto mProto;
+ final String mName;
+ final Bundle mBundle;
- private PropertyConfig(PropertyConfigProto proto) {
- mProto = proto;
+ PropertyConfig(@NonNull String name, @NonNull Bundle bundle) {
+ mName = Preconditions.checkNotNull(name);
+ mBundle = Preconditions.checkNotNull(bundle);
}
@Override
public String toString() {
- return mProto.toString();
+ return mBundle.toString();
}
/**
@@ -232,15 +286,14 @@ public final class AppSearchSchema {
* is also required.
*/
public static final class Builder {
- private final PropertyConfigProto.Builder mPropertyConfigProto =
- PropertyConfigProto.newBuilder();
- private final com.google.android.icing.proto.IndexingConfig.Builder
- mIndexingConfigProto =
- com.google.android.icing.proto.IndexingConfig.newBuilder();
+ private final String mName;
+ private final Bundle mBundle = new Bundle();
+ private boolean mBuilt = false;
/** Creates a new {@link PropertyConfig.Builder}. */
public Builder(@NonNull String propertyName) {
- mPropertyConfigProto.setPropertyName(propertyName);
+ mName = Preconditions.checkNotNull(propertyName);
+ mBundle.putString(NAME_FIELD, propertyName);
}
/**
@@ -250,24 +303,24 @@ public final class AppSearchSchema {
*/
@NonNull
public PropertyConfig.Builder setDataType(@DataType int dataType) {
- PropertyConfigProto.DataType.Code dataTypeProto =
- PropertyConfigProto.DataType.Code.forNumber(dataType);
- if (dataTypeProto == null) {
- throw new IllegalArgumentException("Invalid dataType: " + dataType);
- }
- mPropertyConfigProto.setDataType(dataTypeProto);
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkArgumentInRange(
+ dataType, DATA_TYPE_STRING, DATA_TYPE_DOCUMENT, "dataType");
+ mBundle.putInt(DATA_TYPE_FIELD, dataType);
return this;
}
/**
* The logical schema-type of the contents of this property.
*
- * <p>Only required when {@link #setDataType(int)} is set to
+ * <p>Only required when {@link #setDataType} is set to
* {@link #DATA_TYPE_DOCUMENT}. Otherwise, it is ignored.
*/
@NonNull
public PropertyConfig.Builder setSchemaType(@NonNull String schemaType) {
- mPropertyConfigProto.setSchemaType(schemaType);
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkNotNull(schemaType);
+ mBundle.putString(SCHEMA_TYPE_FIELD, schemaType);
return this;
}
@@ -278,12 +331,10 @@ public final class AppSearchSchema {
*/
@NonNull
public PropertyConfig.Builder setCardinality(@Cardinality int cardinality) {
- PropertyConfigProto.Cardinality.Code cardinalityProto =
- PropertyConfigProto.Cardinality.Code.forNumber(cardinality);
- if (cardinalityProto == null) {
- throw new IllegalArgumentException("Invalid cardinality: " + cardinality);
- }
- mPropertyConfigProto.setCardinality(cardinalityProto);
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkArgumentInRange(
+ cardinality, CARDINALITY_REPEATED, CARDINALITY_REQUIRED, "cardinality");
+ mBundle.putInt(CARDINALITY_FIELD, cardinality);
return this;
}
@@ -292,35 +343,20 @@ public final class AppSearchSchema {
*/
@NonNull
public PropertyConfig.Builder setIndexingType(@IndexingType int indexingType) {
- TermMatchType.Code termMatchTypeProto;
- switch (indexingType) {
- case INDEXING_TYPE_NONE:
- termMatchTypeProto = TermMatchType.Code.UNKNOWN;
- break;
- case INDEXING_TYPE_EXACT_TERMS:
- termMatchTypeProto = TermMatchType.Code.EXACT_ONLY;
- break;
- case INDEXING_TYPE_PREFIXES:
- termMatchTypeProto = TermMatchType.Code.PREFIX;
- break;
- default:
- throw new IllegalArgumentException("Invalid indexingType: " + indexingType);
- }
- mIndexingConfigProto.setTermMatchType(termMatchTypeProto);
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkArgumentInRange(
+ indexingType, INDEXING_TYPE_NONE, INDEXING_TYPE_PREFIXES, "indexingType");
+ mBundle.putInt(INDEXING_TYPE_FIELD, indexingType);
return this;
}
/** Configures how this property should be tokenized (split into words). */
@NonNull
public PropertyConfig.Builder setTokenizerType(@TokenizerType int tokenizerType) {
- com.google.android.icing.proto.IndexingConfig.TokenizerType.Code
- tokenizerTypeProto =
- com.google.android.icing.proto.IndexingConfig
- .TokenizerType.Code.forNumber(tokenizerType);
- if (tokenizerTypeProto == null) {
- throw new IllegalArgumentException("Invalid tokenizerType: " + tokenizerType);
- }
- mIndexingConfigProto.setTokenizerType(tokenizerTypeProto);
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkArgumentInRange(
+ tokenizerType, TOKENIZER_TYPE_NONE, TOKENIZER_TYPE_PLAIN, "tokenizerType");
+ mBundle.putInt(TOKENIZER_TYPE_FIELD, tokenizerType);
return this;
}
@@ -334,25 +370,23 @@ public final class AppSearchSchema {
*/
@NonNull
public PropertyConfig build() {
- mPropertyConfigProto.setIndexingConfig(mIndexingConfigProto);
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
// TODO(b/147692920): Send the schema to Icing Lib for official validation, instead
// of partially reimplementing some of the validation Icing does here.
- if (mPropertyConfigProto.getDataType()
- == PropertyConfigProto.DataType.Code.UNKNOWN) {
+ if (!mBundle.containsKey(DATA_TYPE_FIELD)) {
throw new IllegalSchemaException("Missing field: dataType");
}
- if (mPropertyConfigProto.getSchemaType().isEmpty()
- && mPropertyConfigProto.getDataType()
- == PropertyConfigProto.DataType.Code.DOCUMENT) {
+ if (mBundle.getString(SCHEMA_TYPE_FIELD, "").isEmpty()
+ && mBundle.getInt(DATA_TYPE_FIELD) == DATA_TYPE_DOCUMENT) {
throw new IllegalSchemaException(
"Missing field: schemaType (required for configs with "
+ "dataType = DOCUMENT)");
}
- if (mPropertyConfigProto.getCardinality()
- == PropertyConfigProto.Cardinality.Code.UNKNOWN) {
+ if (!mBundle.containsKey(CARDINALITY_FIELD)) {
throw new IllegalSchemaException("Missing field: cardinality");
}
- return new PropertyConfig(mPropertyConfigProto.build());
+ mBuilt = true;
+ return new PropertyConfig(mName, mBundle);
}
}
}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
index 68de4f068470..c710a29919e3 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
@@ -15,6 +15,8 @@
*/
package android.app.appsearch;
+import android.os.Bundle;
+
import com.android.internal.infra.AndroidFuture;
parcelable AppSearchResult;
@@ -25,14 +27,16 @@ interface IAppSearchManager {
/**
* Sets the schema.
*
- * @param schemaBytes Serialized SchemaProto.
+ * @param schemaBundles List of AppSearchSchema bundles.
* @param forceOverride Whether to apply the new schema even if it is incompatible. All
* incompatible documents will be deleted.
* @param callback {@link AndroidFuture}&lt;{@link AppSearchResult}&lt;{@link Void}&gt&gt;.
* The results of the call.
*/
void setSchema(
- in byte[] schemaBytes, boolean forceOverride, in AndroidFuture<AppSearchResult> callback);
+ in List<Bundle> schemaBundles,
+ boolean forceOverride,
+ in AndroidFuture<AppSearchResult> callback);
/**
* Inserts documents into the index.
@@ -63,14 +67,14 @@ interface IAppSearchManager {
/**
* Searches a document based on a given specifications.
*
- * @param searchSpecBytes Serialized SearchSpecProto.
- * @param resultSpecBytes Serialized SearchResultsProto.
- * @param scoringSpecBytes Serialized ScoringSpecProto.
+ * @param queryExpression String to search for
+ * @param searchSpecBundle SearchSpec bundle
* @param callback {@link AndroidFuture}&lt;{@link AppSearchResult}&lt;{@link byte[]}&gt;&gt;
* Will be completed with a serialized {@link SearchResultsProto}.
*/
void query(
- in byte[] searchSpecBytes, in byte[] resultSpecBytes, in byte[] scoringSpecBytes,
+ in String queryExpression,
+ in Bundle searchSpecBundle,
in AndroidFuture<AppSearchResult> callback);
/**
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java b/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java
index 6e644ffb8b27..817c3ef5e028 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/SearchSpec.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -16,18 +16,17 @@
package android.app.appsearch;
+import android.os.Bundle;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
-import com.google.android.icing.proto.ResultSpecProto;
-import com.google.android.icing.proto.ScoringSpecProto;
-import com.google.android.icing.proto.SearchSpecProto;
-import com.google.android.icing.proto.TermMatchType;
+import android.app.appsearch.exceptions.IllegalSearchSpecException;
+import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-
/**
* This class represents the specification logic for AppSearch. It can be used to set the type of
* search, like prefix or exact only or apply filters to search for a specific schema type only etc.
@@ -35,67 +34,100 @@ import java.lang.annotation.RetentionPolicy;
*/
// TODO(sidchhabra) : AddResultSpec fields for Snippets etc.
public final class SearchSpec {
+ /** @hide */
+
+ public static final String TERM_MATCH_TYPE_FIELD = "termMatchType";
- private final SearchSpecProto mSearchSpecProto;
- private final ResultSpecProto mResultSpecProto;
- private final ScoringSpecProto mScoringSpecProto;
+ /** @hide */
+
+ public static final String SCHEMA_TYPES_FIELD = "schemaType";
- private SearchSpec(@NonNull SearchSpecProto searchSpecProto,
- @NonNull ResultSpecProto resultSpecProto, @NonNull ScoringSpecProto scoringSpecProto) {
- mSearchSpecProto = searchSpecProto;
- mResultSpecProto = resultSpecProto;
- mScoringSpecProto = scoringSpecProto;
- }
+ /** @hide */
+
+ public static final String NAMESPACE_FIELD = "namespace";
- /** Creates a new {@link SearchSpec.Builder}. */
- @NonNull
- public static SearchSpec.Builder newBuilder() {
- return new SearchSpec.Builder();
- }
+ /** @hide */
+
+ public static final String NUM_PER_PAGE_FIELD = "numPerPage";
/** @hide */
- @NonNull
- SearchSpecProto getSearchSpecProto() {
- return mSearchSpecProto;
- }
+
+ public static final String RANKING_STRATEGY_FIELD = "rankingStrategy";
/** @hide */
- @NonNull
- ResultSpecProto getResultSpecProto() {
- return mResultSpecProto;
- }
+
+ public static final String ORDER_FIELD = "order";
+
+ /** @hide */
+
+ public static final String SNIPPET_COUNT_FIELD = "snippetCount";
+
+ /** @hide */
+
+ public static final String SNIPPET_COUNT_PER_PROPERTY_FIELD = "snippetCountPerProperty";
+
+ /** @hide */
+
+ public static final String MAX_SNIPPET_FIELD = "maxSnippet";
+
+ /** @hide */
+
+ public static final int DEFAULT_NUM_PER_PAGE = 10;
+
+ private static final int MAX_NUM_PER_PAGE = 10_000;
+ private static final int MAX_SNIPPET_COUNT = 10_000;
+ private static final int MAX_SNIPPET_PER_PROPERTY_COUNT = 10_000;
+ private static final int MAX_SNIPPET_SIZE_LIMIT = 10_000;
+
+ private final Bundle mBundle;
/** @hide */
+
+ public SearchSpec(@NonNull Bundle bundle) {
+ Preconditions.checkNotNull(bundle);
+ mBundle = bundle;
+ }
+
+ /**
+ * Returns the {@link Bundle} populated by this builder.
+ * @hide
+ */
@NonNull
- ScoringSpecProto getScoringSpecProto() {
- return mScoringSpecProto;
+ public Bundle getBundle() {
+ return mBundle;
}
- /** Term Match Type for the query. */
+ /**
+ * Term Match Type for the query.
+ * @hide
+ */
// NOTE: The integer values of these constants must match the proto enum constants in
// {@link com.google.android.icing.proto.SearchSpecProto.termMatchType}
- @IntDef(prefix = {"TERM_MATCH_TYPE_"}, value = {
- TERM_MATCH_TYPE_EXACT_ONLY,
- TERM_MATCH_TYPE_PREFIX
+ @IntDef(value = {
+ TERM_MATCH_EXACT_ONLY,
+ TERM_MATCH_PREFIX
})
@Retention(RetentionPolicy.SOURCE)
- public @interface TermMatchTypeCode {}
+ public @interface TermMatchCode {}
/**
* Query terms will only match exact tokens in the index.
* <p>Ex. A query term "foo" will only match indexed token "foo", and not "foot" or "football".
*/
- public static final int TERM_MATCH_TYPE_EXACT_ONLY = 1;
+ public static final int TERM_MATCH_EXACT_ONLY = 1;
/**
* Query terms will match indexed tokens when the query term is a prefix of the token.
* <p>Ex. A query term "foo" will match indexed tokens like "foo", "foot", and "football".
*/
- public static final int TERM_MATCH_TYPE_PREFIX = 2;
+ public static final int TERM_MATCH_PREFIX = 2;
- /** Ranking Strategy for query result.*/
+ /**
+ * Ranking Strategy for query result.
+ * @hide
+ */
// NOTE: The integer values of these constants must match the proto enum constants in
// {@link ScoringSpecProto.RankingStrategy.Code }
- @IntDef(prefix = {"RANKING_STRATEGY_"}, value = {
+ @IntDef(value = {
RANKING_STRATEGY_NONE,
RANKING_STRATEGY_DOCUMENT_SCORE,
RANKING_STRATEGY_CREATION_TIMESTAMP
@@ -110,10 +142,13 @@ public final class SearchSpec {
/** Ranked by document creation timestamps. */
public static final int RANKING_STRATEGY_CREATION_TIMESTAMP = 2;
- /** Order for query result.*/
+ /**
+ * Order for query result.
+ * @hide
+ */
// NOTE: The integer values of these constants must match the proto enum constants in
// {@link ScoringSpecProto.Order.Code }
- @IntDef(prefix = {"ORDER_"}, value = {
+ @IntDef(value = {
ORDER_DESCENDING,
ORDER_ASCENDING
})
@@ -128,27 +163,24 @@ public final class SearchSpec {
/** Builder for {@link SearchSpec objects}. */
public static final class Builder {
- private final SearchSpecProto.Builder mSearchSpecBuilder = SearchSpecProto.newBuilder();
- private final ResultSpecProto.Builder mResultSpecBuilder = ResultSpecProto.newBuilder();
- private final ScoringSpecProto.Builder mScoringSpecBuilder = ScoringSpecProto.newBuilder();
- private final ResultSpecProto.SnippetSpecProto.Builder mSnippetSpecBuilder =
- ResultSpecProto.SnippetSpecProto.newBuilder();
+ private final Bundle mBundle;
+ private boolean mBuilt = false;
- private Builder() {
+ /** Creates a new {@link SearchSpec.Builder}. */
+ public Builder() {
+ mBundle = new Bundle();
+ mBundle.putInt(NUM_PER_PAGE_FIELD, DEFAULT_NUM_PER_PAGE);
}
/**
- * Indicates how the query terms should match {@link TermMatchTypeCode} in the index.
+ * Indicates how the query terms should match {@code TermMatchCode} in the index.
*/
@NonNull
- public Builder setTermMatchType(@TermMatchTypeCode int termMatchTypeCode) {
- TermMatchType.Code termMatchTypeCodeProto =
- TermMatchType.Code.forNumber(termMatchTypeCode);
- if (termMatchTypeCodeProto == null) {
- throw new IllegalArgumentException("Invalid term match type: "
- + termMatchTypeCode);
- }
- mSearchSpecBuilder.setTermMatchType(termMatchTypeCodeProto);
+ public Builder setTermMatch(@TermMatchCode int termMatchTypeCode) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkArgumentInRange(termMatchTypeCode, TERM_MATCH_EXACT_ONLY,
+ TERM_MATCH_PREFIX, "Term match type");
+ mBundle.putInt(TERM_MATCH_TYPE_FIELD, termMatchTypeCode);
return this;
}
@@ -159,31 +191,44 @@ public final class SearchSpec {
*/
@NonNull
public Builder setSchemaTypes(@NonNull String... schemaTypes) {
- for (String schemaType : schemaTypes) {
- mSearchSpecBuilder.addSchemaTypeFilters(schemaType);
- }
+ Preconditions.checkNotNull(schemaTypes);
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ mBundle.putStringArray(SCHEMA_TYPES_FIELD, schemaTypes);
return this;
}
- /** Sets the maximum number of results to retrieve from the query */
+ /**
+ * Adds a namespace filter to {@link SearchSpec} Entry. Only search for documents that
+ * have the specified namespaces.
+ * <p>If unset, the query will search over all namespaces.
+ */
@NonNull
- public SearchSpec.Builder setNumToRetrieve(int numToRetrieve) {
- // Just retrieve everything in one page.
- // TODO(b/152359656): Realign these two apis properly.
- mResultSpecBuilder.setNumPerPage(numToRetrieve);
+ public Builder setNamespaces(@NonNull String... namespaces) {
+ Preconditions.checkNotNull(namespaces);
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ mBundle.putStringArray(NAMESPACE_FIELD, namespaces);
+ return this;
+ }
+
+ /**
+ * Sets the number of results per page in the returned object.
+ * <p> The default number of results per page is 10. And should be set in range [0, 10k].
+ */
+ @NonNull
+ public SearchSpec.Builder setNumPerPage(int numPerPage) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkArgumentInRange(numPerPage, 0, MAX_NUM_PER_PAGE, "NumPerPage");
+ mBundle.putInt(NUM_PER_PAGE_FIELD, numPerPage);
return this;
}
/** Sets ranking strategy for AppSearch results.*/
@NonNull
public Builder setRankingStrategy(@RankingStrategyCode int rankingStrategy) {
- ScoringSpecProto.RankingStrategy.Code rankingStrategyCodeProto =
- ScoringSpecProto.RankingStrategy.Code.forNumber(rankingStrategy);
- if (rankingStrategyCodeProto == null) {
- throw new IllegalArgumentException("Invalid result ranking strategy: "
- + rankingStrategyCodeProto);
- }
- mScoringSpecBuilder.setRankBy(rankingStrategyCodeProto);
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkArgumentInRange(rankingStrategy, RANKING_STRATEGY_NONE,
+ RANKING_STRATEGY_CREATION_TIMESTAMP, "Result ranking strategy");
+ mBundle.putInt(RANKING_STRATEGY_FIELD, rankingStrategy);
return this;
}
@@ -194,37 +239,41 @@ public final class SearchSpec {
*/
@NonNull
public Builder setOrder(@OrderCode int order) {
- ScoringSpecProto.Order.Code orderCodeProto =
- ScoringSpecProto.Order.Code.forNumber(order);
- if (orderCodeProto == null) {
- throw new IllegalArgumentException("Invalid result ranking order: "
- + orderCodeProto);
- }
- mScoringSpecBuilder.setOrderBy(orderCodeProto);
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkArgumentInRange(order, ORDER_DESCENDING, ORDER_ASCENDING,
+ "Result ranking order");
+ mBundle.putInt(ORDER_FIELD, order);
return this;
}
/**
- * Only the first {@code numToSnippet} documents based on the ranking strategy
+ * Only the first {@code snippetCount} documents based on the ranking strategy
* will have snippet information provided.
* <p>If set to 0 (default), snippeting is disabled and
- * {@link SearchResults.Result#getMatchInfo} will return {@code null} for that result.
+ * {@link SearchResults.Result#getMatches} will return {@code null} for that result.
+ * <p>The value should be set in range[0, 10k].
*/
@NonNull
- public SearchSpec.Builder setNumToSnippet(int numToSnippet) {
- mSnippetSpecBuilder.setNumToSnippet(numToSnippet);
+ public SearchSpec.Builder setSnippetCount(int snippetCount) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkArgumentInRange(snippetCount, 0, MAX_SNIPPET_COUNT, "snippetCount");
+ mBundle.putInt(SNIPPET_COUNT_FIELD, snippetCount);
return this;
}
/**
- * Only the first {@code numMatchesPerProperty} matches for a every property of
- * {@link AppSearchDocument} will contain snippet information.
- * <p>If set to 0, snippeting is disabled and {@link SearchResults.Result#getMatchInfo}
+ * Only the first {@code matchesCountPerProperty} matches for a every property of
+ * {@link GenericDocument} will contain snippet information.
+ * <p>If set to 0, snippeting is disabled and {@link SearchResults.Result#getMatches}
* will return {@code null} for that result.
+ * <p>The value should be set in range[0, 10k].
*/
@NonNull
- public SearchSpec.Builder setNumMatchesPerProperty(int numMatchesPerProperty) {
- mSnippetSpecBuilder.setNumMatchesPerProperty(numMatchesPerProperty);
+ public SearchSpec.Builder setSnippetCountPerProperty(int snippetCountPerProperty) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkArgumentInRange(snippetCountPerProperty,
+ 0, MAX_SNIPPET_PER_PROPERTY_COUNT, "snippetCountPerProperty");
+ mBundle.putInt(SNIPPET_COUNT_PER_PROPERTY_FIELD, snippetCountPerProperty);
return this;
}
@@ -237,10 +286,14 @@ public final class SearchSpec {
* be returned. If matches enabled is also set to false, then snippeting is disabled.
* <p>Ex. {@code maxSnippetSize} = 16. "foo bar baz bat rat" with a query of "baz" will
* return a window of "bar baz bat" which is only 11 bytes long.
+ * <p>The value should be in range[0, 10k].
*/
@NonNull
public SearchSpec.Builder setMaxSnippetSize(int maxSnippetSize) {
- mSnippetSpecBuilder.setMaxWindowBytes(maxSnippetSize);
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ Preconditions.checkArgumentInRange(
+ maxSnippetSize, 0, MAX_SNIPPET_SIZE_LIMIT, "maxSnippetSize");
+ mBundle.putInt(MAX_SNIPPET_FIELD, maxSnippetSize);
return this;
}
@@ -251,12 +304,12 @@ public final class SearchSpec {
*/
@NonNull
public SearchSpec build() {
- if (mSearchSpecBuilder.getTermMatchType() == TermMatchType.Code.UNKNOWN) {
+ Preconditions.checkState(!mBuilt, "Builder has already been used");
+ if (!mBundle.containsKey(TERM_MATCH_TYPE_FIELD)) {
throw new IllegalSearchSpecException("Missing termMatchType field.");
}
- mResultSpecBuilder.setSnippetSpec(mSnippetSpecBuilder);
- return new SearchSpec(mSearchSpecBuilder.build(), mResultSpecBuilder.build(),
- mScoringSpecBuilder.build());
+ mBuilt = true;
+ return new SearchSpec(mBundle);
}
}
}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IllegalSchemaException.java b/apex/appsearch/framework/java/android/app/appsearch/exceptions/IllegalSchemaException.java
index f9e528cd2951..6dd86f5e6de1 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/IllegalSchemaException.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/exceptions/IllegalSchemaException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,16 +14,18 @@
* limitations under the License.
*/
-package android.app.appsearch;
+package android.app.appsearch.exceptions;
import android.annotation.NonNull;
+
/**
* Indicates that a {@link android.app.appsearch.AppSearchSchema} has logical inconsistencies such
* as unpopulated mandatory fields or illegal combinations of parameters.
*
* @hide
*/
+
public class IllegalSchemaException extends IllegalArgumentException {
/**
* Constructs a new {@link IllegalSchemaException}.
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IllegalSearchSpecException.java b/apex/appsearch/framework/java/android/app/appsearch/exceptions/IllegalSearchSpecException.java
index 0d029f029ee5..3ef887f09eab 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/IllegalSearchSpecException.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/exceptions/IllegalSearchSpecException.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,16 +14,18 @@
* limitations under the License.
*/
-package android.app.appsearch;
+package android.app.appsearch.exceptions;
import android.annotation.NonNull;
+
/**
- * Indicates that a {@link android.app.appsearch.SearchResults} has logical inconsistencies such
+ * Indicates that a {@link android.app.appsearch.SearchResult} has logical inconsistencies such
* as unpopulated mandatory fields or illegal combinations of parameters.
*
* @hide
*/
+
public class IllegalSearchSpecException extends IllegalArgumentException {
/**
* Constructs a new {@link IllegalSearchSpecException}.
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index 75fad82d3fff..4bc0c39bb6c9 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -19,24 +19,27 @@ import android.annotation.NonNull;
import android.app.appsearch.AppSearchBatchResult;
import android.app.appsearch.AppSearchDocument;
import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.AppSearchSchema;
import android.app.appsearch.IAppSearchManager;
+import android.app.appsearch.SearchSpec;
import android.app.appsearch.exceptions.AppSearchException;
import android.content.Context;
import android.os.Binder;
+import android.os.Bundle;
import android.os.UserHandle;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.Preconditions;
import com.android.server.SystemService;
import com.android.server.appsearch.external.localbackend.AppSearchImpl;
+import com.android.server.appsearch.external.localbackend.converter.SchemaToProtoConverter;
+import com.android.server.appsearch.external.localbackend.converter.SearchSpecToProtoConverter;
import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.ResultSpecProto;
import com.google.android.icing.proto.SchemaProto;
-import com.google.android.icing.proto.ScoringSpecProto;
+import com.google.android.icing.proto.SchemaTypeConfigProto;
import com.google.android.icing.proto.SearchResultProto;
import com.google.android.icing.proto.SearchSpecProto;
-import com.google.android.icing.proto.StatusProto;
import java.io.IOException;
import java.util.List;
@@ -59,19 +62,24 @@ public class AppSearchManagerService extends SystemService {
private class Stub extends IAppSearchManager.Stub {
@Override
public void setSchema(
- @NonNull byte[] schemaBytes,
+ @NonNull List<Bundle> schemaBundles,
boolean forceOverride,
@NonNull AndroidFuture<AppSearchResult> callback) {
- Preconditions.checkNotNull(schemaBytes);
+ Preconditions.checkNotNull(schemaBundles);
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUidOrThrow();
int callingUserId = UserHandle.getUserId(callingUid);
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
- SchemaProto schema = SchemaProto.parseFrom(schemaBytes);
+ SchemaProto.Builder schemaProtoBuilder = SchemaProto.newBuilder();
+ for (int i = 0; i < schemaBundles.size(); i++) {
+ AppSearchSchema schema = new AppSearchSchema(schemaBundles.get(i));
+ SchemaTypeConfigProto schemaTypeProto = SchemaToProtoConverter.convert(schema);
+ schemaProtoBuilder.addTypes(schemaTypeProto);
+ }
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
String databaseName = makeDatabaseName(callingUid);
- impl.setSchema(databaseName, schema, forceOverride);
+ impl.setSchema(databaseName, schemaProtoBuilder.build(), forceOverride);
callback.complete(AppSearchResult.newSuccessfulResult(/*value=*/ null));
} catch (Throwable t) {
callback.complete(throwableToFailedResult(t));
@@ -88,7 +96,7 @@ public class AppSearchManagerService extends SystemService {
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUidOrThrow();
int callingUserId = UserHandle.getUserId(callingUid);
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
String databaseName = makeDatabaseName(callingUid);
@@ -119,7 +127,7 @@ public class AppSearchManagerService extends SystemService {
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUidOrThrow();
int callingUserId = UserHandle.getUserId(callingUid);
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
String databaseName = makeDatabaseName(callingUid);
@@ -151,36 +159,31 @@ public class AppSearchManagerService extends SystemService {
// TODO(sidchhabra): Do this in a threadpool.
@Override
public void query(
- @NonNull byte[] searchSpecBytes,
- @NonNull byte[] resultSpecBytes,
- @NonNull byte[] scoringSpecBytes,
+ @NonNull String queryExpression,
+ @NonNull Bundle searchSpecBundle,
@NonNull AndroidFuture<AppSearchResult> callback) {
- Preconditions.checkNotNull(searchSpecBytes);
- Preconditions.checkNotNull(resultSpecBytes);
- Preconditions.checkNotNull(scoringSpecBytes);
+ Preconditions.checkNotNull(queryExpression);
+ Preconditions.checkNotNull(searchSpecBundle);
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUidOrThrow();
int callingUserId = UserHandle.getUserId(callingUid);
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
- SearchSpecProto searchSpecProto = SearchSpecProto.parseFrom(searchSpecBytes);
- ResultSpecProto resultSpecProto = ResultSpecProto.parseFrom(resultSpecBytes);
- ScoringSpecProto scoringSpecProto = ScoringSpecProto.parseFrom(scoringSpecBytes);
+ SearchSpec searchSpec = new SearchSpec(searchSpecBundle);
+ SearchSpecProto searchSpecProto =
+ SearchSpecToProtoConverter.toSearchSpecProto(searchSpec);
+ searchSpecProto = searchSpecProto.toBuilder()
+ .setQuery(queryExpression).build();
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
String databaseName = makeDatabaseName(callingUid);
+ // TODO(adorokhine): handle pagination
SearchResultProto searchResultProto = impl.query(
- databaseName, searchSpecProto, resultSpecProto, scoringSpecProto);
- // TODO(sidchhabra): Translate SearchResultProto errors into error codes. This might
- // better be done in AppSearchImpl by throwing an AppSearchException.
- if (searchResultProto.getStatus().getCode() != StatusProto.Code.OK) {
- callback.complete(
- AppSearchResult.newFailedResult(
- AppSearchResult.RESULT_INTERNAL_ERROR,
- searchResultProto.getStatus().getMessage()));
- } else {
- callback.complete(
- AppSearchResult.newSuccessfulResult(searchResultProto.toByteArray()));
- }
+ databaseName,
+ searchSpecProto,
+ SearchSpecToProtoConverter.toResultSpecProto(searchSpec),
+ SearchSpecToProtoConverter.toScoringSpecProto(searchSpec));
+ callback.complete(
+ AppSearchResult.newSuccessfulResult(searchResultProto.toByteArray()));
} catch (Throwable t) {
callback.complete(throwableToFailedResult(t));
} finally {
@@ -194,7 +197,7 @@ public class AppSearchManagerService extends SystemService {
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUidOrThrow();
int callingUserId = UserHandle.getUserId(callingUid);
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
String databaseName = makeDatabaseName(callingUid);
@@ -224,7 +227,7 @@ public class AppSearchManagerService extends SystemService {
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUidOrThrow();
int callingUserId = UserHandle.getUserId(callingUid);
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
String databaseName = makeDatabaseName(callingUid);
@@ -252,7 +255,7 @@ public class AppSearchManagerService extends SystemService {
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUidOrThrow();
int callingUserId = UserHandle.getUserId(callingUid);
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
String databaseName = makeDatabaseName(callingUid);
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/converter/SchemaToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/converter/SchemaToProtoConverter.java
new file mode 100644
index 000000000000..ca0d2ee970cb
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/converter/SchemaToProtoConverter.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appsearch.external.localbackend.converter;
+
+import android.os.Bundle;
+
+import android.annotation.NonNull;
+
+import android.app.appsearch.AppSearchSchema;
+import com.android.internal.util.Preconditions;
+
+import com.google.android.icing.proto.IndexingConfig;
+import com.google.android.icing.proto.PropertyConfigProto;
+import com.google.android.icing.proto.SchemaTypeConfigProto;
+import com.google.android.icing.proto.TermMatchType;
+
+import java.util.ArrayList;
+
+/**
+ * Translates an {@link AppSearchSchema} into a {@link SchemaTypeConfigProto}.
+ * @hide
+ */
+
+public final class SchemaToProtoConverter {
+ private SchemaToProtoConverter() {}
+
+ /**
+ * Converts an {@link android.app.appsearch.AppSearchSchema} into a
+ * {@link SchemaTypeConfigProto}.
+ */
+ @NonNull
+ public static SchemaTypeConfigProto convert(@NonNull AppSearchSchema schema) {
+ Preconditions.checkNotNull(schema);
+ Bundle bundle = schema.getBundle();
+ SchemaTypeConfigProto.Builder protoBuilder =
+ SchemaTypeConfigProto.newBuilder()
+ .setSchemaType(bundle.getString(AppSearchSchema.SCHEMA_TYPE_FIELD, ""));
+ ArrayList<Bundle> properties =
+ bundle.getParcelableArrayList(AppSearchSchema.PROPERTIES_FIELD);
+ if (properties != null) {
+ for (int i = 0; i < properties.size(); i++) {
+ PropertyConfigProto propertyProto = convertProperty(properties.get(i));
+ protoBuilder.addProperties(propertyProto);
+ }
+ }
+ return protoBuilder.build();
+ }
+
+ @NonNull
+ private static PropertyConfigProto convertProperty(@NonNull Bundle bundle) {
+ Preconditions.checkNotNull(bundle);
+ PropertyConfigProto.Builder propertyConfigProto = PropertyConfigProto.newBuilder()
+ .setPropertyName(bundle.getString(AppSearchSchema.PropertyConfig.NAME_FIELD, ""));
+ IndexingConfig.Builder indexingConfig = IndexingConfig.newBuilder();
+
+ // Set dataType
+ @AppSearchSchema.PropertyConfig.DataType int dataType =
+ bundle.getInt(AppSearchSchema.PropertyConfig.DATA_TYPE_FIELD);
+ PropertyConfigProto.DataType.Code dataTypeProto =
+ PropertyConfigProto.DataType.Code.forNumber(dataType);
+ if (dataTypeProto == null) {
+ throw new IllegalArgumentException("Invalid dataType: " + dataType);
+ }
+ propertyConfigProto.setDataType(dataTypeProto);
+
+ // Set schemaType
+ propertyConfigProto.setSchemaType(
+ bundle.getString(AppSearchSchema.PropertyConfig.SCHEMA_TYPE_FIELD, ""));
+
+ // Set cardinality
+ @AppSearchSchema.PropertyConfig.Cardinality int cardinality =
+ bundle.getInt(AppSearchSchema.PropertyConfig.CARDINALITY_FIELD);
+ PropertyConfigProto.Cardinality.Code cardinalityProto =
+ PropertyConfigProto.Cardinality.Code.forNumber(cardinality);
+ if (cardinalityProto == null) {
+ throw new IllegalArgumentException("Invalid cardinality: " + dataType);
+ }
+ propertyConfigProto.setCardinality(cardinalityProto);
+
+ // Set indexingType
+ @AppSearchSchema.PropertyConfig.IndexingType int indexingType =
+ bundle.getInt(AppSearchSchema.PropertyConfig.INDEXING_TYPE_FIELD);
+ TermMatchType.Code termMatchTypeProto;
+ switch (indexingType) {
+ case AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE:
+ termMatchTypeProto = TermMatchType.Code.UNKNOWN;
+ break;
+ case AppSearchSchema.PropertyConfig.INDEXING_TYPE_EXACT_TERMS:
+ termMatchTypeProto = TermMatchType.Code.EXACT_ONLY;
+ break;
+ case AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES:
+ termMatchTypeProto = TermMatchType.Code.PREFIX;
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid indexingType: " + indexingType);
+ }
+ indexingConfig.setTermMatchType(termMatchTypeProto);
+
+ // Set tokenizerType
+ @AppSearchSchema.PropertyConfig.TokenizerType int tokenizerType =
+ bundle.getInt(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_FIELD);
+ IndexingConfig.TokenizerType.Code tokenizerTypeProto =
+ IndexingConfig.TokenizerType.Code.forNumber(tokenizerType);
+ if (tokenizerTypeProto == null) {
+ throw new IllegalArgumentException("Invalid tokenizerType: " + tokenizerType);
+ }
+ indexingConfig.setTokenizerType(tokenizerTypeProto);
+
+ // Build!
+ propertyConfigProto.setIndexingConfig(indexingConfig);
+ return propertyConfigProto.build();
+ }
+}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/converter/SearchSpecToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/converter/SearchSpecToProtoConverter.java
new file mode 100644
index 000000000000..a5d913a20590
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localbackend/converter/SearchSpecToProtoConverter.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appsearch.external.localbackend.converter;
+
+import android.os.Bundle;
+
+import android.annotation.NonNull;
+
+import android.app.appsearch.SearchSpec;
+import com.android.internal.util.Preconditions;
+
+import com.google.android.icing.proto.ResultSpecProto;
+import com.google.android.icing.proto.ScoringSpecProto;
+import com.google.android.icing.proto.SearchSpecProto;
+import com.google.android.icing.proto.TermMatchType;
+
+import java.util.Arrays;
+
+/**
+ * Translates a {@link SearchSpec} into icing search protos.
+ * @hide
+ */
+
+public final class SearchSpecToProtoConverter {
+ private SearchSpecToProtoConverter() {}
+
+ /** Extracts {@link SearchSpecProto} information from a {@link SearchSpec}. */
+ @NonNull
+ public static SearchSpecProto toSearchSpecProto(@NonNull SearchSpec spec) {
+ Preconditions.checkNotNull(spec);
+ Bundle bundle = spec.getBundle();
+ SearchSpecProto.Builder protoBuilder = SearchSpecProto.newBuilder();
+
+ @SearchSpec.TermMatchCode int termMatchCode =
+ bundle.getInt(SearchSpec.TERM_MATCH_TYPE_FIELD);
+ TermMatchType.Code termMatchCodeProto = TermMatchType.Code.forNumber(termMatchCode);
+ if (termMatchCodeProto == null || termMatchCodeProto.equals(TermMatchType.Code.UNKNOWN)) {
+ throw new IllegalArgumentException("Invalid term match type: " + termMatchCode);
+ }
+ protoBuilder.setTermMatchType(termMatchCodeProto);
+
+ String[] schemaTypes = bundle.getStringArray(SearchSpec.SCHEMA_TYPES_FIELD);
+ if (schemaTypes != null) {
+ protoBuilder.addAllSchemaTypeFilters(Arrays.asList(schemaTypes));
+ }
+ String[] namespaces = bundle.getStringArray(SearchSpec.NAMESPACE_FIELD);
+ if (namespaces != null) {
+ protoBuilder.addAllNamespaceFilters(Arrays.asList(namespaces));
+ }
+ return protoBuilder.build();
+ }
+
+ /** Extracts {@link ResultSpecProto} information from a {@link SearchSpec}. */
+ @NonNull
+ public static ResultSpecProto toResultSpecProto(@NonNull SearchSpec spec) {
+ Preconditions.checkNotNull(spec);
+ Bundle bundle = spec.getBundle();
+ return ResultSpecProto.newBuilder()
+ .setNumPerPage(bundle.getInt(
+ SearchSpec.NUM_PER_PAGE_FIELD, SearchSpec.DEFAULT_NUM_PER_PAGE))
+ .setSnippetSpec(ResultSpecProto.SnippetSpecProto.newBuilder()
+ .setNumToSnippet(bundle.getInt(SearchSpec.SNIPPET_COUNT_FIELD))
+ .setNumMatchesPerProperty(
+ bundle.getInt(SearchSpec.SNIPPET_COUNT_PER_PROPERTY_FIELD))
+ .setMaxWindowBytes(bundle.getInt(SearchSpec.MAX_SNIPPET_FIELD)))
+ .build();
+
+ }
+
+ /** Extracts {@link ScoringSpecProto} information from a {@link SearchSpec}. */
+ @NonNull
+ public static ScoringSpecProto toScoringSpecProto(@NonNull SearchSpec spec) {
+ Preconditions.checkNotNull(spec);
+ Bundle bundle = spec.getBundle();
+ ScoringSpecProto.Builder protoBuilder = ScoringSpecProto.newBuilder();
+
+ @SearchSpec.OrderCode int orderCode = bundle.getInt(SearchSpec.ORDER_FIELD);
+ ScoringSpecProto.Order.Code orderCodeProto =
+ ScoringSpecProto.Order.Code.forNumber(orderCode);
+ if (orderCodeProto == null) {
+ throw new IllegalArgumentException("Invalid result ranking order: " + orderCode);
+ }
+ protoBuilder.setOrderBy(orderCodeProto);
+
+ @SearchSpec.RankingStrategyCode int rankingStrategyCode =
+ bundle.getInt(SearchSpec.RANKING_STRATEGY_FIELD);
+ ScoringSpecProto.RankingStrategy.Code rankingStrategyCodeProto =
+ ScoringSpecProto.RankingStrategy.Code.forNumber(rankingStrategyCode);
+ if (rankingStrategyCodeProto == null) {
+ throw new IllegalArgumentException("Invalid result ranking strategy: "
+ + rankingStrategyCode);
+ }
+ protoBuilder.setRankBy(rankingStrategyCodeProto);
+
+ return protoBuilder.build();
+ }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index 59915e145c49..1a81587990f2 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -1682,7 +1682,7 @@ public class DeviceIdleController extends SystemService
}
getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
null);
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
return addPowerSaveWhitelistAppsInternal(packageNames);
} finally {
@@ -1696,7 +1696,7 @@ public class DeviceIdleController extends SystemService
}
getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
null);
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
if (!removePowerSaveWhitelistAppInternal(name)
&& mPowerSaveWhitelistAppsExceptIdle.containsKey(name)) {
@@ -1713,7 +1713,7 @@ public class DeviceIdleController extends SystemService
}
getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
null);
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
removeSystemPowerWhitelistAppInternal(name);
} finally {
@@ -1727,7 +1727,7 @@ public class DeviceIdleController extends SystemService
}
getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
null);
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
restoreSystemPowerWhitelistAppInternal(name);
} finally {
@@ -1815,7 +1815,7 @@ public class DeviceIdleController extends SystemService
@Override public void exitIdle(String reason) {
getContext().enforceCallingOrSelfPermission(Manifest.permission.DEVICE_POWER,
null);
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
exitIdleInternal(reason);
} finally {
@@ -1826,7 +1826,7 @@ public class DeviceIdleController extends SystemService
@Override public int setPreIdleTimeoutMode(int mode) {
getContext().enforceCallingOrSelfPermission(Manifest.permission.DEVICE_POWER,
null);
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
return DeviceIdleController.this.setPreIdleTimeoutMode(mode);
} finally {
@@ -1837,7 +1837,7 @@ public class DeviceIdleController extends SystemService
@Override public void resetPreIdleTimeoutMode() {
getContext().enforceCallingOrSelfPermission(Manifest.permission.DEVICE_POWER,
null);
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
DeviceIdleController.this.resetPreIdleTimeoutMode();
} finally {
@@ -4031,7 +4031,7 @@ public class DeviceIdleController extends SystemService
getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
null);
synchronized (this) {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
String arg = shell.getNextArg();
try {
if (arg == null || "deep".equals(arg)) {
@@ -4052,7 +4052,7 @@ public class DeviceIdleController extends SystemService
getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
null);
synchronized (this) {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
String arg = shell.getNextArg();
try {
if (arg == null || "deep".equals(arg)) {
@@ -4100,7 +4100,7 @@ public class DeviceIdleController extends SystemService
getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
null);
synchronized (this) {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mForceIdle = true;
becomeInactiveIfAppropriateLocked();
@@ -4116,7 +4116,7 @@ public class DeviceIdleController extends SystemService
getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
null);
synchronized (this) {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
exitForceIdleLocked();
pw.print("Light state: ");
@@ -4133,7 +4133,7 @@ public class DeviceIdleController extends SystemService
synchronized (this) {
String arg = shell.getNextArg();
if (arg != null) {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
switch (arg) {
case "light": pw.println(lightStateToString(mLightState)); break;
@@ -4156,7 +4156,7 @@ public class DeviceIdleController extends SystemService
getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
null);
synchronized (this) {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
String arg = shell.getNextArg();
try {
boolean becomeActive = false;
@@ -4193,7 +4193,7 @@ public class DeviceIdleController extends SystemService
getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
null);
synchronized (this) {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
String arg = shell.getNextArg();
try {
boolean becomeInactive = false;
@@ -4242,7 +4242,7 @@ public class DeviceIdleController extends SystemService
if (arg != null) {
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
do {
if (arg.length() < 1 || (arg.charAt(0) != '-'
@@ -4418,7 +4418,7 @@ public class DeviceIdleController extends SystemService
getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
null);
synchronized (this) {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
motionLocked();
pw.print("Light state: ");
@@ -4433,7 +4433,7 @@ public class DeviceIdleController extends SystemService
getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
null);
synchronized (this) {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
int ret = SET_IDLE_FACTOR_RESULT_UNINIT;
try {
String arg = shell.getNextArg();
@@ -4468,7 +4468,7 @@ public class DeviceIdleController extends SystemService
getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
null);
synchronized (this) {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
resetPreIdleTimeoutMode();
} finally {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
index 4512d77e650e..6c14233dba13 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -2673,7 +2673,7 @@ public class JobSchedulerService extends com.android.server.SystemService
validateJobFlags(job, uid);
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
return JobSchedulerService.this.scheduleAsPackage(job, null, uid, null, userId,
null);
@@ -2701,7 +2701,7 @@ public class JobSchedulerService extends com.android.server.SystemService
validateJobFlags(job, uid);
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
return JobSchedulerService.this.scheduleAsPackage(job, work, uid, null, userId,
null);
@@ -2732,7 +2732,7 @@ public class JobSchedulerService extends com.android.server.SystemService
validateJobFlags(job, callerUid);
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
return JobSchedulerService.this.scheduleAsPackage(job, null, callerUid,
packageName, userId, tag);
@@ -2745,7 +2745,7 @@ public class JobSchedulerService extends com.android.server.SystemService
public ParceledListSlice<JobInfo> getAllPendingJobs() throws RemoteException {
final int uid = Binder.getCallingUid();
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
return new ParceledListSlice<>(JobSchedulerService.this.getPendingJobs(uid));
} finally {
@@ -2757,7 +2757,7 @@ public class JobSchedulerService extends com.android.server.SystemService
public JobInfo getPendingJob(int jobId) throws RemoteException {
final int uid = Binder.getCallingUid();
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
return JobSchedulerService.this.getPendingJob(uid, jobId);
} finally {
@@ -2768,7 +2768,7 @@ public class JobSchedulerService extends com.android.server.SystemService
@Override
public void cancelAll() throws RemoteException {
final int uid = Binder.getCallingUid();
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
JobSchedulerService.this.cancelJobsForUid(uid,
"cancelAll() called by app, callingUid=" + uid);
@@ -2781,7 +2781,7 @@ public class JobSchedulerService extends com.android.server.SystemService
public void cancel(int jobId) throws RemoteException {
final int uid = Binder.getCallingUid();
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
JobSchedulerService.this.cancelJob(uid, jobId, uid);
} finally {
diff --git a/apex/statsd/framework/java/android/app/StatsManager.java b/apex/statsd/framework/java/android/app/StatsManager.java
index a7d20572ca96..41803cfd6960 100644
--- a/apex/statsd/framework/java/android/app/StatsManager.java
+++ b/apex/statsd/framework/java/android/app/StatsManager.java
@@ -547,7 +547,7 @@ public final class StatsManager {
@Override
public void onPullAtom(int atomTag, IPullAtomResultReceiver resultReceiver) {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(() -> {
List<StatsEvent> data = new ArrayList<>();
diff --git a/api/Android.bp b/api/Android.bp
index e403082b1fb2..f0218b84a58a 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -150,3 +150,17 @@ genrule {
tools: ["metalava"],
cmd: "$(location metalava) --no-banner --format=v2 $(in) --api $(out)",
}
+
+genrule {
+ name: "combined-removed-dex",
+ srcs: [
+ ":frameworks-base-api-removed-merged.txt",
+ ":frameworks-base-api-system-removed-merged.txt",
+ ":android.car-stubs-docs{.removed-api.txt}",
+ ":android.car-system-stubs-docs{.removed-api.txt}",
+ ],
+ tool_files: ["gen_combined_removed_dex.sh"],
+ tools: ["metalava"],
+ out: ["combined-removed-dex.txt"],
+ cmd: "$(location gen_combined_removed_dex.sh) $(location metalava) $(genDir) $(in) > $(out)",
+}
diff --git a/api/current.txt b/api/current.txt
index b22e84c2c6c0..83df1d97dbff 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4376,6 +4376,7 @@ package android.app {
method @Deprecated public void checkPackage(int, @NonNull String);
method @Deprecated public void finishOp(@NonNull String, int, @NonNull String);
method public void finishOp(@NonNull String, int, @NonNull String, @Nullable String);
+ method public void finishProxyOp(@NonNull String, int, @NonNull String, @Nullable String);
method public boolean isOpActive(@NonNull String, int, @NonNull String);
method @Deprecated public int noteOp(@NonNull String, int, @NonNull String);
method public int noteOp(@NonNull String, int, @Nullable String, @Nullable String, @Nullable String);
@@ -4392,6 +4393,8 @@ package android.app {
method public int startOp(@NonNull String, int, @Nullable String, @Nullable String, @Nullable String);
method @Deprecated public int startOpNoThrow(@NonNull String, int, @NonNull String);
method public int startOpNoThrow(@NonNull String, int, @NonNull String, @NonNull String, @Nullable String);
+ method public int startProxyOp(@NonNull String, int, @NonNull String, @Nullable String, @Nullable String);
+ method public int startProxyOpNoThrow(@NonNull String, int, @NonNull String, @Nullable String, @Nullable String);
method public void startWatchingActive(@NonNull String[], @NonNull java.util.concurrent.Executor, @NonNull android.app.AppOpsManager.OnOpActiveChangedListener);
method public void startWatchingMode(@NonNull String, @Nullable String, @NonNull android.app.AppOpsManager.OnOpChangedListener);
method public void startWatchingMode(@NonNull String, @Nullable String, int, @NonNull android.app.AppOpsManager.OnOpChangedListener);
@@ -6515,6 +6518,7 @@ package android.app {
method public void dropShellPermissionIdentity();
method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
method public android.os.ParcelFileDescriptor executeShellCommand(String);
+ method @NonNull public android.os.ParcelFileDescriptor[] executeShellCommandRw(@NonNull String);
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
@@ -9141,6 +9145,7 @@ package android.bluetooth.le {
method public boolean getIncludeTxPowerLevel();
method public android.util.SparseArray<byte[]> getManufacturerSpecificData();
method public java.util.Map<android.os.ParcelUuid,byte[]> getServiceData();
+ method @Nullable public java.util.List<android.os.ParcelUuid> getServiceSolicitationUuids();
method public java.util.List<android.os.ParcelUuid> getServiceUuids();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.AdvertiseData> CREATOR;
@@ -9150,6 +9155,7 @@ package android.bluetooth.le {
ctor public AdvertiseData.Builder();
method public android.bluetooth.le.AdvertiseData.Builder addManufacturerData(int, byte[]);
method public android.bluetooth.le.AdvertiseData.Builder addServiceData(android.os.ParcelUuid, byte[]);
+ method @NonNull public android.bluetooth.le.AdvertiseData.Builder addServiceSolicitationUuid(@NonNull android.os.ParcelUuid);
method public android.bluetooth.le.AdvertiseData.Builder addServiceUuid(android.os.ParcelUuid);
method public android.bluetooth.le.AdvertiseData build();
method public android.bluetooth.le.AdvertiseData.Builder setIncludeDeviceName(boolean);
@@ -10804,6 +10810,7 @@ package android.content {
field public static final String EXTRA_REFERRER = "android.intent.extra.REFERRER";
field public static final String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME";
field public static final String EXTRA_REMOTE_INTENT_TOKEN = "android.intent.extra.remote_intent_token";
+ field public static final String EXTRA_REMOVED_BY_SYSTEM = "android.intent.extra.REMOVED_BY_SYSTEM";
field public static final String EXTRA_REPLACEMENT_EXTRAS = "android.intent.extra.REPLACEMENT_EXTRAS";
field public static final String EXTRA_REPLACING = "android.intent.extra.REPLACING";
field public static final String EXTRA_RESTRICTIONS_BUNDLE = "android.intent.extra.restrictions_bundle";
@@ -31772,6 +31779,7 @@ package android.net.wifi {
method @IntRange(from=0) public int getPriority();
method public int getPriorityGroup();
method @Nullable public String getSsid();
+ method public int getSubscriptionId();
method public boolean isAppInteractionRequired();
method public boolean isCredentialSharedWithUser();
method public boolean isEnhancedOpen();
@@ -31800,6 +31808,7 @@ package android.net.wifi {
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriority(@IntRange(from=0) int);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriorityGroup(int);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setSsid(@NonNull String);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setSubscriptionId(int);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setUntrusted(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWapiEnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWapiPassphrase(@NonNull String);
@@ -40378,7 +40387,7 @@ package android.provider {
field public static final android.net.Uri INTERNAL_CONTENT_URI;
}
- public static final class MediaStore.Audio.Artists.Albums implements android.provider.MediaStore.Audio.AlbumColumns {
+ public static final class MediaStore.Audio.Artists.Albums implements android.provider.BaseColumns android.provider.MediaStore.Audio.AlbumColumns {
ctor public MediaStore.Audio.Artists.Albums();
method public static android.net.Uri getContentUri(String, long);
}
@@ -50874,6 +50883,7 @@ package android.text.style {
field @NonNull public static final android.os.Parcelable.Creator<android.text.style.SuggestionSpan> CREATOR;
field public static final int FLAG_AUTO_CORRECTION = 4; // 0x4
field public static final int FLAG_EASY_CORRECT = 1; // 0x1
+ field public static final int FLAG_GRAMMAR_ERROR = 8; // 0x8
field public static final int FLAG_MISSPELLED = 2; // 0x2
field public static final int SUGGESTIONS_MAX_SIZE = 5; // 0x5
field @Deprecated public static final String SUGGESTION_SPAN_PICKED_AFTER = "after";
@@ -58248,6 +58258,7 @@ package android.view.textservice {
field @NonNull public static final android.os.Parcelable.Creator<android.view.textservice.SuggestionsInfo> CREATOR;
field public static final int RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = 4; // 0x4
field public static final int RESULT_ATTR_IN_THE_DICTIONARY = 1; // 0x1
+ field public static final int RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR = 8; // 0x8
field public static final int RESULT_ATTR_LOOKS_LIKE_TYPO = 2; // 0x2
}
diff --git a/api/gen_combined_removed_dex.sh b/api/gen_combined_removed_dex.sh
new file mode 100755
index 000000000000..9225fe8dfe85
--- /dev/null
+++ b/api/gen_combined_removed_dex.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+metalava_path="$1"
+tmp_dir="$2"
+shift 2
+
+# Convert each removed.txt to the "dex format" equivalent, and print all output.
+for f in "$@"; do
+ "$metalava_path" --no-banner "$f" --dex-api "${tmp_dir}/tmp"
+ cat "${tmp_dir}/tmp"
+done
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index 19f348c84062..2d24d5b9a0ca 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -82,9 +82,9 @@ package android.media.session {
public final class MediaSessionManager {
method public void addOnActiveSessionsChangedListener(@NonNull android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, @Nullable android.content.ComponentName, int, @Nullable android.os.Handler);
method public void dispatchMediaKeyEventAsSystemService(@NonNull android.view.KeyEvent);
- method public boolean dispatchMediaKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
+ method public boolean dispatchMediaKeyEventToSessionAsSystemService(@NonNull android.view.KeyEvent, @NonNull android.media.session.MediaSession.Token);
method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.view.KeyEvent, int);
- method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
+ method public void dispatchVolumeKeyEventToSessionAsSystemService(@NonNull android.view.KeyEvent, @NonNull android.media.session.MediaSession.Token);
field public static final int RESULT_MEDIA_KEY_HANDLED = 1; // 0x1
field public static final int RESULT_MEDIA_KEY_NOT_HANDLED = 0; // 0x0
}
diff --git a/api/system-current.txt b/api/system-current.txt
index bfc92e6a665a..2919f138aefa 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -7325,6 +7325,7 @@ package android.net.wifi {
field @Deprecated public int numScorerOverrideAndSwitchedNetwork;
field @Deprecated public boolean requirePmf;
field @Deprecated public boolean shared;
+ field @Deprecated public int subscriptionId;
field @Deprecated public boolean useExternalScores;
}
diff --git a/api/system-lint-baseline.txt b/api/system-lint-baseline.txt
index 3a9f49c316ea..7195144f28e5 100644
--- a/api/system-lint-baseline.txt
+++ b/api/system-lint-baseline.txt
@@ -229,6 +229,8 @@ MutableBareField: android.net.wifi.WifiConfiguration#saePasswordId:
MutableBareField: android.net.wifi.WifiConfiguration#shared:
+MutableBareField: android.net.wifi.WifiConfiguration#subscriptionId:
+ Bare field subscriptionId must be marked final, or moved behind accessors if mutable
MutableBareField: android.net.wifi.WifiScanner.ScanSettings#type:
diff --git a/api/test-current.txt b/api/test-current.txt
index 25a471086409..a27268d44c24 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -539,7 +539,6 @@ package android.app {
public final class UiAutomation {
method public void destroy();
- method @NonNull public android.os.ParcelFileDescriptor[] executeShellCommandRw(@NonNull String);
method @NonNull public android.os.ParcelFileDescriptor[] executeShellCommandRwe(@NonNull String);
method @Deprecated public boolean grantRuntimePermission(String, String, android.os.UserHandle);
method @Deprecated public boolean revokeRuntimePermission(String, String, android.os.UserHandle);
@@ -2995,7 +2994,7 @@ package android.os {
}
public final class VibrationAttributes implements android.os.Parcelable {
- method @Deprecated @NonNull public android.media.AudioAttributes getAudioAttributes();
+ method public int getAudioUsage();
}
public static final class VibrationAttributes.Builder {
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index bda9e24d31fb..90c8788d2ada 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -499,7 +499,7 @@ message Atom {
}
// Pulled events will start at field 10000.
- // Next: 10087
+ // Next: 10088
oneof pulled {
WifiBytesTransfer wifi_bytes_transfer = 10000 [(module) = "framework"];
WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001 [(module) = "framework"];
@@ -599,6 +599,7 @@ message Atom {
GeneralExternalStorageAccessStats general_external_storage_access_stats =
10085 [(module) = "mediaprovider"];
IncomingSms incoming_sms = 10086 [(module) = "telephony"];
+ OutgoingSms outgoing_sms = 10087 [(module) = "telephony"];
}
// DO NOT USE field numbers above 100,000 in AOSP.
@@ -3192,8 +3193,9 @@ message BackGesture {
optional int32 end_y = 7; // Y coordinate for ACTION_MOVE event.
optional int32 left_boundary = 8; // left edge width + left inset
optional int32 right_boundary = 9; // screen width - (right edge width + right inset)
- optional float ml_model_score = 10; // The score between 0 and 1 which is the prediction output
- // for the Back Gesture model.
+ // The score between 0 and 1 which is the prediction output for the Back Gesture model.
+ optional float ml_model_score = 10;
+ optional string package_name = 11; // The name of the top 100 most used package by all users.
enum WindowHorizontalLocation {
DEFAULT_LOCATION = 0;
@@ -10518,6 +10520,61 @@ message IncomingSms {
}
/**
+ * Pulls information for a single outgoing SMS.
+ *
+ * Each pull creates multiple atoms, one for each SMS. The sequence is randomized when pulled.
+ *
+ * Pulled from:
+ * frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
+ */
+message OutgoingSms {
+ // Format of the SMS (3GPP or 3GPP2).
+ optional android.telephony.SmsFormatEnum sms_format = 1;
+
+ // Technology of the SMS (CS or IMS).
+ optional android.telephony.SmsTechEnum sms_tech = 2;
+
+ // Radio access technology (RAT) used for the SMS. It can be IWLAN in case of IMS.
+ optional android.telephony.NetworkTypeEnum rat = 3;
+
+ // Result of the SMS sending.
+ optional android.telephony.SmsSendResultEnum send_result = 4;
+
+ // Error code
+ // For IMS technology, see @SmsManager.Result in
+ // http://cs/android/frameworks/base/telephony/java/android/telephony/SmsManager.java
+ // For CS technology:
+ // - GSM format: see GsmSmsErrorCode (3GPP 27.005 clause 3.2.5)
+ // - CDMA format: see CdmaSmsErrorCode (3GPP2 N.S0005 (IS-41-C) Table 171)
+ optional int32 error_code = 5;
+
+ // Whether the SMS was sent while roaming.
+ optional bool is_roaming = 6;
+
+ // Whether the default SMS application generated the SMS (regardless of which application).
+ optional bool is_from_default_app = 7;
+
+ // Index of the SIM is used, 0 for single-SIM devices.
+ optional int32 sim_slot_index = 8;
+
+ // Whether the device was in multi-SIM mode (with multiple active SIM profiles).
+ optional bool is_multi_sim = 9;
+
+ // Whether the message was sent with an eSIM profile.
+ optional bool is_esim = 10;
+
+ // Carrier ID of the SIM card used for the SMS.
+ // See https://source.android.com/devices/tech/config/carrierid.
+ optional int32 carrier_id = 11;
+
+ // Random message ID.
+ optional int64 message_id = 12;
+
+ // Retry count: 0 for the first attempt and then increasing for each attempt.
+ optional int32 retry_id = 13;
+}
+
+/**
* Logs gnss stats from location service provider
*
* Pulled from:
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 1f8cf8ac6d1d..89cb8b8d5406 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -103,6 +103,11 @@ public abstract class ActivityManagerInternal {
IBinder whitelistToken, long duration);
/**
+ * Returns the flags set for a {@link PendingIntent}.
+ */
+ public abstract int getPendingIntentFlags(IIntentSender target);
+
+ /**
* Allows a {@link PendingIntent} to start activities from background.
*/
public abstract void setPendingIntentAllowBgActivityStarts(
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index bb194a5aff0e..8f7116cac81e 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3144,12 +3144,25 @@ public final class ActivityThread extends ClientTransactionHandler {
}
}
+ /**
+ * Returns {@code true} if the {@link android.app.ActivityManager.ProcessState} of the current
+ * process is cached.
+ */
+ @VisibleForTesting
+ public boolean isCachedProcessState() {
+ synchronized (mAppThread) {
+ return mLastProcessState >= ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
+ }
+ }
+
@Override
public void updateProcessState(int processState, boolean fromIpc) {
+ final boolean wasCached;
synchronized (mAppThread) {
if (mLastProcessState == processState) {
return;
}
+ wasCached = isCachedProcessState();
mLastProcessState = processState;
// Defer the top state for VM to avoid aggressive JIT compilation affecting activity
// launch time.
@@ -3166,6 +3179,24 @@ public final class ActivityThread extends ClientTransactionHandler {
+ (fromIpc ? " (from ipc" : ""));
}
}
+
+ // Handle the pending configuration if the process state is changed from cached to
+ // non-cached. Except the case where there is a launching activity because the
+ // LaunchActivityItem will handle it.
+ if (wasCached && !isCachedProcessState() && mNumLaunchingActivities.get() == 0) {
+ final Configuration pendingConfig;
+ synchronized (mResourcesManager) {
+ pendingConfig = mPendingConfiguration;
+ }
+ if (pendingConfig == null) {
+ return;
+ }
+ if (Looper.myLooper() == mH.getLooper()) {
+ handleConfigurationChanged(pendingConfig);
+ } else {
+ sendMessage(H.CONFIGURATION_CHANGED, pendingConfig);
+ }
+ }
}
/** Update VM state based on ActivityManager.PROCESS_STATE_* constants. */
@@ -5687,6 +5718,12 @@ public final class ActivityThread extends ClientTransactionHandler {
@Override
public void handleConfigurationChanged(Configuration config) {
+ if (isCachedProcessState()) {
+ updatePendingConfiguration(config);
+ // If the process is in a cached state, delay the handling until the process is no
+ // longer cached.
+ return;
+ }
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "configChanged");
mCurDefaultDisplayDpi = config.densityDpi;
handleConfigurationChanged(config, null /* compat */);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index ef4f099f441d..d1fbd76c6db1 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -7978,6 +7978,91 @@ public class AppOpsManager {
throw e.rethrowFromSystemServer();
}
}
+ /**
+ * Report that an application has started executing a long-running operation on behalf of
+ * another application when handling an IPC. This function will verify that the calling uid and
+ * proxied package name match, and if not, return {@link #MODE_IGNORED}.
+ *
+ * @param op The op to note
+ * @param proxiedUid The uid to note the op for {@code null}
+ * @param proxiedUid The package name the uid belongs to
+ * @param proxiedAttributionTag The proxied {@link Context#createAttributionContext
+ * attribution tag} or {@code null} for default attribution
+ * @param message A message describing the reason the op was noted
+ *
+ * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or {@link #MODE_IGNORED}
+ * if it is not allowed and should be silently ignored (without causing the app to crash).
+ *
+ * @throws SecurityException If the proxy or proxied app has been configured to crash on this
+ * op.
+ */
+ public int startProxyOp(@NonNull String op, int proxiedUid, @NonNull String proxiedPackageName,
+ @Nullable String proxiedAttributionTag, @Nullable String message) {
+ final int mode = startProxyOpNoThrow(op, proxiedUid, proxiedPackageName,
+ proxiedAttributionTag, message);
+ if (mode == MODE_ERRORED) {
+ throw new SecurityException("Proxy package " + mContext.getOpPackageName()
+ + " from uid " + Process.myUid() + " or calling package " + proxiedPackageName
+ + " from uid " + proxiedUid + " not allowed to perform "
+ + sOpNames[strOpToOp(op)]);
+ }
+ return mode;
+ }
+
+ /**
+ *Like {@link #startProxyOp(String, int, String, String, String)} but instead
+ * of throwing a {@link SecurityException} it returns {@link #MODE_ERRORED}.
+ *
+ * @param op The op to note
+ * @param proxiedUid The uid to note the op for {@code null}
+ * @param proxiedUid The package name the uid belongs to
+ * @param proxiedAttributionTag The proxied {@link Context#createAttributionContext
+ * attribution tag} or {@code null} for default attribution
+ * @param message A message describing the reason the op was noted*
+ * <p>This API requires package with the {@code proxiedPackageName} to belong to
+ * {@code proxiedUid}.
+ *
+ * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or {@link #MODE_IGNORED}
+ * if it is not allowed and should be silently ignored (without causing the app to crash).
+ */
+ public int startProxyOpNoThrow(@NonNull String op, int proxiedUid,
+ @NonNull String proxiedPackageName, @Nullable String proxiedAttributionTag,
+ @Nullable String message) {
+ try {
+ int opInt = strOpToOp(op);
+
+ collectNoteOpCallsForValidation(opInt);
+ int collectionMode = getNotedOpCollectionMode(proxiedUid, proxiedPackageName, opInt);
+ boolean shouldCollectMessage = Process.myUid() == Process.SYSTEM_UID;
+ if (collectionMode == COLLECT_ASYNC) {
+ if (message == null) {
+ // Set stack trace as default message
+ message = getFormattedStackTrace();
+ shouldCollectMessage = true;
+ }
+ }
+
+ int mode = mService.startProxyOperation(getClientId(), opInt, proxiedUid,
+ proxiedPackageName, proxiedAttributionTag, Process.myUid(),
+ mContext.getOpPackageName(), mContext.getAttributionTag(), false,
+ collectionMode == COLLECT_ASYNC, message, shouldCollectMessage);
+
+ if (mode == MODE_ALLOWED) {
+ if (collectionMode == COLLECT_SELF) {
+ collectNotedOpForSelf(opInt, proxiedAttributionTag);
+ } else if (collectionMode == COLLECT_SYNC
+ // Only collect app-ops when the proxy is trusted
+ && mContext.checkPermission(Manifest.permission.UPDATE_APP_OPS_STATS, -1,
+ Process.myUid()) == PackageManager.PERMISSION_GRANTED) {
+ collectNotedOpSync(opInt, proxiedAttributionTag);
+ }
+ }
+
+ return mode;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
/**
* @deprecated Use {@link #finishOp(String, int, String, String)} instead
@@ -8034,6 +8119,28 @@ public class AppOpsManager {
}
/**
+ * Report that an application is no longer performing an operation that had previously
+ * been started with {@link #startProxyOp(String, int, String, String, String)}. There is no
+ * validation of input or result; the parameters supplied here must be the exact same ones
+ * previously passed in when starting the operation.
+ * @param op The operation which was started
+ * @param proxiedUid The uid the op was started on behalf of
+ * @param proxiedPackageName The package the op was started on behalf of
+ * @param proxiedAttributionTag The proxied {@link Context#createAttributionContext
+ * attribution tag} or {@code null} for default attribution
+ */
+ public void finishProxyOp(@NonNull String op, int proxiedUid,
+ @NonNull String proxiedPackageName, @Nullable String proxiedAttributionTag) {
+ try {
+ mService.finishProxyOperation(getClientId(), strOpToOp(op), proxiedUid,
+ proxiedPackageName, proxiedAttributionTag, Process.myUid(),
+ mContext.getOpPackageName(), mContext.getAttributionTag());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Checks whether the given op for a package is active, i.e. did someone call {@link #startOp}
* without {@link #finishOp} yet.
* <p>
@@ -8477,7 +8584,7 @@ public class AppOpsManager {
public void opNoted(AsyncNotedAppOp op) {
Objects.requireNonNull(op);
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
getAsyncNotedExecutor().execute(() -> onAsyncNoted(op));
} finally {
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 4e868fe7370b..1b0fd9edf4f8 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -1242,10 +1242,8 @@ public final class UiAutomation {
*
* @param command The command to execute.
* @return File descriptors (out, in) to the standard output/input streams.
- *
- * @hide
*/
- @TestApi
+ @SuppressLint("ArrayReturn") // For consistency with other APIs
public @NonNull ParcelFileDescriptor[] executeShellCommandRw(@NonNull String command) {
return executeShellCommandInternal(command, false /* includeStderr */);
}
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 056cfc7c28f1..065127138ecc 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -1054,14 +1054,15 @@ public abstract class BackupAgent extends ContextWrapper {
long quotaBytes,
IBackupCallback callbackBinder,
int transportFlags) throws RemoteException {
- // Ensure that we're running with the app's normal permission level
- long ident = Binder.clearCallingIdentity();
-
if (DEBUG) Log.v(TAG, "doBackup() invoked");
+
BackupDataOutput output = new BackupDataOutput(
data.getFileDescriptor(), quotaBytes, transportFlags);
long result = RESULT_ERROR;
+
+ // Ensure that we're running with the app's normal permission level
+ final long ident = Binder.clearCallingIdentity();
try {
BackupAgent.this.onBackup(oldState, output, newState);
result = RESULT_SUCCESS;
@@ -1111,9 +1112,6 @@ public abstract class BackupAgent extends ContextWrapper {
private void doRestoreInternal(ParcelFileDescriptor data, long appVersionCode,
ParcelFileDescriptor newState, int token, IBackupManager callbackBinder,
List<String> excludedKeys) throws RemoteException {
- // Ensure that we're running with the app's normal permission level
- long ident = Binder.clearCallingIdentity();
-
if (DEBUG) Log.v(TAG, "doRestore() invoked");
// Ensure that any side-effect SharedPreferences writes have landed *before*
@@ -1121,6 +1119,9 @@ public abstract class BackupAgent extends ContextWrapper {
waitForSharedPrefs();
BackupDataInput input = new BackupDataInput(data.getFileDescriptor());
+
+ // Ensure that we're running with the app's normal permission level
+ final long ident = Binder.clearCallingIdentity();
try {
BackupAgent.this.onRestore(input, appVersionCode, newState,
excludedKeys != null ? new HashSet<>(excludedKeys)
@@ -1152,15 +1153,14 @@ public abstract class BackupAgent extends ContextWrapper {
@Override
public void doFullBackup(ParcelFileDescriptor data,
long quotaBytes, int token, IBackupManager callbackBinder, int transportFlags) {
- // Ensure that we're running with the app's normal permission level
- long ident = Binder.clearCallingIdentity();
-
if (DEBUG) Log.v(TAG, "doFullBackup() invoked");
// Ensure that any SharedPreferences writes have landed *before*
// we potentially try to back up the underlying files directly.
waitForSharedPrefs();
+ // Ensure that we're running with the app's normal permission level
+ final long ident = Binder.clearCallingIdentity();
try {
BackupAgent.this.onFullBackup(new FullBackupDataOutput(
data, quotaBytes, transportFlags));
@@ -1199,12 +1199,13 @@ public abstract class BackupAgent extends ContextWrapper {
public void doMeasureFullBackup(long quotaBytes, int token, IBackupManager callbackBinder,
int transportFlags) {
- // Ensure that we're running with the app's normal permission level
- final long ident = Binder.clearCallingIdentity();
FullBackupDataOutput measureOutput =
new FullBackupDataOutput(quotaBytes, transportFlags);
waitForSharedPrefs();
+
+ // Ensure that we're running with the app's normal permission level
+ final long ident = Binder.clearCallingIdentity();
try {
BackupAgent.this.onFullBackup(measureOutput);
} catch (IOException ex) {
@@ -1228,7 +1229,7 @@ public abstract class BackupAgent extends ContextWrapper {
public void doRestoreFile(ParcelFileDescriptor data, long size,
int type, String domain, String path, long mode, long mtime,
int token, IBackupManager callbackBinder) throws RemoteException {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
BackupAgent.this.onRestoreFile(data, size, type, domain, path, mode, mtime);
} catch (IOException e) {
@@ -1255,7 +1256,7 @@ public abstract class BackupAgent extends ContextWrapper {
@Override
public void doRestoreFinished(int token, IBackupManager callbackBinder) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
BackupAgent.this.onRestoreFinished();
} catch (Exception e) {
@@ -1284,9 +1285,10 @@ public abstract class BackupAgent extends ContextWrapper {
long backupDataBytes,
long quotaBytes,
IBackupCallback callbackBinder) {
- long ident = Binder.clearCallingIdentity();
-
long result = RESULT_ERROR;
+
+ // Ensure that we're running with the app's normal permission level
+ final long ident = Binder.clearCallingIdentity();
try {
BackupAgent.this.onQuotaExceeded(backupDataBytes, quotaBytes);
result = RESULT_SUCCESS;
diff --git a/core/java/android/app/role/RoleControllerManager.java b/core/java/android/app/role/RoleControllerManager.java
index 96a4debd3d6a..8dde2c55d7d3 100644
--- a/core/java/android/app/role/RoleControllerManager.java
+++ b/core/java/android/app/role/RoleControllerManager.java
@@ -258,7 +258,7 @@ public class RoleControllerManager {
Consumer<Boolean> destination) {
operation.orTimeout(REQUEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
.whenComplete((res, err) -> executor.execute(() -> {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
if (err != null) {
Log.e(LOG_TAG, "Error calling " + opName + "()", err);
@@ -276,7 +276,7 @@ public class RoleControllerManager {
RemoteCallback destination) {
operation.orTimeout(REQUEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
.whenComplete((res, err) -> {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
if (err != null) {
Log.e(LOG_TAG, "Error calling " + opName + "()", err);
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index 87e1df3fb234..82159235ae28 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -413,7 +413,7 @@ public final class RoleManager {
@NonNull Consumer<Boolean> callback) {
return new RemoteCallback(result -> executor.execute(() -> {
boolean successful = result != null;
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
callback.accept(successful);
} finally {
@@ -660,7 +660,7 @@ public final class RoleManager {
@Override
public void onRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId) {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(PooledLambda.obtainRunnable(
OnRoleHoldersChangedListener::onRoleHoldersChanged, mListener, roleName,
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index b5959c06cc1a..2baa73822c9c 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -342,44 +342,72 @@ public final class BluetoothHidDevice implements BluetoothProfile {
@Override
public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) {
- clearCallingIdentity();
- mExecutor.execute(() -> mCallback.onAppStatusChanged(pluggedDevice, registered));
+ final long token = clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onAppStatusChanged(pluggedDevice, registered));
+ } finally {
+ restoreCallingIdentity(token);
+ }
}
@Override
public void onConnectionStateChanged(BluetoothDevice device, int state) {
- clearCallingIdentity();
- mExecutor.execute(() -> mCallback.onConnectionStateChanged(device, state));
+ final long token = clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onConnectionStateChanged(device, state));
+ } finally {
+ restoreCallingIdentity(token);
+ }
}
@Override
public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) {
- clearCallingIdentity();
- mExecutor.execute(() -> mCallback.onGetReport(device, type, id, bufferSize));
+ final long token = clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onGetReport(device, type, id, bufferSize));
+ } finally {
+ restoreCallingIdentity(token);
+ }
}
@Override
public void onSetReport(BluetoothDevice device, byte type, byte id, byte[] data) {
- clearCallingIdentity();
- mExecutor.execute(() -> mCallback.onSetReport(device, type, id, data));
+ final long token = clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onSetReport(device, type, id, data));
+ } finally {
+ restoreCallingIdentity(token);
+ }
}
@Override
public void onSetProtocol(BluetoothDevice device, byte protocol) {
- clearCallingIdentity();
- mExecutor.execute(() -> mCallback.onSetProtocol(device, protocol));
+ final long token = clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onSetProtocol(device, protocol));
+ } finally {
+ restoreCallingIdentity(token);
+ }
}
@Override
public void onInterruptData(BluetoothDevice device, byte reportId, byte[] data) {
- clearCallingIdentity();
- mExecutor.execute(() -> mCallback.onInterruptData(device, reportId, data));
+ final long token = clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onInterruptData(device, reportId, data));
+ } finally {
+ restoreCallingIdentity(token);
+ }
}
@Override
public void onVirtualCableUnplug(BluetoothDevice device) {
- clearCallingIdentity();
- mExecutor.execute(() -> mCallback.onVirtualCableUnplug(device));
+ final long token = clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onVirtualCableUnplug(device));
+ } finally {
+ restoreCallingIdentity(token);
+ }
}
}
diff --git a/core/java/android/bluetooth/le/AdvertiseData.java b/core/java/android/bluetooth/le/AdvertiseData.java
index 5fd825837647..573b93232642 100644
--- a/core/java/android/bluetooth/le/AdvertiseData.java
+++ b/core/java/android/bluetooth/le/AdvertiseData.java
@@ -16,6 +16,7 @@
package android.bluetooth.le;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.ParcelUuid;
@@ -43,17 +44,22 @@ public final class AdvertiseData implements Parcelable {
@Nullable
private final List<ParcelUuid> mServiceUuids;
+ @Nullable
+ private final List<ParcelUuid> mServiceSolicitationUuids;
+
private final SparseArray<byte[]> mManufacturerSpecificData;
private final Map<ParcelUuid, byte[]> mServiceData;
private final boolean mIncludeTxPowerLevel;
private final boolean mIncludeDeviceName;
private AdvertiseData(List<ParcelUuid> serviceUuids,
+ List<ParcelUuid> serviceSolicitationUuids,
SparseArray<byte[]> manufacturerData,
Map<ParcelUuid, byte[]> serviceData,
boolean includeTxPowerLevel,
boolean includeDeviceName) {
mServiceUuids = serviceUuids;
+ mServiceSolicitationUuids = serviceSolicitationUuids;
mManufacturerSpecificData = manufacturerData;
mServiceData = serviceData;
mIncludeTxPowerLevel = includeTxPowerLevel;
@@ -69,6 +75,14 @@ public final class AdvertiseData implements Parcelable {
}
/**
+ * Returns a list of service solicitation UUIDs within the advertisement that we invite to connect.
+ */
+ @Nullable
+ public List<ParcelUuid> getServiceSolicitationUuids() {
+ return mServiceSolicitationUuids;
+ }
+
+ /**
* Returns an array of manufacturer Id and the corresponding manufacturer specific data. The
* manufacturer id is a non-negative number assigned by Bluetooth SIG.
*/
@@ -102,8 +116,8 @@ public final class AdvertiseData implements Parcelable {
*/
@Override
public int hashCode() {
- return Objects.hash(mServiceUuids, mManufacturerSpecificData, mServiceData,
- mIncludeDeviceName, mIncludeTxPowerLevel);
+ return Objects.hash(mServiceUuids, mServiceSolicitationUuids, mManufacturerSpecificData,
+ mServiceData, mIncludeDeviceName, mIncludeTxPowerLevel);
}
/**
@@ -119,6 +133,7 @@ public final class AdvertiseData implements Parcelable {
}
AdvertiseData other = (AdvertiseData) obj;
return Objects.equals(mServiceUuids, other.mServiceUuids)
+ && Objects.equals(mServiceSolicitationUuids, other.mServiceSolicitationUuids)
&& BluetoothLeUtils.equals(mManufacturerSpecificData,
other.mManufacturerSpecificData)
&& BluetoothLeUtils.equals(mServiceData, other.mServiceData)
@@ -128,7 +143,8 @@ public final class AdvertiseData implements Parcelable {
@Override
public String toString() {
- return "AdvertiseData [mServiceUuids=" + mServiceUuids + ", mManufacturerSpecificData="
+ return "AdvertiseData [mServiceUuids=" + mServiceUuids + ", mServiceSolicitationUuids="
+ + mServiceSolicitationUuids + ", mManufacturerSpecificData="
+ BluetoothLeUtils.toString(mManufacturerSpecificData) + ", mServiceData="
+ BluetoothLeUtils.toString(mServiceData)
+ ", mIncludeTxPowerLevel=" + mIncludeTxPowerLevel + ", mIncludeDeviceName="
@@ -143,6 +159,8 @@ public final class AdvertiseData implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeTypedArray(mServiceUuids.toArray(new ParcelUuid[mServiceUuids.size()]), flags);
+ dest.writeTypedArray(mServiceSolicitationUuids.toArray(
+ new ParcelUuid[mServiceSolicitationUuids.size()]), flags);
// mManufacturerSpecificData could not be null.
dest.writeInt(mManufacturerSpecificData.size());
@@ -174,6 +192,11 @@ public final class AdvertiseData implements Parcelable {
builder.addServiceUuid(uuid);
}
+ ArrayList<ParcelUuid> solicitationUuids = in.createTypedArrayList(ParcelUuid.CREATOR);
+ for (ParcelUuid uuid : solicitationUuids) {
+ builder.addServiceSolicitationUuid(uuid);
+ }
+
int manufacturerSize = in.readInt();
for (int i = 0; i < manufacturerSize; ++i) {
int manufacturerId = in.readInt();
@@ -198,6 +221,8 @@ public final class AdvertiseData implements Parcelable {
public static final class Builder {
@Nullable
private List<ParcelUuid> mServiceUuids = new ArrayList<ParcelUuid>();
+ @Nullable
+ private List<ParcelUuid> mServiceSolicitationUuids = new ArrayList<ParcelUuid>();
private SparseArray<byte[]> mManufacturerSpecificData = new SparseArray<byte[]>();
private Map<ParcelUuid, byte[]> mServiceData = new ArrayMap<ParcelUuid, byte[]>();
private boolean mIncludeTxPowerLevel;
@@ -207,17 +232,31 @@ public final class AdvertiseData implements Parcelable {
* Add a service UUID to advertise data.
*
* @param serviceUuid A service UUID to be advertised.
- * @throws IllegalArgumentException If the {@code serviceUuids} are null.
+ * @throws IllegalArgumentException If the {@code serviceUuid} is null.
*/
public Builder addServiceUuid(ParcelUuid serviceUuid) {
if (serviceUuid == null) {
- throw new IllegalArgumentException("serivceUuids are null");
+ throw new IllegalArgumentException("serviceUuid is null");
}
mServiceUuids.add(serviceUuid);
return this;
}
/**
+ * Add a service solicitation UUID to advertise data.
+ *
+ * @param serviceSolicitationUuid A service solicitation UUID to be advertised.
+ * @throws IllegalArgumentException If the {@code serviceSolicitationUuid} is null.
+ */
+ @NonNull
+ public Builder addServiceSolicitationUuid(@NonNull ParcelUuid serviceSolicitationUuid) {
+ if (serviceSolicitationUuid == null) {
+ throw new IllegalArgumentException("serviceSolicitationUuid is null");
+ }
+ mServiceSolicitationUuids.add(serviceSolicitationUuid);
+ return this;
+ }
+ /**
* Add service data to advertise data.
*
* @param serviceDataUuid 16-bit UUID of the service the data is associated with
@@ -279,8 +318,9 @@ public final class AdvertiseData implements Parcelable {
* Build the {@link AdvertiseData}.
*/
public AdvertiseData build() {
- return new AdvertiseData(mServiceUuids, mManufacturerSpecificData, mServiceData,
- mIncludeTxPowerLevel, mIncludeDeviceName);
+ return new AdvertiseData(mServiceUuids, mServiceSolicitationUuids,
+ mManufacturerSpecificData, mServiceData, mIncludeTxPowerLevel,
+ mIncludeDeviceName);
}
}
}
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index 13c5ff690973..5f166f4a41da 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -507,6 +507,33 @@ public final class BluetoothLeAdvertiser {
+ num128BitUuids * BluetoothUuid.UUID_BYTES_128_BIT;
}
}
+ if (data.getServiceSolicitationUuids() != null) {
+ int num16BitUuids = 0;
+ int num32BitUuids = 0;
+ int num128BitUuids = 0;
+ for (ParcelUuid uuid : data.getServiceSolicitationUuids()) {
+ if (BluetoothUuid.is16BitUuid(uuid)) {
+ ++num16BitUuids;
+ } else if (BluetoothUuid.is32BitUuid(uuid)) {
+ ++num32BitUuids;
+ } else {
+ ++num128BitUuids;
+ }
+ }
+ // 16 bit service uuids are grouped into one field when doing advertising.
+ if (num16BitUuids != 0) {
+ size += OVERHEAD_BYTES_PER_FIELD + num16BitUuids * BluetoothUuid.UUID_BYTES_16_BIT;
+ }
+ // 32 bit service uuids are grouped into one field when doing advertising.
+ if (num32BitUuids != 0) {
+ size += OVERHEAD_BYTES_PER_FIELD + num32BitUuids * BluetoothUuid.UUID_BYTES_32_BIT;
+ }
+ // 128 bit service uuids are grouped into one field when doing advertising.
+ if (num128BitUuids != 0) {
+ size += OVERHEAD_BYTES_PER_FIELD
+ + num128BitUuids * BluetoothUuid.UUID_BYTES_128_BIT;
+ }
+ }
for (ParcelUuid uuid : data.getServiceData().keySet()) {
int uuidLen = BluetoothUuid.uuidToBytes(uuid).length;
size += OVERHEAD_BYTES_PER_FIELD + uuidLen
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 33be50d34777..6cb5b92abb37 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -1043,6 +1043,7 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
* calling identity by passing it to
* {@link #restoreCallingIdentity}.
*/
+ @SuppressWarnings("AndroidFrameworkBinderIdentity")
public final @NonNull CallingIdentity clearCallingIdentity() {
return new CallingIdentity(Binder.clearCallingIdentity(), setCallingPackage(null));
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9a9f165030b0..2f1254f90ccf 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -620,6 +620,7 @@ import java.util.TimeZone;
* <li> {@link #EXTRA_PHONE_NUMBER}
* <li> {@link #EXTRA_REFERRER}
* <li> {@link #EXTRA_REMOTE_INTENT_TOKEN}
+ * <li> {@link #EXTRA_REMOVED_BY_SYSTEM}
* <li> {@link #EXTRA_REPLACING}
* <li> {@link #EXTRA_SHORTCUT_ICON}
* <li> {@link #EXTRA_SHORTCUT_ICON_RESOURCE}
@@ -2464,6 +2465,8 @@ public class Intent implements Parcelable, Cloneable {
* application -- data and code -- is being removed.
* <li> {@link #EXTRA_REPLACING} is set to true if this will be followed
* by an {@link #ACTION_PACKAGE_ADDED} broadcast for the same package.
+ * <li> {@link #EXTRA_REMOVED_BY_SYSTEM} containing boolean field to to signal that the
+ * application was removed automatically without the user-initiated action.
* </ul>
*
* <p class="note">This is a protected intent that can only be sent
@@ -5557,6 +5560,14 @@ public class Intent implements Parcelable, Cloneable {
public static final String EXTRA_DONT_KILL_APP = "android.intent.extra.DONT_KILL_APP";
/**
+ * Used as a boolean extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED}
+ * intents to signal that the application was removed automatically without the user-initiated
+ * action.
+ */
+ public static final String EXTRA_REMOVED_BY_SYSTEM =
+ "android.intent.extra.REMOVED_BY_SYSTEM";
+
+ /**
* A String holding the phone number originally entered in
* {@link android.content.Intent#ACTION_NEW_OUTGOING_CALL}, or the actual
* number to call in a {@link android.content.Intent#ACTION_CALL}.
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 79e3eead1234..30f3325cc11c 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -379,8 +379,7 @@ interface IPackageManager {
/**
* Logs process start information (including APK hash) to the security log.
*/
- void logAppProcessStartIfNeeded(String processName, int uid, String seinfo, String apkFile,
- int pid);
+ void logAppProcessStartIfNeeded(String packageName, String processName, int uid, String seinfo, String apkFile, int pid);
/**
* As per {@link android.content.pm.PackageManager#flushPackageRestrictionsAsUser}.
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 08b23b04f2ae..d81dff8f2908 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -366,8 +366,9 @@ public class UserInfo implements Parcelable {
* @return true if this user can be switched to.
**/
public boolean supportsSwitchTo() {
- if (isEphemeral() && !isEnabled()) {
- // Don't support switching to an ephemeral user with removal in progress.
+ if (partial || !isEnabled()) {
+ // Don't support switching to disabled or partial users, which includes users with
+ // removal in progress.
return false;
}
if (preCreated) {
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index e21b45ab6577..48ec3fd808fe 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -1587,7 +1587,7 @@ public class CameraDeviceImpl extends CameraDevice
}
switch (errorCode) {
- case CameraDeviceCallbacks.ERROR_CAMERA_DISCONNECTED:
+ case CameraDeviceCallbacks.ERROR_CAMERA_DISCONNECTED: {
final long ident = Binder.clearCallingIdentity();
try {
mDeviceExecutor.execute(mCallOnDisconnected);
@@ -1595,6 +1595,7 @@ public class CameraDeviceImpl extends CameraDevice
Binder.restoreCallingIdentity(ident);
}
break;
+ }
case CameraDeviceCallbacks.ERROR_CAMERA_REQUEST:
case CameraDeviceCallbacks.ERROR_CAMERA_RESULT:
case CameraDeviceCallbacks.ERROR_CAMERA_BUFFER:
diff --git a/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java
index 413caf5e22e0..1d8b2a123c6a 100644
--- a/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java
@@ -147,7 +147,7 @@ public class CameraOfflineSessionImpl extends CameraOfflineSession
case CameraDeviceCallbacks.ERROR_CAMERA_BUFFER:
onCaptureErrorLocked(errorCode, resultExtras);
break;
- default:
+ default: {
Runnable errorDispatch = new Runnable() {
@Override
public void run() {
@@ -164,6 +164,7 @@ public class CameraOfflineSessionImpl extends CameraOfflineSession
} finally {
Binder.restoreCallingIdentity(ident);
}
+ }
}
}
}
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index da4d8e06ad48..e5e73200c8ef 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -1006,8 +1006,12 @@ public final class HdmiControlManager {
return new IHdmiHotplugEventListener.Stub() {
@Override
public void onReceived(HdmiHotplugEvent event) {
- Binder.clearCallingIdentity();
- executor.execute(() -> listener.onReceived(event));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> listener.onReceived(event));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
};
}
@@ -1098,8 +1102,12 @@ public final class HdmiControlManager {
return new IHdmiControlStatusChangeListener.Stub() {
@Override
public void onStatusChange(boolean isCecEnabled, boolean isCecAvailable) {
- Binder.clearCallingIdentity();
- executor.execute(() -> listener.onStatusChange(isCecEnabled, isCecAvailable));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> listener.onStatusChange(isCecEnabled, isCecAvailable));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
};
}
@@ -1171,8 +1179,12 @@ public final class HdmiControlManager {
return new android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener.Stub() {
@Override
public void onHdmiCecVolumeControlFeature(boolean enabled) {
- Binder.clearCallingIdentity();
- executor.execute(() -> listener.onHdmiCecVolumeControlFeature(enabled));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> listener.onHdmiCecVolumeControlFeature(enabled));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
};
}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 4f46160a71e1..25fec3208f65 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -29,18 +29,19 @@ import android.annotation.TestApi;
import android.compat.annotation.ChangeId;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
-import android.media.AudioAttributes;
import android.os.Binder;
import android.os.BlockUntrustedTouchesMode;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
+import android.os.InputEventInjectionSync;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.os.SystemClock;
+import android.os.VibrationAttributes;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.Settings;
@@ -212,7 +213,7 @@ public final class InputManager {
* Never blocks. Injection is asynchronous and is assumed always to be successful.
* @hide
*/
- public static final int INJECT_INPUT_EVENT_MODE_ASYNC = 0; // see InputDispatcher.h
+ public static final int INJECT_INPUT_EVENT_MODE_ASYNC = InputEventInjectionSync.NONE;
/**
* Input Event Injection Synchronization Mode: Wait for result.
@@ -222,7 +223,8 @@ public final class InputManager {
* by the application.
* @hide
*/
- public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT = 1; // see InputDispatcher.h
+ public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT =
+ InputEventInjectionSync.WAIT_FOR_RESULT;
/**
* Input Event Injection Synchronization Mode: Wait for finish.
@@ -230,7 +232,8 @@ public final class InputManager {
* @hide
*/
@UnsupportedAppUsage
- public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH = 2; // see InputDispatcher.h
+ public static final int INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH =
+ InputEventInjectionSync.WAIT_FOR_FINISHED;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -1022,9 +1025,9 @@ public final class InputManager {
*
* @param event The event to inject.
* @param mode The synchronization mode. One of:
- * {@link #INJECT_INPUT_EVENT_MODE_ASYNC},
- * {@link #INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT}, or
- * {@link #INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH}.
+ * {@link android.os.InputEventInjectionSync.NONE},
+ * {@link android.os.InputEventInjectionSync.WAIT_FOR_RESULT}, or
+ * {@link android.os.InputEventInjectionSync.WAIT_FOR_FINISHED}.
* @return True if input event injection succeeded.
*
* @hide
@@ -1034,9 +1037,9 @@ public final class InputManager {
if (event == null) {
throw new IllegalArgumentException("event must not be null");
}
- if (mode != INJECT_INPUT_EVENT_MODE_ASYNC
- && mode != INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
- && mode != INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
+ if (mode != InputEventInjectionSync.NONE
+ && mode != InputEventInjectionSync.WAIT_FOR_FINISHED
+ && mode != InputEventInjectionSync.WAIT_FOR_RESULT) {
throw new IllegalArgumentException("mode is invalid");
}
@@ -1432,8 +1435,8 @@ public final class InputManager {
* @hide
*/
@Override
- public void vibrate(int uid, String opPkg, VibrationEffect effect,
- String reason, AudioAttributes attributes) {
+ public void vibrate(int uid, String opPkg, @NonNull VibrationEffect effect,
+ String reason, @NonNull VibrationAttributes attributes) {
try {
mIm.vibrate(mDeviceId, effect, mToken);
} catch (RemoteException ex) {
diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java
index d7ca63a54987..3ca5207d867c 100644
--- a/core/java/android/inputmethodservice/AbstractInputMethodService.java
+++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java
@@ -193,7 +193,17 @@ public abstract class AbstractInputMethodService extends Service
* needed for a new client of the input method.
*/
public abstract AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface();
-
+
+ /**
+ * Dumps the internal state of IME to a protocol buffer output stream initialized using the
+ * given {@link FileDescriptor}.
+ *
+ * @param fd The file descriptor to which proto dump should be written.
+ * @param args The arguments passed to the dump method.
+ * @hide
+ */
+ abstract void dumpProtoInternal(FileDescriptor fd, String[] args);
+
/**
* Implement this to handle {@link android.os.Binder#dump Binder.dump()}
* calls on your input method.
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index a298c856a0fb..0512305e71a2 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -16,6 +16,8 @@
package android.inputmethodservice;
+import static android.util.imetracing.ImeTracing.PROTO_ARG;
+
import android.annotation.BinderThread;
import android.annotation.MainThread;
import android.annotation.Nullable;
@@ -37,8 +39,8 @@ import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodSession;
import android.view.inputmethod.InputMethodSubtype;
-import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
import com.android.internal.inputmethod.CancellationGroup;
+import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
import com.android.internal.view.IInlineSuggestionsRequestCallback;
@@ -155,9 +157,20 @@ class IInputMethodWrapper extends IInputMethod.Stub
return;
}
SomeArgs args = (SomeArgs)msg.obj;
+ String[] dumpArgs = (String[]) args.arg3;
+ boolean protoDumpRequested = false;
+ for (String arg : dumpArgs) {
+ if (arg.equals(PROTO_ARG)) {
+ protoDumpRequested = true;
+ break;
+ }
+ }
try {
- target.dump((FileDescriptor)args.arg1,
- (PrintWriter)args.arg2, (String[])args.arg3);
+ if (protoDumpRequested) {
+ target.dumpProtoInternal((FileDescriptor) args.arg1, dumpArgs);
+ } else {
+ target.dump((FileDescriptor) args.arg1, (PrintWriter) args.arg2, dumpArgs);
+ }
} catch (RuntimeException e) {
((PrintWriter)args.arg2).println("Exception: " + e);
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index d62d1e1e5775..78cc71a782a5 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -17,6 +17,37 @@
package android.inputmethodservice;
import static android.graphics.Color.TRANSPARENT;
+import static android.inputmethodservice.InputMethodServiceProto.CANDIDATES_VIEW_STARTED;
+import static android.inputmethodservice.InputMethodServiceProto.CANDIDATES_VISIBILITY;
+import static android.inputmethodservice.InputMethodServiceProto.CAN_PRE_RENDER;
+import static android.inputmethodservice.InputMethodServiceProto.CONFIGURATION;
+import static android.inputmethodservice.InputMethodServiceProto.DECOR_VIEW_VISIBLE;
+import static android.inputmethodservice.InputMethodServiceProto.DECOR_VIEW_WAS_VISIBLE;
+import static android.inputmethodservice.InputMethodServiceProto.EXTRACTED_TOKEN;
+import static android.inputmethodservice.InputMethodServiceProto.EXTRACT_VIEW_HIDDEN;
+import static android.inputmethodservice.InputMethodServiceProto.FULLSCREEN_APPLIED;
+import static android.inputmethodservice.InputMethodServiceProto.INPUT_BINDING;
+import static android.inputmethodservice.InputMethodServiceProto.INPUT_EDITOR_INFO;
+import static android.inputmethodservice.InputMethodServiceProto.INPUT_STARTED;
+import static android.inputmethodservice.InputMethodServiceProto.INPUT_VIEW_STARTED;
+import static android.inputmethodservice.InputMethodServiceProto.IN_SHOW_WINDOW;
+import static android.inputmethodservice.InputMethodServiceProto.IS_FULLSCREEN;
+import static android.inputmethodservice.InputMethodServiceProto.IS_INPUT_VIEW_SHOWN;
+import static android.inputmethodservice.InputMethodServiceProto.IS_PRE_RENDERED;
+import static android.inputmethodservice.InputMethodServiceProto.InsetsProto.CONTENT_TOP_INSETS;
+import static android.inputmethodservice.InputMethodServiceProto.InsetsProto.TOUCHABLE_INSETS;
+import static android.inputmethodservice.InputMethodServiceProto.InsetsProto.TOUCHABLE_REGION;
+import static android.inputmethodservice.InputMethodServiceProto.InsetsProto.VISIBLE_TOP_INSETS;
+import static android.inputmethodservice.InputMethodServiceProto.LAST_COMPUTED_INSETS;
+import static android.inputmethodservice.InputMethodServiceProto.LAST_SHOW_INPUT_REQUESTED;
+import static android.inputmethodservice.InputMethodServiceProto.SETTINGS_OBSERVER;
+import static android.inputmethodservice.InputMethodServiceProto.SHOW_INPUT_FLAGS;
+import static android.inputmethodservice.InputMethodServiceProto.SHOW_INPUT_REQUESTED;
+import static android.inputmethodservice.InputMethodServiceProto.SOFT_INPUT_WINDOW;
+import static android.inputmethodservice.InputMethodServiceProto.STATUS_ICON;
+import static android.inputmethodservice.InputMethodServiceProto.TOKEN;
+import static android.inputmethodservice.InputMethodServiceProto.VIEWS_CREATED;
+import static android.inputmethodservice.InputMethodServiceProto.WINDOW_VISIBLE;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowInsets.Type.navigationBars;
@@ -59,6 +90,7 @@ import android.text.method.MovementMethod;
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Printer;
+import android.util.proto.ProtoOutputStream;
import android.view.Gravity;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -104,6 +136,7 @@ import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Collections;
+import java.util.Objects;
/**
* InputMethodService provides a standard implementation of an InputMethod,
@@ -1041,6 +1074,15 @@ public class InputMethodService extends AbstractInputMethodService {
* or {@link #TOUCHABLE_INSETS_REGION}.
*/
public int touchableInsets;
+
+ private void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ proto.write(CONTENT_TOP_INSETS, contentTopInsets);
+ proto.write(VISIBLE_TOP_INSETS, visibleTopInsets);
+ proto.write(TOUCHABLE_INSETS, touchableInsets);
+ proto.write(TOUCHABLE_REGION, touchableRegion.toString());
+ proto.end(token);
+ }
}
/**
@@ -1380,7 +1422,7 @@ public class InputMethodService extends AbstractInputMethodService {
public AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface() {
return new InputMethodSessionImpl();
}
-
+
public LayoutInflater getLayoutInflater() {
return mInflater;
}
@@ -3294,7 +3336,7 @@ public class InputMethodService extends AbstractInputMethodService {
} else {
p.println(" mInputEditorInfo: null");
}
-
+
p.println(" mShowInputRequested=" + mShowInputRequested
+ " mLastShowInputRequested=" + mLastShowInputRequested
+ " mCanPreRender=" + mCanPreRender
@@ -3304,7 +3346,7 @@ public class InputMethodService extends AbstractInputMethodService {
+ " mFullscreenApplied=" + mFullscreenApplied
+ " mIsFullscreen=" + mIsFullscreen
+ " mExtractViewHidden=" + mExtractViewHidden);
-
+
if (mExtractedText != null) {
p.println(" mExtractedText:");
p.println(" text=" + mExtractedText.text.length() + " chars"
@@ -3325,4 +3367,42 @@ public class InputMethodService extends AbstractInputMethodService {
+ " touchableRegion=" + mTmpInsets.touchableRegion);
p.println(" mSettingsObserver=" + mSettingsObserver);
}
+
+ /**
+ * @hide
+ */
+ @Override
+ final void dumpProtoInternal(FileDescriptor fd, String[] args) {
+ final ProtoOutputStream proto = new ProtoOutputStream(fd);
+ mWindow.dumpDebug(proto, SOFT_INPUT_WINDOW);
+ proto.write(VIEWS_CREATED, mViewsCreated);
+ proto.write(DECOR_VIEW_VISIBLE, mDecorViewVisible);
+ proto.write(DECOR_VIEW_WAS_VISIBLE, mDecorViewWasVisible);
+ proto.write(WINDOW_VISIBLE, mWindowVisible);
+ proto.write(IN_SHOW_WINDOW, mInShowWindow);
+ proto.write(CONFIGURATION, getResources().getConfiguration().toString());
+ proto.write(TOKEN, Objects.toString(mToken));
+ proto.write(INPUT_BINDING, Objects.toString(mInputBinding));
+ proto.write(INPUT_STARTED, mInputStarted);
+ proto.write(INPUT_VIEW_STARTED, mInputViewStarted);
+ proto.write(CANDIDATES_VIEW_STARTED, mCandidatesViewStarted);
+ if (mInputEditorInfo != null) {
+ mInputEditorInfo.dumpDebug(proto, INPUT_EDITOR_INFO);
+ }
+ proto.write(SHOW_INPUT_REQUESTED, mShowInputRequested);
+ proto.write(LAST_SHOW_INPUT_REQUESTED, mLastShowInputRequested);
+ proto.write(CAN_PRE_RENDER, mCanPreRender);
+ proto.write(IS_PRE_RENDERED, mIsPreRendered);
+ proto.write(SHOW_INPUT_FLAGS, mShowInputFlags);
+ proto.write(CANDIDATES_VISIBILITY, mCandidatesVisibility);
+ proto.write(FULLSCREEN_APPLIED, mFullscreenApplied);
+ proto.write(IS_FULLSCREEN, mIsFullscreen);
+ proto.write(EXTRACT_VIEW_HIDDEN, mExtractViewHidden);
+ proto.write(EXTRACTED_TOKEN, mExtractedToken);
+ proto.write(IS_INPUT_VIEW_SHOWN, mIsInputViewShown);
+ proto.write(STATUS_ICON, mStatusIcon);
+ mTmpInsets.dumpDebug(proto, LAST_COMPUTED_INSETS);
+ proto.write(SETTINGS_OBSERVER, Objects.toString(mSettingsObserver));
+ proto.flush();
+ }
}
diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java
index 6efd03c44b9f..bc0b37ed626d 100644
--- a/core/java/android/inputmethodservice/SoftInputWindow.java
+++ b/core/java/android/inputmethodservice/SoftInputWindow.java
@@ -16,6 +16,13 @@
package android.inputmethodservice;
+import static android.inputmethodservice.SoftInputWindowProto.BOUNDS;
+import static android.inputmethodservice.SoftInputWindowProto.GRAVITY;
+import static android.inputmethodservice.SoftInputWindowProto.NAME;
+import static android.inputmethodservice.SoftInputWindowProto.TAKES_FOCUS;
+import static android.inputmethodservice.SoftInputWindowProto.WINDOW_STATE;
+import static android.inputmethodservice.SoftInputWindowProto.WINDOW_TYPE;
+
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
@@ -25,6 +32,7 @@ import android.graphics.Rect;
import android.os.Debug;
import android.os.IBinder;
import android.util.Log;
+import android.util.proto.ProtoOutputStream;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -362,4 +370,15 @@ public class SoftInputWindow extends Dialog {
throw new IllegalStateException("Unknown state=" + state);
}
}
+
+ void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ proto.write(NAME, mName);
+ proto.write(WINDOW_TYPE, mWindowType);
+ proto.write(GRAVITY, mGravity);
+ proto.write(TAKES_FOCUS, mTakesFocus);
+ mBounds.dumpDebug(proto, BOUNDS);
+ proto.write(WINDOW_STATE, mWindowState);
+ proto.end(token);
+ }
}
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index a190c473f0a0..0ba266345a60 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -511,18 +511,26 @@ public class NetworkScoreManager {
@Override
public void updateScores(@NonNull List<ScoredNetwork> networks) {
- Binder.clearCallingIdentity();
- mExecutor.execute(() -> {
- mCallback.onScoresUpdated(networks);
- });
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> {
+ mCallback.onScoresUpdated(networks);
+ });
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
@Override
public void clearScores() {
- Binder.clearCallingIdentity();
- mExecutor.execute(() -> {
- mCallback.onScoresInvalidated();
- });
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> {
+ mCallback.onScoresInvalidated();
+ });
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
}
diff --git a/core/java/android/net/NetworkSpecifier.java b/core/java/android/net/NetworkSpecifier.java
index 160259e39813..6ef496b1f6fe 100644
--- a/core/java/android/net/NetworkSpecifier.java
+++ b/core/java/android/net/NetworkSpecifier.java
@@ -22,10 +22,14 @@ import android.annotation.SystemApi;
/**
* Describes specific properties of a requested network for use in a {@link NetworkRequest}.
*
- * Applications cannot instantiate this class by themselves, but can obtain instances of
- * subclasses of this class via other APIs.
+ * This as an abstract class. Applications shouldn't instantiate this class by themselves, but can
+ * obtain instances of subclasses of this class via other APIs.
*/
public abstract class NetworkSpecifier {
+ /**
+ * Create a placeholder object. Please use subclasses of this class in a {@link NetworkRequest}
+ * to request a network.
+ */
public NetworkSpecifier() {}
/**
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index bec96f98dbcd..d492e0870b2e 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -391,8 +391,8 @@ public class Binder implements IBinder {
* @hide
*/
public static final void withCleanCallingIdentity(@NonNull ThrowingRunnable action) {
- long callingIdentity = clearCallingIdentity();
Throwable throwableToPropagate = null;
+ final long callingIdentity = clearCallingIdentity();
try {
action.runOrThrow();
} catch (Throwable throwable) {
@@ -415,8 +415,8 @@ public class Binder implements IBinder {
* @hide
*/
public static final <T> T withCleanCallingIdentity(@NonNull ThrowingSupplier<T> action) {
- long callingIdentity = clearCallingIdentity();
Throwable throwableToPropagate = null;
+ final long callingIdentity = clearCallingIdentity();
try {
return action.getOrThrow();
} catch (Throwable throwable) {
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index b05ea39850f8..c39fd4d1bc43 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -155,6 +155,7 @@ public final class Looper {
/**
* Poll and deliver single message, return true if the outer loop should continue.
*/
+ @SuppressWarnings("AndroidFrameworkBinderIdentity")
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
Message msg = me.mQueue.next(); // might block
@@ -255,6 +256,7 @@ public final class Looper {
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
+ @SuppressWarnings("AndroidFrameworkBinderIdentity")
public static void loop() {
final Looper me = myLooper();
if (me == null) {
diff --git a/core/java/android/os/NullVibrator.java b/core/java/android/os/NullVibrator.java
index 6d8ab6d70cdf..6bb016519a84 100644
--- a/core/java/android/os/NullVibrator.java
+++ b/core/java/android/os/NullVibrator.java
@@ -16,8 +16,6 @@
package android.os;
-import android.media.AudioAttributes;
-
/**
* Vibrator implementation that does nothing.
*
@@ -50,7 +48,7 @@ public class NullVibrator extends Vibrator {
@Override
public void vibrate(int uid, String opPkg, VibrationEffect effect,
- String reason, AudioAttributes attributes) {
+ String reason, VibrationAttributes attributes) {
}
@Override
diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java
index 2dba8dce62da..5c9067ac3c3e 100644
--- a/core/java/android/os/SystemVibrator.java
+++ b/core/java/android/os/SystemVibrator.java
@@ -221,18 +221,14 @@ public class SystemVibrator extends Vibrator {
}
@Override
- public void vibrate(int uid, String opPkg, VibrationEffect effect,
- String reason, AudioAttributes attributes) {
+ public void vibrate(int uid, String opPkg, @NonNull VibrationEffect effect,
+ String reason, @NonNull VibrationAttributes attributes) {
if (mService == null) {
Log.w(TAG, "Failed to vibrate; no vibrator service.");
return;
}
try {
- if (attributes == null) {
- attributes = new AudioAttributes.Builder().build();
- }
- VibrationAttributes atr = new VibrationAttributes.Builder(attributes, effect).build();
- mService.vibrate(uid, opPkg, effect, atr, reason, mToken);
+ mService.vibrate(uid, opPkg, effect, attributes, reason, mToken);
} catch (RemoteException e) {
Log.w(TAG, "Failed to vibrate.", e);
}
diff --git a/core/java/android/os/VibrationAttributes.java b/core/java/android/os/VibrationAttributes.java
index 8a7cf608cfb8..d77861fb71b2 100644
--- a/core/java/android/os/VibrationAttributes.java
+++ b/core/java/android/os/VibrationAttributes.java
@@ -140,13 +140,12 @@ public final class VibrationAttributes implements Parcelable {
private final int mUsage;
private final int mFlags;
+ private final int mOriginalAudioUsage;
- private final AudioAttributes mAudioAttributes;
-
- private VibrationAttributes(int usage, int flags, @NonNull AudioAttributes audio) {
+ private VibrationAttributes(int usage, int audioUsage, int flags) {
mUsage = usage;
+ mOriginalAudioUsage = audioUsage;
mFlags = flags & FLAG_ALL_SUPPORTED;
- mAudioAttributes = audio;
}
/**
@@ -182,14 +181,31 @@ public final class VibrationAttributes implements Parcelable {
}
/**
- * Return AudioAttributes equivalent to this VibrationAttributes.
- * @deprecated Temporary support of AudioAttributes, will be removed when out of WIP
+ * Return {@link AudioAttributes} usage equivalent to {@link #getUsage()}.
+ * @return one of {@link AudioAttributes#SDK_USAGES} that represents {@link #getUsage()}
* @hide
*/
- @Deprecated
@TestApi
- public @NonNull AudioAttributes getAudioAttributes() {
- return mAudioAttributes;
+ public int getAudioUsage() {
+ if (mOriginalAudioUsage != AudioAttributes.USAGE_UNKNOWN) {
+ // Return same audio usage set in the Builder.
+ return mOriginalAudioUsage;
+ }
+ // Return correct audio usage based on the vibration usage set in the Builder.
+ switch (mUsage) {
+ case USAGE_NOTIFICATION:
+ return AudioAttributes.USAGE_NOTIFICATION;
+ case USAGE_COMMUNICATION_REQUEST:
+ return AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST;
+ case USAGE_RINGTONE:
+ return AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
+ case USAGE_TOUCH:
+ return AudioAttributes.USAGE_ASSISTANCE_SONIFICATION;
+ case USAGE_ALARM:
+ return AudioAttributes.USAGE_ALARM;
+ default:
+ return AudioAttributes.USAGE_UNKNOWN;
+ }
}
@Override
@@ -200,15 +216,14 @@ public final class VibrationAttributes implements Parcelable {
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mUsage);
+ dest.writeInt(mOriginalAudioUsage);
dest.writeInt(mFlags);
- dest.writeParcelable(mAudioAttributes, flags);
}
private VibrationAttributes(Parcel src) {
mUsage = src.readInt();
+ mOriginalAudioUsage = src.readInt();
mFlags = src.readInt();
- mAudioAttributes = (AudioAttributes) src.readParcelable(
- AudioAttributes.class.getClassLoader());
}
public static final @NonNull Parcelable.Creator<VibrationAttributes>
@@ -230,18 +245,20 @@ public final class VibrationAttributes implements Parcelable {
return false;
}
VibrationAttributes rhs = (VibrationAttributes) o;
- return mUsage == rhs.mUsage && mFlags == rhs.mFlags;
+ return mUsage == rhs.mUsage && mOriginalAudioUsage == rhs.mOriginalAudioUsage
+ && mFlags == rhs.mFlags;
}
@Override
public int hashCode() {
- return Objects.hash(mUsage, mFlags);
+ return Objects.hash(mUsage, mOriginalAudioUsage, mFlags);
}
@Override
public String toString() {
return "VibrationAttributes:"
+ " Usage=" + usageToString()
+ + " Audio Usage= " + AudioAttributes.usageToString(mOriginalAudioUsage)
+ " Flags=" + mFlags;
}
@@ -280,10 +297,9 @@ public final class VibrationAttributes implements Parcelable {
*/
public static final class Builder {
private int mUsage = USAGE_UNKNOWN;
+ private int mOriginalAudioUsage = AudioAttributes.USAGE_UNKNOWN;
private int mFlags = 0x0;
- private AudioAttributes mAudioAttributes = new AudioAttributes.Builder().build();
-
/**
* Constructs a new Builder with the defaults.
*/
@@ -296,8 +312,8 @@ public final class VibrationAttributes implements Parcelable {
public Builder(@Nullable VibrationAttributes vib) {
if (vib != null) {
mUsage = vib.mUsage;
+ mOriginalAudioUsage = vib.mOriginalAudioUsage;
mFlags = vib.mFlags;
- mAudioAttributes = vib.mAudioAttributes;
}
}
@@ -306,9 +322,7 @@ public final class VibrationAttributes implements Parcelable {
* @hide
*/
@TestApi
- public Builder(@NonNull AudioAttributes audio,
- @Nullable VibrationEffect effect) {
- mAudioAttributes = audio;
+ public Builder(@NonNull AudioAttributes audio, @Nullable VibrationEffect effect) {
setUsage(audio);
setFlags(audio);
applyHapticFeedbackHeuristics(effect);
@@ -342,6 +356,7 @@ public final class VibrationAttributes implements Parcelable {
}
private void setUsage(@NonNull AudioAttributes audio) {
+ mOriginalAudioUsage = audio.getUsage();
switch (audio.getUsage()) {
case AudioAttributes.USAGE_NOTIFICATION:
case AudioAttributes.USAGE_NOTIFICATION_EVENT:
@@ -379,8 +394,7 @@ public final class VibrationAttributes implements Parcelable {
* @return a new {@link VibrationAttributes} object
*/
public @NonNull VibrationAttributes build() {
- VibrationAttributes ans = new VibrationAttributes(mUsage, mFlags,
- mAudioAttributes);
+ VibrationAttributes ans = new VibrationAttributes(mUsage, mOriginalAudioUsage, mFlags);
return ans;
}
@@ -396,6 +410,7 @@ public final class VibrationAttributes implements Parcelable {
* @return the same Builder instance.
*/
public @NonNull Builder setUsage(int usage) {
+ mOriginalAudioUsage = AudioAttributes.USAGE_UNKNOWN;
mUsage = usage;
return this;
}
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 86d009e8607e..0c0e6b5d73a6 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -344,8 +344,24 @@ public abstract class Vibrator {
* @hide
*/
@RequiresPermission(android.Manifest.permission.VIBRATE)
- public abstract void vibrate(int uid, String opPkg, VibrationEffect vibe,
- String reason, AudioAttributes attributes);
+ public final void vibrate(int uid, String opPkg, VibrationEffect vibe,
+ String reason, AudioAttributes attributes) {
+ if (attributes == null) {
+ attributes = new AudioAttributes.Builder().build();
+ }
+ VibrationAttributes attr = new VibrationAttributes.Builder(attributes, vibe).build();
+ vibrate(uid, opPkg, vibe, reason, attr);
+ }
+
+ /**
+ * Like {@link #vibrate(int, String, VibrationEffect, String, AudioAttributes)}, but allows the
+ * caller to specify {@link VibrationAttributes} instead of {@link AudioAttributes}.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.VIBRATE)
+ public abstract void vibrate(int uid, String opPkg, @NonNull VibrationEffect vibe,
+ String reason, @NonNull VibrationAttributes attributes);
/**
* Query whether the vibrator supports the given effects.
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 17a78a8f301e..d6c95db95e85 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -308,7 +308,7 @@ public final class PermissionControllerManager {
revokeRuntimePermissionsResult);
return revokeRuntimePermissionsResult;
}).whenCompleteAsync((revoked, err) -> {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
if (err != null) {
Log.e(TAG, "Failure when revoking runtime permissions " + revoked, err);
@@ -358,7 +358,7 @@ public final class PermissionControllerManager {
setRuntimePermissionGrantStateResult);
return setRuntimePermissionGrantStateResult;
}).whenCompleteAsync((setRuntimePermissionGrantStateResult, err) -> {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
if (err != null) {
Log.e(TAG, "Error setting permissions state for device admin " + packageName,
@@ -477,7 +477,7 @@ public final class PermissionControllerManager {
applyStagedRuntimePermissionBackupResult);
return applyStagedRuntimePermissionBackupResult;
}).whenCompleteAsync((applyStagedRuntimePermissionBackupResult, err) -> {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
if (err != null) {
Log.e(TAG, "Error restoring delayed permissions for " + packageName, err);
@@ -623,7 +623,7 @@ public final class PermissionControllerManager {
Log.e(TAG, "Error getting permission usages", err);
callback.onPermissionUsageResult(Collections.emptyList());
} else {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
callback.onPermissionUsageResult(
CollectionUtils.emptyIfNull(getPermissionUsagesResult));
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 87334d5bab49..7df9a5fc7a51 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6827,6 +6827,12 @@ public final class Settings {
/**
* Whether to draw text in bold.
*
+ * <p>Values:
+ * 1 - Text is not displayed in bold. (Default)
+ * 2 - Text is displayed in bold.
+ *
+ * @see Configuration#FORCE_BOLD_TEXT_NO
+ * @see Configuration#FORCE_BOLD_TEXT_YES
* @hide
*/
public static final String FORCE_BOLD_TEXT = "force_bold_text";
@@ -14530,6 +14536,15 @@ public final class Settings {
public static final String SHOW_PEOPLE_SPACE = "show_people_space";
/**
+ * Whether to show new lockscreen & AOD UI.
+ * Values are:
+ * 0: Disabled (default)
+ * 1: Enabled
+ * @hide
+ */
+ public static final String SHOW_NEW_LOCKSCREEN = "show_new_lockscreen";
+
+ /**
* Block untrusted touches mode.
*
* Can be one of:
diff --git a/core/java/android/telephony/CellBroadcastIntents.java b/core/java/android/telephony/CellBroadcastIntents.java
index e07f69a98a85..c3ca2866c71c 100644
--- a/core/java/android/telephony/CellBroadcastIntents.java
+++ b/core/java/android/telephony/CellBroadcastIntents.java
@@ -45,7 +45,8 @@ public class CellBroadcastIntents {
private static final String EXTRA_MESSAGE = "message";
/**
- * Broadcast intent action for notifying area information has been updated. The information
+ * Broadcast intent action for notifying area information has been updated. broadcast is also
+ * sent when the user turns off area info alerts. The information
* can be retrieved by {@link CellBroadcastService#getCellBroadcastAreaInfo(int)}. The
* associated SIM slot index of updated area information can be retrieved through the extra
* {@link SubscriptionManager#EXTRA_SLOT_INDEX}.
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index 16826865987e..70c11f282a2b 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -936,18 +936,21 @@ public class PhoneStateListener {
/**
* Callback invoked when the current emergency number list has changed on the registered
* subscription.
- * Note, the registration subId comes from {@link TelephonyManager} object which registers
- * PhoneStateListener by {@link TelephonyManager#listen(PhoneStateListener, int)}.
+ *
+ * Note, the registered subscription is associated with {@link TelephonyManager} object
+ * on which {@link TelephonyManager#listen(PhoneStateListener, int)} was called.
* If this TelephonyManager object was created with
* {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
- * subId. Otherwise, this callback applies to
+ * given subId. Otherwise, this callback applies to
* {@link SubscriptionManager#getDefaultSubscriptionId()}.
*
- * @param emergencyNumberList Map including the key as the active subscription ID
- * (Note: if there is no active subscription, the key is
- * {@link SubscriptionManager#getDefaultSubscriptionId})
- * and the value as the list of {@link EmergencyNumber};
- * null if this information is not available.
+ * @param emergencyNumberList Map associating all active subscriptions on the device with the
+ * list of emergency numbers originating from that subscription.
+ * If there are no active subscriptions, the map will contain a
+ * single entry with
+ * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} as
+ * the key and a list of emergency numbers as the value. If no
+ * emergency number information is available, the value will be null.
*/
public void onEmergencyNumberListChanged(
@NonNull Map<Integer, List<EmergencyNumber>> emergencyNumberList) {
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 984acfd2c860..d441e6bbf8cb 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -2173,7 +2173,7 @@ public class TextUtils {
public static <T extends CharSequence> T trimToLengthWithEllipsis(@Nullable T text,
@IntRange(from = 1) int size) {
T trimmed = trimToSize(text, size);
- if (trimmed.length() < text.length()) {
+ if (text != null && trimmed.length() < text.length()) {
trimmed = (T) (trimmed.toString() + "...");
}
return trimmed;
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index be01bfb94f21..ac8005b39469 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -71,6 +71,12 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
public static final int FLAG_AUTO_CORRECTION = 0x0004;
/**
+ * Sets this flag if the suggestions apply to a grammar error. This type of suggestion is
+ * rendered differently to highlight the error.
+ */
+ public static final int FLAG_GRAMMAR_ERROR = 0x0008;
+
+ /**
* This action is deprecated in {@link android.os.Build.VERSION_CODES#Q}.
*
* @deprecated For IMEs to receive this kind of user interaction signals, implement IMEs' own
@@ -136,6 +142,9 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
private float mAutoCorrectionUnderlineThickness;
private int mAutoCorrectionUnderlineColor;
+ private float mGrammarErrorUnderlineThickness;
+ private int mGrammarErrorUnderlineColor;
+
/**
* @param context Context for the application
* @param suggestions Suggestions for the string under the span
@@ -190,9 +199,11 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
private void initStyle(Context context) {
if (context == null) {
mMisspelledUnderlineThickness = 0;
+ mGrammarErrorUnderlineThickness = 0;
mEasyCorrectUnderlineThickness = 0;
mAutoCorrectionUnderlineThickness = 0;
mMisspelledUnderlineColor = Color.BLACK;
+ mGrammarErrorUnderlineColor = Color.BLACK;
mEasyCorrectUnderlineColor = Color.BLACK;
mAutoCorrectionUnderlineColor = Color.BLACK;
return;
@@ -206,6 +217,14 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
mMisspelledUnderlineColor = typedArray.getColor(
com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK);
+ defStyleAttr = com.android.internal.R.attr.textAppearanceGrammarErrorSuggestion;
+ typedArray = context.obtainStyledAttributes(
+ null, com.android.internal.R.styleable.SuggestionSpan, defStyleAttr, 0);
+ mGrammarErrorUnderlineThickness = typedArray.getDimension(
+ com.android.internal.R.styleable.SuggestionSpan_textUnderlineThickness, 0);
+ mGrammarErrorUnderlineColor = typedArray.getColor(
+ com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK);
+
defStyleAttr = com.android.internal.R.attr.textAppearanceEasyCorrectSuggestion;
typedArray = context.obtainStyledAttributes(
null, com.android.internal.R.styleable.SuggestionSpan, defStyleAttr, 0);
@@ -235,6 +254,8 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
mMisspelledUnderlineThickness = src.readFloat();
mAutoCorrectionUnderlineColor = src.readInt();
mAutoCorrectionUnderlineThickness = src.readFloat();
+ mGrammarErrorUnderlineColor = src.readInt();
+ mGrammarErrorUnderlineThickness = src.readFloat();
}
/**
@@ -313,6 +334,8 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
dest.writeFloat(mMisspelledUnderlineThickness);
dest.writeInt(mAutoCorrectionUnderlineColor);
dest.writeFloat(mAutoCorrectionUnderlineThickness);
+ dest.writeInt(mGrammarErrorUnderlineColor);
+ dest.writeFloat(mGrammarErrorUnderlineThickness);
}
@Override
@@ -362,13 +385,19 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
final boolean misspelled = (mFlags & FLAG_MISSPELLED) != 0;
final boolean easy = (mFlags & FLAG_EASY_CORRECT) != 0;
final boolean autoCorrection = (mFlags & FLAG_AUTO_CORRECTION) != 0;
+ final boolean grammarError = (mFlags & FLAG_GRAMMAR_ERROR) != 0;
if (easy) {
- if (!misspelled) {
+ if (!misspelled && !grammarError) {
tp.setUnderlineText(mEasyCorrectUnderlineColor, mEasyCorrectUnderlineThickness);
} else if (tp.underlineColor == 0) {
// Spans are rendered in an arbitrary order. Since misspelled is less prioritary
// than just easy, do not apply misspelled if an easy (or a mispelled) has been set
- tp.setUnderlineText(mMisspelledUnderlineColor, mMisspelledUnderlineThickness);
+ if (grammarError) {
+ tp.setUnderlineText(
+ mGrammarErrorUnderlineColor, mGrammarErrorUnderlineThickness);
+ } else {
+ tp.setUnderlineText(mMisspelledUnderlineColor, mMisspelledUnderlineThickness);
+ }
}
} else if (autoCorrection) {
tp.setUnderlineText(mAutoCorrectionUnderlineColor, mAutoCorrectionUnderlineThickness);
@@ -384,11 +413,14 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
final boolean misspelled = (mFlags & FLAG_MISSPELLED) != 0;
final boolean easy = (mFlags & FLAG_EASY_CORRECT) != 0;
final boolean autoCorrection = (mFlags & FLAG_AUTO_CORRECTION) != 0;
+ final boolean grammarError = (mFlags & FLAG_GRAMMAR_ERROR) != 0;
if (easy) {
- if (!misspelled) {
- return mEasyCorrectUnderlineColor;
- } else {
+ if (grammarError) {
+ return mGrammarErrorUnderlineColor;
+ } else if (misspelled) {
return mMisspelledUnderlineColor;
+ } else {
+ return mEasyCorrectUnderlineColor;
}
} else if (autoCorrection) {
return mAutoCorrectionUnderlineColor;
diff --git a/core/java/android/util/IconDrawableFactory.java b/core/java/android/util/IconDrawableFactory.java
index 721e6b39d24a..5eeb12273661 100644
--- a/core/java/android/util/IconDrawableFactory.java
+++ b/core/java/android/util/IconDrawableFactory.java
@@ -48,7 +48,7 @@ public class IconDrawableFactory {
}
protected boolean needsBadging(ApplicationInfo appInfo, @UserIdInt int userId) {
- return appInfo.isInstantApp() || mUm.isManagedProfile(userId);
+ return appInfo.isInstantApp() || mUm.hasBadge(userId);
}
@UnsupportedAppUsage
diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java
new file mode 100644
index 000000000000..8097dc6dca11
--- /dev/null
+++ b/core/java/android/uwb/UwbManager.java
@@ -0,0 +1,269 @@
+/*
+ * 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.uwb;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SuppressLint;
+import android.os.PersistableBundle;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.Executor;
+
+/**
+ * This class provides a way to perform Ultra Wideband (UWB) operations such as querying the
+ * device's capabilities and determining the distance and angle between the local device and a
+ * remote device.
+ *
+ * <p>To get a {@link UwbManager}, call the <code>Context.getSystemService(UwbManager.class)</code>.
+ *
+ * @hide
+ */
+public final class UwbManager {
+ /**
+ * Interface for receiving UWB adapter state changes
+ */
+ public interface AdapterStateCallback {
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ STATE_CHANGED_REASON_SESSION_STARTED,
+ STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED,
+ STATE_CHANGED_REASON_SYSTEM_POLICY,
+ STATE_CHANGED_REASON_SYSTEM_BOOT,
+ STATE_CHANGED_REASON_ERROR_UNKNOWN})
+ @interface StateChangedReason {}
+
+ /**
+ * Indicates that the state change was due to opening of first UWB session
+ */
+ int STATE_CHANGED_REASON_SESSION_STARTED = 0;
+
+ /**
+ * Indicates that the state change was due to closure of all UWB sessions
+ */
+ int STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED = 1;
+
+ /**
+ * Indicates that the state change was due to changes in system policy
+ */
+ int STATE_CHANGED_REASON_SYSTEM_POLICY = 2;
+
+ /**
+ * Indicates that the current state is due to a system boot
+ */
+ int STATE_CHANGED_REASON_SYSTEM_BOOT = 3;
+
+ /**
+ * Indicates that the state change was due to some unknown error
+ */
+ int STATE_CHANGED_REASON_ERROR_UNKNOWN = 4;
+
+ /**
+ * Invoked when underlying UWB adapter's state is changed
+ * <p>Invoked with the adapter's current state after registering an
+ * {@link AdapterStateCallback} using
+ * {@link UwbManager#registerAdapterStateCallback(Executor, AdapterStateCallback)}.
+ *
+ * <p>Possible values for the state to change are
+ * {@link #STATE_CHANGED_REASON_SESSION_STARTED},
+ * {@link #STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED},
+ * {@link #STATE_CHANGED_REASON_SYSTEM_POLICY},
+ * {@link #STATE_CHANGED_REASON_SYSTEM_BOOT},
+ * {@link #STATE_CHANGED_REASON_ERROR_UNKNOWN}.
+ *
+ * @param isEnabled true when UWB adapter is enabled, false when it is disabled
+ * @param reason the reason for the state change
+ */
+ void onStateChanged(boolean isEnabled, @StateChangedReason int reason);
+ }
+
+ /**
+ * Use <code>Context.getSystemService(UwbManager.class)</code> to get an instance.
+ */
+ private UwbManager() {
+ throw new UnsupportedOperationException();
+ }
+ /**
+ * Register an {@link AdapterStateCallback} to listen for UWB adapter state changes
+ * <p>The provided callback will be invoked by the given {@link Executor}.
+ *
+ * <p>When first registering a callback, the callbacks's
+ * {@link AdapterStateCallback#onStateChanged(boolean, int)} is immediately invoked to indicate
+ * the current state of the underlying UWB adapter with the most recent
+ * {@link AdapterStateCallback.StateChangedReason} that caused the change.
+ *
+ * @param executor an {@link Executor} to execute given callback
+ * @param callback user implementation of the {@link AdapterStateCallback}
+ */
+ public void registerAdapterStateCallback(Executor executor, AdapterStateCallback callback) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Unregister the specified {@link AdapterStateCallback}
+ * <p>The same {@link AdapterStateCallback} object used when calling
+ * {@link #registerAdapterStateCallback(Executor, AdapterStateCallback)} must be used.
+ *
+ * <p>Callbacks are automatically unregistered when application process goes away
+ *
+ * @param callback user implementation of the {@link AdapterStateCallback}
+ */
+ public void unregisterAdapterStateCallback(AdapterStateCallback callback) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Get a {@link PersistableBundle} with the supported UWB protocols and parameters.
+ * <p>The {@link PersistableBundle} should be parsed using a support library
+ *
+ * <p>Android reserves the '^android.*' namespace</p>
+ *
+ * @return {@link PersistableBundle} of the device's supported UWB protocols and parameters
+ */
+ @NonNull
+ public PersistableBundle getSpecificationInfo() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Check if ranging is supported, regardless of ranging method
+ *
+ * @return true if ranging is supported
+ */
+ public boolean isRangingSupported() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE,
+ ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D,
+ ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL,
+ ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL})
+ public @interface AngleOfArrivalSupportType {}
+
+ /**
+ * Indicate absence of support for angle of arrival measurement
+ */
+ public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE = 1;
+
+ /**
+ * Indicate support for planar angle of arrival measurement, due to antenna
+ * limitation. Typically requires at least two antennas.
+ */
+ public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D = 2;
+
+ /**
+ * Indicate support for three dimensional angle of arrival measurement.
+ * Typically requires at least three antennas. However, due to antenna
+ * arrangement, a platform may only support hemi-spherical azimuth angles
+ * ranging from -pi/2 to pi/2
+ */
+ public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL = 2;
+
+ /**
+ * Indicate support for three dimensional angle of arrival measurement.
+ * Typically requires at least three antennas. This mode supports full
+ * azimuth angles ranging from -pi to pi.
+ */
+ public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL = 3;
+
+
+ /**
+ * Gets the {@link AngleOfArrivalSupportType} supported on this platform
+ * <p>Possible return values are
+ * {@link #ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE},
+ * {@link #ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D},
+ * {@link #ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL},
+ * {@link #ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL}.
+ *
+ * @return angle of arrival type supported
+ */
+ @AngleOfArrivalSupportType
+ public int getAngleOfArrivalSupport() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Get a {@link List} of supported channel numbers based on the device's current location
+ * <p>The returned values are ordered by the system's desired ordered of use, with the first
+ * entry being the most preferred.
+ *
+ * <p>Channel numbers are defined based on the IEEE 802.15.4z standard for UWB.
+ *
+ * @return {@link List} of supported channel numbers ordered by preference
+ */
+ @NonNull
+ public List<Integer> getSupportedChannelNumbers() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Get a {@link List} of supported preamble code indices
+ * <p> Preamble code indices are defined based on the IEEE 802.15.4z standard for UWB.
+ *
+ * @return {@link List} of supported preamble code indices
+ */
+ @NonNull
+ public Set<Integer> getSupportedPreambleCodeIndices() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Get the timestamp resolution for events in nanoseconds
+ * <p>This value defines the maximum error of all timestamps for events reported to
+ * {@link RangingSession.Callback}.
+ *
+ * @return the timestamp resolution in nanoseconds
+ */
+ @SuppressLint("MethodNameUnits")
+ public long elapsedRealtimeResolutionNanos() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Get the number of simultaneous sessions allowed in the system
+ *
+ * @return the maximum allowed number of simultaneously open {@link RangingSession} instances.
+ */
+ public int getMaxSimultaneousSessions() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Get the maximum number of remote devices in a {@link RangingSession} when the local device
+ * is the initiator.
+ *
+ * @return the maximum number of remote devices per {@link RangingSession}
+ */
+ public int getMaxRemoteDevicesPerInitiatorSession() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Get the maximum number of remote devices in a {@link RangingSession} when the local device
+ * is a responder.
+ *
+ * @return the maximum number of remote devices per {@link RangingSession}
+ */
+ public int getMaxRemoteDevicesPerResponderSession() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index 41cc8459a266..ec54007e9979 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -188,7 +188,13 @@ public class InsetsSource implements Parcelable {
return false;
}
- void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ /**
+ * Export the state of {@link InsetsSource} into a protocol buffer output stream.
+ *
+ * @param proto Stream to write the state to
+ * @param fieldId FieldId of InsetsSource as defined in the parent message
+ */
+ public void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
proto.write(TYPE, InsetsState.typeToString(mType));
mFrame.dumpDebug(proto, FRAME);
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index b45bd3869f64..5ddbd029f113 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -128,7 +128,13 @@ public class InsetsSourceControl implements Parcelable {
}
};
- void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ /**
+ * Export the state of {@link InsetsSourceControl} into a protocol buffer output stream.
+ *
+ * @param proto Stream to write the state to
+ * @param fieldId FieldId of InsetsSource as defined in the parent message
+ */
+ public void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
proto.write(TYPE, InsetsState.typeToString(mType));
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 0c64eeac2ec7..ed9deecd7e88 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -267,7 +267,7 @@ public final class SurfaceControl implements Parcelable {
private WeakReference<View> mLocalOwnerView;
- static Transaction sGlobalTransaction;
+ static GlobalTransactionWrapper sGlobalTransaction;
static long sTransactionNestCount = 0;
/**
@@ -1453,7 +1453,7 @@ public final class SurfaceControl implements Parcelable {
public static void openTransaction() {
synchronized (SurfaceControl.class) {
if (sGlobalTransaction == null) {
- sGlobalTransaction = new Transaction();
+ sGlobalTransaction = new GlobalTransactionWrapper();
}
synchronized(SurfaceControl.class) {
sTransactionNestCount++;
@@ -1487,7 +1487,7 @@ public final class SurfaceControl implements Parcelable {
} else if (--sTransactionNestCount > 0) {
return;
}
- sGlobalTransaction.apply();
+ sGlobalTransaction.applyGlobalTransaction(false);
}
}
@@ -2555,7 +2555,10 @@ public final class SurfaceControl implements Parcelable {
nativeApplyTransaction(mNativeObject, sync);
}
- private void applyResizedSurfaces() {
+ /**
+ * @hide
+ */
+ protected void applyResizedSurfaces() {
for (int i = mResizedSurfaces.size() - 1; i >= 0; i--) {
final Point size = mResizedSurfaces.valueAt(i);
final SurfaceControl surfaceControl = mResizedSurfaces.keyAt(i);
@@ -2567,7 +2570,10 @@ public final class SurfaceControl implements Parcelable {
mResizedSurfaces.clear();
}
- private void notifyReparentedSurfaces() {
+ /**
+ * @hide
+ */
+ protected void notifyReparentedSurfaces() {
final int reparentCount = mReparentedSurfaces.size();
for (int i = reparentCount - 1; i >= 0; i--) {
final SurfaceControl child = mReparentedSurfaces.keyAt(i);
@@ -3403,6 +3409,26 @@ public final class SurfaceControl implements Parcelable {
}
/**
+ * As part of eliminating usage of the global Transaction we expose
+ * a SurfaceControl.getGlobalTransaction function. However calling
+ * apply on this global transaction (rather than using closeTransaction)
+ * would be very dangerous. So for the global transaction we use this
+ * subclass of Transaction where the normal apply throws an exception.
+ */
+ private static class GlobalTransactionWrapper extends SurfaceControl.Transaction {
+ void applyGlobalTransaction(boolean sync) {
+ applyResizedSurfaces();
+ notifyReparentedSurfaces();
+ nativeApplyTransaction(mNativeObject, sync);
+ }
+
+ @Override
+ public void apply(boolean sync) {
+ throw new RuntimeException("Global transaction must be applied from closeTransaction");
+ }
+ }
+
+ /**
* Acquire a frame rate flexibility token, which allows surface flinger to freely switch display
* frame rates. This is used by CTS tests to put the device in a consistent state. See
* ISurfaceComposer::acquireFrameRateFlexibilityToken(). The caller must have the
@@ -3422,4 +3448,17 @@ public final class SurfaceControl implements Parcelable {
public static void releaseFrameRateFlexibilityToken(long token) {
nativeReleaseFrameRateFlexibilityToken(token);
}
+
+ /**
+ * This is a refactoring utility function to enable lower levels of code to be refactored
+ * from using the global transaction (and instead use a passed in Transaction) without
+ * having to refactor the higher levels at the same time.
+ * The returned global transaction can't be applied, it must be applied from closeTransaction
+ * Unless you are working on removing Global Transaction usage in the WindowManager, this
+ * probably isn't a good function to use.
+ * @hide
+ */
+ public static Transaction getGlobalTransaction() {
+ return sGlobalTransaction;
+ }
}
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 299ae2f0c55e..d803f8bfa6cc 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -441,8 +441,8 @@ public final class AccessibilityInteractionClient
prefetchFlags &= ~AccessibilityNodeInfo.FLAG_PREFETCH_MASK;
}
final int interactionId = mInteractionIdCounter.getAndIncrement();
- final long identityToken = Binder.clearCallingIdentity();
final String[] packageNames;
+ final long identityToken = Binder.clearCallingIdentity();
try {
packageNames = connection.findAccessibilityNodeInfoByAccessibilityId(
accessibilityWindowId, accessibilityNodeId, interactionId, this,
@@ -501,8 +501,8 @@ public final class AccessibilityInteractionClient
IAccessibilityServiceConnection connection = getConnection(connectionId);
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
- final long identityToken = Binder.clearCallingIdentity();
final String[] packageNames;
+ final long identityToken = Binder.clearCallingIdentity();
try {
packageNames = connection.findAccessibilityNodeInfosByViewId(
accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this,
@@ -555,8 +555,8 @@ public final class AccessibilityInteractionClient
IAccessibilityServiceConnection connection = getConnection(connectionId);
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
- final long identityToken = Binder.clearCallingIdentity();
final String[] packageNames;
+ final long identityToken = Binder.clearCallingIdentity();
try {
packageNames = connection.findAccessibilityNodeInfosByText(
accessibilityWindowId, accessibilityNodeId, text, interactionId, this,
@@ -608,8 +608,8 @@ public final class AccessibilityInteractionClient
IAccessibilityServiceConnection connection = getConnection(connectionId);
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
- final long identityToken = Binder.clearCallingIdentity();
final String[] packageNames;
+ final long identityToken = Binder.clearCallingIdentity();
try {
packageNames = connection.findFocus(accessibilityWindowId,
accessibilityNodeId, focusType, interactionId, this,
@@ -657,8 +657,8 @@ public final class AccessibilityInteractionClient
IAccessibilityServiceConnection connection = getConnection(connectionId);
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
- final long identityToken = Binder.clearCallingIdentity();
final String[] packageNames;
+ final long identityToken = Binder.clearCallingIdentity();
try {
packageNames = connection.focusSearch(accessibilityWindowId,
accessibilityNodeId, direction, interactionId, this,
@@ -705,8 +705,8 @@ public final class AccessibilityInteractionClient
IAccessibilityServiceConnection connection = getConnection(connectionId);
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
- final long identityToken = Binder.clearCallingIdentity();
final boolean success;
+ final long identityToken = Binder.clearCallingIdentity();
try {
success = connection.performAccessibilityAction(
accessibilityWindowId, accessibilityNodeId, action, arguments,
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 16f35ad8c24c..aed9b89747d0 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -606,7 +606,7 @@ public final class AccessibilityManager {
// it is possible that this manager is in the same process as the service but
// client using it is called through Binder from another process. Example: MMS
// app adds a SMS notification and the NotificationManagerService calls this method
- long identityToken = Binder.clearCallingIdentity();
+ final long identityToken = Binder.clearCallingIdentity();
try {
service.sendAccessibilityEvent(dispatchedEvent, userId);
} finally {
diff --git a/core/java/android/view/textservice/SuggestionsInfo.java b/core/java/android/view/textservice/SuggestionsInfo.java
index e69b6e7277a8..ca529f626cfe 100644
--- a/core/java/android/view/textservice/SuggestionsInfo.java
+++ b/core/java/android/view/textservice/SuggestionsInfo.java
@@ -45,6 +45,14 @@ public final class SuggestionsInfo implements Parcelable {
* the result suggestions include highly recommended ones.
*/
public static final int RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = 0x0004;
+
+ /**
+ * Flag of the attributes of the suggestions that can be obtained by
+ * {@link #getSuggestionsAttributes}: this tells that the text service thinks the requested
+ * sentence contains a grammar error.
+ */
+ public static final int RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR = 0x0008;
+
private final int mSuggestionsAttributes;
private final String[] mSuggestions;
private final boolean mSuggestionsAvailable;
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index fa195211fb54..eaa738d59577 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -186,6 +186,9 @@ public class Editor {
private static final int MENU_ITEM_ORDER_SECONDARY_ASSIST_ACTIONS_START = 50;
private static final int MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START = 100;
+ private static final int FLAG_MISSPELLED_OR_GRAMMAR_ERROR =
+ SuggestionSpan.FLAG_MISSPELLED | SuggestionSpan.FLAG_GRAMMAR_ERROR;
+
@IntDef({MagnifierHandleTrigger.SELECTION_START,
MagnifierHandleTrigger.SELECTION_END,
MagnifierHandleTrigger.INSERTION})
@@ -1552,7 +1555,7 @@ public class Editor {
for (int i = 0; i < suggestionSpans.length; i++) {
int flags = suggestionSpans[i].getFlags();
if ((flags & SuggestionSpan.FLAG_EASY_CORRECT) != 0
- && (flags & SuggestionSpan.FLAG_MISSPELLED) == 0) {
+ && (flags & FLAG_MISSPELLED_OR_GRAMMAR_ERROR) == 0) {
flags &= ~SuggestionSpan.FLAG_EASY_CORRECT;
suggestionSpans[i].setFlags(flags);
}
@@ -3064,8 +3067,9 @@ public class Editor {
// Remove potential misspelled flags
int suggestionSpanFlags = suggestionSpan.getFlags();
- if ((suggestionSpanFlags & SuggestionSpan.FLAG_MISSPELLED) != 0) {
+ if ((suggestionSpanFlags & FLAG_MISSPELLED_OR_GRAMMAR_ERROR) != 0) {
suggestionSpanFlags &= ~SuggestionSpan.FLAG_MISSPELLED;
+ suggestionSpanFlags &= ~SuggestionSpan.FLAG_GRAMMAR_ERROR;
suggestionSpanFlags &= ~SuggestionSpan.FLAG_EASY_CORRECT;
suggestionSpan.setFlags(suggestionSpanFlags);
}
@@ -3601,19 +3605,29 @@ public class Editor {
final int flag1 = span1.getFlags();
final int flag2 = span2.getFlags();
if (flag1 != flag2) {
- // The order here should match what is used in updateDrawState
- final boolean easy1 = (flag1 & SuggestionSpan.FLAG_EASY_CORRECT) != 0;
- final boolean easy2 = (flag2 & SuggestionSpan.FLAG_EASY_CORRECT) != 0;
- final boolean misspelled1 = (flag1 & SuggestionSpan.FLAG_MISSPELLED) != 0;
- final boolean misspelled2 = (flag2 & SuggestionSpan.FLAG_MISSPELLED) != 0;
- if (easy1 && !misspelled1) return -1;
- if (easy2 && !misspelled2) return 1;
- if (misspelled1) return -1;
- if (misspelled2) return 1;
+ // Compare so that the order will be: easy -> misspelled -> grammarError
+ int easy = compareFlag(SuggestionSpan.FLAG_EASY_CORRECT, flag1, flag2);
+ if (easy != 0) return easy;
+ int misspelled = compareFlag(SuggestionSpan.FLAG_MISSPELLED, flag1, flag2);
+ if (misspelled != 0) return misspelled;
+ int grammarError = compareFlag(SuggestionSpan.FLAG_GRAMMAR_ERROR, flag1, flag2);
+ if (grammarError != 0) return grammarError;
}
return mSpansLengths.get(span1).intValue() - mSpansLengths.get(span2).intValue();
}
+
+ /*
+ * Returns -1 if flags1 has flagToCompare but flags2 does not.
+ * Returns 1 if flags2 has flagToCompare but flags1 does not.
+ * Otherwise, returns 0.
+ */
+ private int compareFlag(int flagToCompare, int flags1, int flags2) {
+ boolean hasFlag1 = (flags1 & flagToCompare) != 0;
+ boolean hasFlag2 = (flags2 & flagToCompare) != 0;
+ if (hasFlag1 == hasFlag2) return 0;
+ return hasFlag1 ? -1 : 1;
+ }
}
/**
@@ -3632,8 +3646,9 @@ public class Editor {
mSpansLengths.put(suggestionSpan, Integer.valueOf(end - start));
}
- // The suggestions are sorted according to their types (easy correction first, then
- // misspelled) and to the length of the text that they cover (shorter first).
+ // The suggestions are sorted according to their types (easy correction first,
+ // misspelled second, then grammar error) and to the length of the text that they cover
+ // (shorter first).
Arrays.sort(suggestionSpans, mSuggestionSpanComparator);
mSpansLengths.clear();
@@ -3661,7 +3676,7 @@ public class Editor {
final int spanEnd = spannable.getSpanEnd(suggestionSpan);
if (misspelledSpanInfo != null
- && (suggestionSpan.getFlags() & SuggestionSpan.FLAG_MISSPELLED) != 0) {
+ && (suggestionSpan.getFlags() & FLAG_MISSPELLED_OR_GRAMMAR_ERROR) != 0) {
misspelledSpanInfo.mSuggestionSpan = suggestionSpan;
misspelledSpanInfo.mSpanStart = spanStart;
misspelledSpanInfo.mSpanEnd = spanEnd;
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index d4aad752daa0..0611bea7978d 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -338,11 +338,13 @@ public class SpellChecker implements SpellCheckerSessionListener {
((attributes & SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY) > 0);
final boolean looksLikeTypo =
((attributes & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) > 0);
+ final boolean looksLikeGrammarError =
+ ((attributes & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR) > 0);
final SpellCheckSpan spellCheckSpan = mSpellCheckSpans[k];
//TODO: we need to change that rule for results from a sentence-level spell
// checker that will probably be in dictionary.
- if (!isInDictionary && looksLikeTypo) {
+ if (!isInDictionary && (looksLikeTypo || looksLikeGrammarError)) {
createMisspelledSuggestionSpan(
editable, suggestionsInfo, spellCheckSpan, offset, length);
} else {
@@ -482,8 +484,16 @@ public class SpellChecker implements SpellCheckerSessionListener {
suggestions = ArrayUtils.emptyArray(String.class);
}
- SuggestionSpan suggestionSpan = new SuggestionSpan(mTextView.getContext(), suggestions,
- SuggestionSpan.FLAG_EASY_CORRECT | SuggestionSpan.FLAG_MISSPELLED);
+ final int suggestionsAttrs = suggestionsInfo.getSuggestionsAttributes();
+ int flags = SuggestionSpan.FLAG_EASY_CORRECT;
+ if ((suggestionsAttrs & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) != 0) {
+ flags |= SuggestionSpan.FLAG_MISSPELLED;
+ }
+ if ((suggestionsAttrs & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR) != 0) {
+ flags |= SuggestionSpan.FLAG_GRAMMAR_ERROR;
+ }
+ SuggestionSpan suggestionSpan =
+ new SuggestionSpan(mTextView.getContext(), suggestions, flags);
// TODO: Remove mIsSentenceSpellCheckSupported by extracting an interface
// to share the logic of word level spell checker and sentence level spell checker
if (mIsSentenceSpellCheckSupported) {
diff --git a/core/java/android/widget/ToastPresenter.java b/core/java/android/widget/ToastPresenter.java
index fb5d55dd2141..b484dfacbf6c 100644
--- a/core/java/android/widget/ToastPresenter.java
+++ b/core/java/android/widget/ToastPresenter.java
@@ -48,6 +48,8 @@ import com.android.internal.util.ArrayUtils;
public class ToastPresenter {
private static final String TAG = "ToastPresenter";
private static final String WINDOW_TITLE = "Toast";
+
+ // exclusively used to guarantee window timeouts
private static final long SHORT_DURATION_TIMEOUT = 4000;
private static final long LONG_DURATION_TIMEOUT = 7000;
@@ -145,7 +147,7 @@ public class ToastPresenter {
*/
private void adjustLayoutParams(WindowManager.LayoutParams params, IBinder windowToken,
int duration, int gravity, int xOffset, int yOffset, float horizontalMargin,
- float verticalMargin) {
+ float verticalMargin, boolean removeWindowAnimations) {
Configuration config = mResources.getConfiguration();
int absGravity = Gravity.getAbsoluteGravity(gravity, config.getLayoutDirection());
params.gravity = absGravity;
@@ -163,6 +165,10 @@ public class ToastPresenter {
params.hideTimeoutMilliseconds =
(duration == Toast.LENGTH_LONG) ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
params.token = windowToken;
+
+ if (removeWindowAnimations && params.windowAnimations == R.style.Animation_Toast) {
+ params.windowAnimations = 0;
+ }
}
/**
@@ -193,16 +199,28 @@ public class ToastPresenter {
/**
* Shows the toast in {@code view} with the parameters passed and callback {@code callback}.
+ * Uses window animations to animate the toast.
*/
public void show(View view, IBinder token, IBinder windowToken, int duration, int gravity,
int xOffset, int yOffset, float horizontalMargin, float verticalMargin,
@Nullable ITransientNotificationCallback callback) {
+ show(view, token, windowToken, duration, gravity, xOffset, yOffset, horizontalMargin,
+ verticalMargin, callback, false /* removeWindowAnimations */);
+ }
+
+ /**
+ * Shows the toast in {@code view} with the parameters passed and callback {@code callback}.
+ * Can optionally remove window animations from the toast window.
+ */
+ public void show(View view, IBinder token, IBinder windowToken, int duration, int gravity,
+ int xOffset, int yOffset, float horizontalMargin, float verticalMargin,
+ @Nullable ITransientNotificationCallback callback, boolean removeWindowAnimations) {
checkState(mView == null, "Only one toast at a time is allowed, call hide() first.");
mView = view;
mToken = token;
adjustLayoutParams(mParams, windowToken, duration, gravity, xOffset, yOffset,
- horizontalMargin, verticalMargin);
+ horizontalMargin, verticalMargin, removeWindowAnimations);
if (mView.getParent() != null) {
mWindowManager.removeView(mView);
}
@@ -247,7 +265,8 @@ public class ToastPresenter {
try {
callback.onToastHidden();
} catch (RemoteException e) {
- Log.w(TAG, "Error calling back " + mPackageName + " to notify onToastHide()", e);
+ Log.w(TAG, "Error calling back " + mPackageName + " to notify onToastHide()",
+ e);
}
}
mView = null;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 61a625e40dcd..e0f8a1ad0a1a 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -1855,6 +1855,7 @@ public class ChooserActivity extends ResolverActivity implements
@VisibleForTesting
protected void queryTargetServices(ChooserListAdapter adapter) {
+
mQueriedTargetServicesTimeMs = System.currentTimeMillis();
Context selectedProfileContext = createContextAsUser(
@@ -1871,15 +1872,14 @@ public class ChooserActivity extends ResolverActivity implements
continue;
}
final ActivityInfo ai = dri.getResolveInfo().activityInfo;
- if (ChooserFlags.USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS
- && sm.hasShareTargets(ai.packageName)) {
+ if (sm.hasShareTargets(ai.packageName)) {
// Share targets will be queried from ShortcutManager
continue;
}
final Bundle md = ai.metaData;
final String serviceName = md != null ? convertServiceName(ai.packageName,
md.getString(ChooserTargetService.META_DATA_NAME)) : null;
- if (serviceName != null) {
+ if (serviceName != null && ChooserFlags.USE_SERVICE_TARGETS_FOR_DIRECT_TARGETS) {
final ComponentName serviceComponent = new ComponentName(
ai.packageName, serviceName);
@@ -2883,8 +2883,7 @@ public class ChooserActivity extends ResolverActivity implements
return;
}
- if (ChooserFlags.USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS
- || ChooserFlags.USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) {
+ if (ChooserFlags.USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) {
if (DEBUG) {
Log.d(TAG, "querying direct share targets from ShortcutManager");
}
diff --git a/core/java/com/android/internal/app/ChooserFlags.java b/core/java/com/android/internal/app/ChooserFlags.java
index f1f1dbf49b8b..3e26679e28a4 100644
--- a/core/java/com/android/internal/app/ChooserFlags.java
+++ b/core/java/com/android/internal/app/ChooserFlags.java
@@ -17,22 +17,29 @@
package com.android.internal.app;
import android.app.prediction.AppPredictionManager;
+import android.provider.DeviceConfig;
+
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
/**
* Common flags for {@link ChooserListAdapter} and {@link ChooserActivity}.
*/
public class ChooserFlags {
+
/**
- * If set to true, use ShortcutManager to retrieve the matching direct share targets, instead of
- * binding to every ChooserTargetService implementation.
+ * Whether to use the deprecated {@link android.service.chooser.ChooserTargetService} API for
+ * direct share targets. If true, both CTS and Shortcuts will be used to find Direct Share
+ * targets. If false, only Shortcuts will be used.
*/
- // TODO(b/121287573): Replace with a system flag (setprop?)
- public static final boolean USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS = true;
+ public static final boolean USE_SERVICE_TARGETS_FOR_DIRECT_TARGETS =
+ DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
+ SystemUiDeviceConfigFlags.SHARE_USE_SERVICE_TARGETS, true);
/**
- * If {@link ChooserFlags#USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS} and this is set to true,
- * {@link AppPredictionManager} will be queried for direct share targets.
+ * Whether to use {@link AppPredictionManager} to query for direct share targets (as opposed to
+ * talking directly to {@link android.content.pm.ShortcutManager}.
*/
// TODO(b/123089490): Replace with system flag
static final boolean USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS = true;
}
+
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 51e56b7fca43..04146bcad083 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -56,6 +56,13 @@ interface IAppOpsService {
String proxiedAttributionTag, int proxyUid, String proxyPackageName,
String proxyAttributionTag, boolean shouldCollectAsyncNotedOp, String message,
boolean shouldCollectMessage);
+ int startProxyOperation(IBinder clientId, int code, int proxiedUid, String proxiedPackageName,
+ @nullable String proxiedAttributionTag, int proxyUid, String proxyPackageName,
+ @nullable String proxyAttributionTag, boolean startIfModeDefault,
+ boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage);
+ void finishProxyOperation(IBinder clientId, int code, int proxiedUid, String proxiedPackageName,
+ @nullable String proxiedAttributionTag, int proxyUid, String proxyPackageName,
+ @nullable String proxyAttributionTag);
// Remaining methods are only used in Java.
int checkPackage(int uid, String packageName);
diff --git a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
index 28a96013e1c0..ce75f45d0897 100644
--- a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
+++ b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
@@ -38,7 +38,6 @@ import android.text.SpannableStringBuilder;
import android.util.Log;
import com.android.internal.app.ChooserActivity;
-import com.android.internal.app.ChooserFlags;
import com.android.internal.app.ResolverActivity;
import com.android.internal.app.ResolverListAdapter.ActivityInfoPresentationGetter;
import com.android.internal.app.SimpleIconFactory;
@@ -147,7 +146,7 @@ public final class SelectableTargetInfo implements ChooserTargetInfo {
final Icon icon = target.getIcon();
if (icon != null) {
directShareIcon = icon.loadDrawable(mContext);
- } else if (ChooserFlags.USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS && shortcutInfo != null) {
+ } else if (shortcutInfo != null) {
LauncherApps launcherApps = (LauncherApps) mContext.getSystemService(
Context.LAUNCHER_APPS_SERVICE);
directShareIcon = launcherApps.getShortcutIconDrawable(shortcutInfo, 0);
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 1ce246ad4274..d23ea3c46695 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -429,6 +429,14 @@ public final class SystemUiDeviceConfigFlags {
*/
public static final String BACK_GESTURE_ML_MODEL_THRESHOLD = "back_gesture_ml_model_threshold";
+ /**
+ * (boolean) Sharesheet - Whether to use the deprecated
+ * {@link android.service.chooser.ChooserTargetService} API for
+ * direct share targets. If true, both CTS and Shortcuts will be used to find Direct
+ * Share targets. If false, only Shortcuts will be used.
+ */
+ public static final String SHARE_USE_SERVICE_TARGETS = "share_use_service_targets";
+
private SystemUiDeviceConfigFlags() {
}
diff --git a/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java b/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java
index f1398bf67283..70505bc5895b 100644
--- a/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractMultiplePendingRequestsRemoteService.java
@@ -25,6 +25,7 @@ import android.util.Slog;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.List;
/**
* Base class representing a remote service that can queue multiple pending requests while not
@@ -39,7 +40,7 @@ public abstract class AbstractMultiplePendingRequestsRemoteService<S
private final int mInitialCapacity;
- protected ArrayList<BasePendingRequest<S, I>> mPendingRequests;
+ protected @NonNull List<BasePendingRequest<S, I>> mPendingRequests;
public AbstractMultiplePendingRequestsRemoteService(@NonNull Context context,
@NonNull String serviceInterface, @NonNull ComponentName componentName, int userId,
@@ -48,35 +49,36 @@ public abstract class AbstractMultiplePendingRequestsRemoteService<S
super(context, serviceInterface, componentName, userId, callback, handler, bindingFlags,
verbose);
mInitialCapacity = initialCapacity;
+ mPendingRequests = new ArrayList<>(mInitialCapacity);
}
@Override // from AbstractRemoteService
void handlePendingRequests() {
- if (mPendingRequests != null) {
+ synchronized (mPendingRequests) {
final int size = mPendingRequests.size();
if (mVerbose) Slog.v(mTag, "Sending " + size + " pending requests");
for (int i = 0; i < size; i++) {
mPendingRequests.get(i).run();
}
- mPendingRequests = null;
+ mPendingRequests.clear();
}
}
@Override // from AbstractRemoteService
protected void handleOnDestroy() {
- if (mPendingRequests != null) {
+ synchronized (mPendingRequests) {
final int size = mPendingRequests.size();
if (mVerbose) Slog.v(mTag, "Canceling " + size + " pending requests");
for (int i = 0; i < size; i++) {
mPendingRequests.get(i).cancel();
}
- mPendingRequests = null;
+ mPendingRequests.clear();
}
}
@Override // from AbstractRemoteService
final void handleBindFailure() {
- if (mPendingRequests != null) {
+ synchronized (mPendingRequests) {
final int size = mPendingRequests.size();
if (mVerbose) Slog.v(mTag, "Sending failure to " + size + " pending requests");
for (int i = 0; i < size; i++) {
@@ -84,7 +86,7 @@ public abstract class AbstractMultiplePendingRequestsRemoteService<S
request.onFailed();
request.finish();
}
- mPendingRequests = null;
+ mPendingRequests.clear();
}
}
@@ -94,18 +96,21 @@ public abstract class AbstractMultiplePendingRequestsRemoteService<S
pw.append(prefix).append("initialCapacity=").append(String.valueOf(mInitialCapacity))
.println();
- final int size = mPendingRequests == null ? 0 : mPendingRequests.size();
+ int size;
+ synchronized (mPendingRequests) {
+ size = mPendingRequests.size();
+ }
pw.append(prefix).append("pendingRequests=").append(String.valueOf(size)).println();
}
@Override // from AbstractRemoteService
void handlePendingRequestWhileUnBound(@NonNull BasePendingRequest<S, I> pendingRequest) {
- if (mPendingRequests == null) {
- mPendingRequests = new ArrayList<>(mInitialCapacity);
- }
- mPendingRequests.add(pendingRequest);
- if (mVerbose) {
- Slog.v(mTag, "queued " + mPendingRequests.size() + " requests; last=" + pendingRequest);
+ synchronized (mPendingRequests) {
+ mPendingRequests.add(pendingRequest);
+ if (mVerbose) {
+ Slog.v(mTag,
+ "queued " + mPendingRequests.size() + " requests; last=" + pendingRequest);
+ }
}
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 308af99d465a..17323ba2f16b 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -1019,8 +1019,6 @@ public class BatteryStatsImpl extends BatteryStats {
*/
private LongSamplingCounterArray mSystemServerCpuTimesUs;
- private long[] mTmpSystemServerCpuTimesUs;
-
/**
* Times spent by the system server threads grouped by cluster and CPU speed.
*/
@@ -12432,41 +12430,15 @@ public class BatteryStatsImpl extends BatteryStats {
return;
}
- int numCpuClusters = mPowerProfile.getNumCpuClusters();
if (mSystemServerCpuTimesUs == null) {
mSystemServerCpuTimesUs = new LongSamplingCounterArray(mOnBatteryTimeBase);
mSystemServerThreadCpuTimesUs = new LongSamplingCounterArray(mOnBatteryTimeBase);
mBinderThreadCpuTimesUs = new LongSamplingCounterArray(mOnBatteryTimeBase);
}
+ mSystemServerCpuTimesUs.addCountLocked(systemServiceCpuThreadTimes.processCpuTimesUs);
mSystemServerThreadCpuTimesUs.addCountLocked(systemServiceCpuThreadTimes.threadCpuTimesUs);
mBinderThreadCpuTimesUs.addCountLocked(systemServiceCpuThreadTimes.binderThreadCpuTimesUs);
- long totalCpuTimeAllThreads = 0;
- for (int index = systemServiceCpuThreadTimes.threadCpuTimesUs.length - 1; index >= 0;
- index--) {
- totalCpuTimeAllThreads += systemServiceCpuThreadTimes.threadCpuTimesUs[index];
- }
-
- // Estimate per cluster per frequency CPU time for the entire process
- // by distributing the total process CPU time proportionately to how much
- // CPU time its threads took on those clusters/frequencies. This algorithm
- // works more accurately when when we have equally distributed concurrency.
- // TODO(b/169279846): obtain actual process CPU times from the kernel
- long processCpuTime = systemServiceCpuThreadTimes.processCpuTimeUs;
- if (mTmpSystemServerCpuTimesUs == null) {
- mTmpSystemServerCpuTimesUs =
- new long[systemServiceCpuThreadTimes.threadCpuTimesUs.length];
- }
- for (int index = systemServiceCpuThreadTimes.threadCpuTimesUs.length - 1; index >= 0;
- index--) {
- mTmpSystemServerCpuTimesUs[index] =
- processCpuTime * systemServiceCpuThreadTimes.threadCpuTimesUs[index]
- / totalCpuTimeAllThreads;
-
- }
-
- mSystemServerCpuTimesUs.addCountLocked(mTmpSystemServerCpuTimesUs);
-
if (DEBUG_BINDER_STATS) {
Slog.d(TAG, "System server threads per CPU cluster (binder threads/total threads/%)");
long totalCpuTimeMs = 0;
@@ -12480,6 +12452,7 @@ public class BatteryStatsImpl extends BatteryStats {
final long[] binderThreadCpuTimesUs =
mBinderThreadCpuTimesUs.getCountsLocked(0);
int index = 0;
+ int numCpuClusters = mPowerProfile.getNumCpuClusters();
for (int cluster = 0; cluster < numCpuClusters; cluster++) {
StringBuilder sb = new StringBuilder();
sb.append("cpu").append(cpuIndex).append(": [");
diff --git a/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java b/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java
index 0578b8976037..4f687f186d88 100644
--- a/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java
+++ b/core/java/com/android/internal/os/KernelSingleProcessCpuThreadReader.java
@@ -33,8 +33,7 @@ import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Arrays;
/**
* Iterates over all threads owned by a given process, and return the CPU usage for
@@ -151,7 +150,7 @@ public class KernelSingleProcessCpuThreadReader {
/**
* Get the CPU frequencies that correspond to the times reported in {@link
- * ThreadCpuUsage#usageTimesMillis}
+ * ProcessCpuUsage#processCpuTimesMillis} etc.
*/
public int getCpuFrequencyCount() {
if (mFrequencyCount == 0) {
@@ -163,14 +162,22 @@ public class KernelSingleProcessCpuThreadReader {
/**
* Get the total and per-thread CPU usage of the process with the PID specified in the
* constructor.
+ * @param selectedThreadIds a SORTED array of native Thread IDs whose CPU times should
+ * be aggregated as a group. This is expected to be a subset
+ * of all thread IDs owned by the process.
*/
@Nullable
- public ProcessCpuUsage getProcessCpuUsage() {
+ public ProcessCpuUsage getProcessCpuUsage(int[] selectedThreadIds) {
if (DEBUG) {
Slog.d(TAG, "Reading CPU thread usages with directory " + mProcPath + " process ID "
+ mPid);
}
+ if (!isSorted(selectedThreadIds)) {
+ throw new IllegalArgumentException("selectedThreadIds is not sorted: "
+ + Arrays.toString(selectedThreadIds));
+ }
+
if (!Process.readProcFile(mProcessStatFilePath, PROCESS_FULL_STATS_FORMAT, null,
mProcessFullStatsData, null)) {
Slog.e(TAG, "Failed to read process stat file " + mProcessStatFilePath);
@@ -182,39 +189,43 @@ public class KernelSingleProcessCpuThreadReader {
long processCpuTimeMillis = (utime + stime) * mJiffyMillis;
- final ArrayList<ThreadCpuUsage> threadCpuUsages = new ArrayList<>();
+ int cpuFrequencyCount = getCpuFrequencyCount();
+ ProcessCpuUsage processCpuUsage = new ProcessCpuUsage(cpuFrequencyCount);
try (DirectoryStream<Path> threadPaths = Files.newDirectoryStream(mThreadsDirectoryPath)) {
for (Path threadDirectory : threadPaths) {
- ThreadCpuUsage threadCpuUsage = getThreadCpuUsage(threadDirectory);
- if (threadCpuUsage == null) {
- continue;
- }
- threadCpuUsages.add(threadCpuUsage);
+ readThreadCpuUsage(processCpuUsage, selectedThreadIds, threadDirectory);
}
} catch (IOException | DirectoryIteratorException e) {
// Expected when a process finishes
return null;
}
- // If we found no threads, then the process has exited while we were reading from it
- if (threadCpuUsages.isEmpty()) {
- return null;
+ // Estimate per cluster per frequency CPU time for the entire process
+ // by distributing the total process CPU time proportionately to how much
+ // CPU time its threads took on those clusters/frequencies. This algorithm
+ // works more accurately when when we have equally distributed concurrency.
+ // TODO(b/169279846): obtain actual process CPU times from the kernel
+ long totalCpuTimeAllThreads = 0;
+ for (int i = cpuFrequencyCount - 1; i >= 0; i--) {
+ totalCpuTimeAllThreads += processCpuUsage.threadCpuTimesMillis[i];
}
- if (DEBUG) {
- Slog.d(TAG, "Read CPU usage of " + threadCpuUsages.size() + " threads");
+
+ for (int i = cpuFrequencyCount - 1; i >= 0; i--) {
+ processCpuUsage.processCpuTimesMillis[i] =
+ processCpuTimeMillis * processCpuUsage.threadCpuTimesMillis[i]
+ / totalCpuTimeAllThreads;
}
- return new ProcessCpuUsage(processCpuTimeMillis, threadCpuUsages);
+
+ return processCpuUsage;
}
/**
- * Get a thread's CPU usage
+ * Reads a thread's CPU usage and aggregates the per-cluster per-frequency CPU times.
*
* @param threadDirectory the {@code /proc} directory of the thread
- * @return thread CPU usage. Null if the thread exited and its {@code proc} directory was
- * removed while collecting information
*/
- @Nullable
- private ThreadCpuUsage getThreadCpuUsage(Path threadDirectory) {
+ private void readThreadCpuUsage(ProcessCpuUsage processCpuUsage, int[] selectedThreadIds,
+ Path threadDirectory) {
// Get the thread ID from the directory name
final int threadId;
try {
@@ -222,38 +233,45 @@ public class KernelSingleProcessCpuThreadReader {
threadId = Integer.parseInt(directoryName);
} catch (NumberFormatException e) {
Slog.w(TAG, "Failed to parse thread ID when iterating over /proc/*/task", e);
- return null;
+ return;
}
// Get the CPU statistics from the directory
final Path threadCpuStatPath = threadDirectory.resolve(CPU_STATISTICS_FILENAME);
final long[] cpuUsages = mProcTimeInStateReader.getUsageTimesMillis(threadCpuStatPath);
if (cpuUsages == null) {
- return null;
+ return;
}
- return new ThreadCpuUsage(threadId, cpuUsages);
+ final int cpuFrequencyCount = getCpuFrequencyCount();
+ final boolean isSelectedThread = Arrays.binarySearch(selectedThreadIds, threadId) >= 0;
+ for (int i = cpuFrequencyCount - 1; i >= 0; i--) {
+ processCpuUsage.threadCpuTimesMillis[i] += cpuUsages[i];
+ if (isSelectedThread) {
+ processCpuUsage.selectedThreadCpuTimesMillis[i] += cpuUsages[i];
+ }
+ }
}
- /** CPU usage of a process and all of its threads */
+ /** CPU usage of a process, all of its threads and a selected subset of its threads */
public static class ProcessCpuUsage {
- public final long cpuTimeMillis;
- public final List<ThreadCpuUsage> threadCpuUsages;
-
- ProcessCpuUsage(long cpuTimeMillis, List<ThreadCpuUsage> threadCpuUsages) {
- this.cpuTimeMillis = cpuTimeMillis;
- this.threadCpuUsages = threadCpuUsages;
+ public long[] processCpuTimesMillis;
+ public long[] threadCpuTimesMillis;
+ public long[] selectedThreadCpuTimesMillis;
+
+ public ProcessCpuUsage(int cpuFrequencyCount) {
+ processCpuTimesMillis = new long[cpuFrequencyCount];
+ threadCpuTimesMillis = new long[cpuFrequencyCount];
+ selectedThreadCpuTimesMillis = new long[cpuFrequencyCount];
}
}
- /** CPU usage of a thread */
- public static class ThreadCpuUsage {
- public final int threadId;
- public final long[] usageTimesMillis;
-
- ThreadCpuUsage(int threadId, long[] usageTimesMillis) {
- this.threadId = threadId;
- this.usageTimesMillis = usageTimesMillis;
+ private static boolean isSorted(int[] array) {
+ for (int i = 0; i < array.length - 1; i++) {
+ if (array[i] > array[i + 1]) {
+ return false;
+ }
}
+ return true;
}
}
diff --git a/core/java/com/android/internal/os/SystemServerCpuThreadReader.java b/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
index d9f0dc0ae795..fbbee94feacc 100644
--- a/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
+++ b/core/java/com/android/internal/os/SystemServerCpuThreadReader.java
@@ -24,7 +24,6 @@ import com.android.internal.annotations.VisibleForTesting;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;
-import java.util.List;
/**
* Reads /proc/UID/task/TID/time_in_state files to obtain statistics on CPU usage
@@ -34,10 +33,7 @@ public class SystemServerCpuThreadReader {
private final KernelSingleProcessCpuThreadReader mKernelCpuThreadReader;
private int[] mBinderThreadNativeTids = new int[0]; // Sorted
- private long mProcessCpuTimeUs;
- private long[] mThreadCpuTimesUs;
- private long[] mBinderThreadCpuTimesUs;
- private long mLastProcessCpuTimeUs;
+ private long[] mLastProcessCpuTimeUs;
private long[] mLastThreadCpuTimesUs;
private long[] mLastBinderThreadCpuTimesUs;
@@ -46,14 +42,15 @@ public class SystemServerCpuThreadReader {
*/
public static class SystemServiceCpuThreadTimes {
// The entire process
- public long processCpuTimeUs;
+ public long[] processCpuTimesUs;
// All threads
public long[] threadCpuTimesUs;
// Just the threads handling incoming binder calls
public long[] binderThreadCpuTimesUs;
}
- private SystemServiceCpuThreadTimes mDeltaCpuThreadTimes = new SystemServiceCpuThreadTimes();
+ private final SystemServiceCpuThreadTimes mDeltaCpuThreadTimes =
+ new SystemServiceCpuThreadTimes();
/**
* Creates a configured instance of SystemServerCpuThreadReader.
@@ -83,59 +80,38 @@ public class SystemServerCpuThreadReader {
*/
@Nullable
public SystemServiceCpuThreadTimes readDelta() {
- int numCpuFrequencies = mKernelCpuThreadReader.getCpuFrequencyCount();
- if (mBinderThreadCpuTimesUs == null) {
- mThreadCpuTimesUs = new long[numCpuFrequencies];
- mBinderThreadCpuTimesUs = new long[numCpuFrequencies];
-
+ final int numCpuFrequencies = mKernelCpuThreadReader.getCpuFrequencyCount();
+ if (mLastProcessCpuTimeUs == null) {
+ mLastProcessCpuTimeUs = new long[numCpuFrequencies];
mLastThreadCpuTimesUs = new long[numCpuFrequencies];
mLastBinderThreadCpuTimesUs = new long[numCpuFrequencies];
+ mDeltaCpuThreadTimes.processCpuTimesUs = new long[numCpuFrequencies];
mDeltaCpuThreadTimes.threadCpuTimesUs = new long[numCpuFrequencies];
mDeltaCpuThreadTimes.binderThreadCpuTimesUs = new long[numCpuFrequencies];
}
- mProcessCpuTimeUs = 0;
- Arrays.fill(mThreadCpuTimesUs, 0);
- Arrays.fill(mBinderThreadCpuTimesUs, 0);
-
- KernelSingleProcessCpuThreadReader.ProcessCpuUsage processCpuUsage =
- mKernelCpuThreadReader.getProcessCpuUsage();
+ final KernelSingleProcessCpuThreadReader.ProcessCpuUsage processCpuUsage =
+ mKernelCpuThreadReader.getProcessCpuUsage(mBinderThreadNativeTids);
if (processCpuUsage == null) {
return null;
}
- mProcessCpuTimeUs = processCpuUsage.cpuTimeMillis * 1000;
-
- List<KernelSingleProcessCpuThreadReader.ThreadCpuUsage> threadCpuUsages =
- processCpuUsage.threadCpuUsages;
- int threadCpuUsagesSize = threadCpuUsages.size();
- for (int i = 0; i < threadCpuUsagesSize; i++) {
- KernelSingleProcessCpuThreadReader.ThreadCpuUsage tcu = threadCpuUsages.get(i);
- boolean isBinderThread =
- Arrays.binarySearch(mBinderThreadNativeTids, tcu.threadId) >= 0;
- for (int k = 0; k < numCpuFrequencies; k++) {
- long usageTimeUs = tcu.usageTimesMillis[k] * 1000;
- mThreadCpuTimesUs[k] += usageTimeUs;
- if (isBinderThread) {
- mBinderThreadCpuTimesUs[k] += usageTimeUs;
- }
- }
- }
-
- for (int i = 0; i < mThreadCpuTimesUs.length; i++) {
- mDeltaCpuThreadTimes.processCpuTimeUs =
- Math.max(0, mProcessCpuTimeUs - mLastProcessCpuTimeUs);
+ for (int i = numCpuFrequencies - 1; i >= 0; i--) {
+ long processCpuTimesUs = processCpuUsage.processCpuTimesMillis[i] * 1000;
+ long threadCpuTimesUs = processCpuUsage.threadCpuTimesMillis[i] * 1000;
+ long binderThreadCpuTimesUs = processCpuUsage.selectedThreadCpuTimesMillis[i] * 1000;
+ mDeltaCpuThreadTimes.processCpuTimesUs[i] =
+ Math.max(0, processCpuTimesUs - mLastProcessCpuTimeUs[i]);
mDeltaCpuThreadTimes.threadCpuTimesUs[i] =
- Math.max(0, mThreadCpuTimesUs[i] - mLastThreadCpuTimesUs[i]);
+ Math.max(0, threadCpuTimesUs - mLastThreadCpuTimesUs[i]);
mDeltaCpuThreadTimes.binderThreadCpuTimesUs[i] =
- Math.max(0, mBinderThreadCpuTimesUs[i] - mLastBinderThreadCpuTimesUs[i]);
- mLastThreadCpuTimesUs[i] = mThreadCpuTimesUs[i];
- mLastBinderThreadCpuTimesUs[i] = mBinderThreadCpuTimesUs[i];
+ Math.max(0, binderThreadCpuTimesUs - mLastBinderThreadCpuTimesUs[i]);
+ mLastProcessCpuTimeUs[i] = processCpuTimesUs;
+ mLastThreadCpuTimesUs[i] = threadCpuTimesUs;
+ mLastBinderThreadCpuTimesUs[i] = binderThreadCpuTimesUs;
}
- mLastProcessCpuTimeUs = mProcessCpuTimeUs;
-
return mDeltaCpuThreadTimes;
}
}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 2f8c45770eb5..50eed27976ad 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -1916,8 +1916,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// If we have a session send it the volume command, otherwise
// use the suggested stream.
if (mMediaController != null) {
- getMediaSessionManager().dispatchVolumeKeyEventAsSystemService(
- mMediaController.getSessionToken(), event);
+ getMediaSessionManager().dispatchVolumeKeyEventToSessionAsSystemService(event,
+ mMediaController.getSessionToken());
} else {
getMediaSessionManager().dispatchVolumeKeyEventAsSystemService(event,
mVolumeControlStreamType);
@@ -1938,8 +1938,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
if (mMediaController != null) {
- if (getMediaSessionManager().dispatchMediaKeyEventAsSystemService(
- mMediaController.getSessionToken(), event)) {
+ if (getMediaSessionManager().dispatchMediaKeyEventToSessionAsSystemService(
+ event, mMediaController.getSessionToken())) {
return true;
}
}
@@ -2010,8 +2010,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// If we have a session send it the volume command, otherwise
// use the suggested stream.
if (mMediaController != null) {
- getMediaSessionManager().dispatchVolumeKeyEventAsSystemService(
- mMediaController.getSessionToken(), event);
+ getMediaSessionManager().dispatchVolumeKeyEventToSessionAsSystemService(event,
+ mMediaController.getSessionToken());
} else {
getMediaSessionManager().dispatchVolumeKeyEventAsSystemService(
event, mVolumeControlStreamType);
@@ -2041,8 +2041,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
if (mMediaController != null) {
- if (getMediaSessionManager().dispatchMediaKeyEventAsSystemService(
- mMediaController.getSessionToken(), event)) {
+ if (getMediaSessionManager().dispatchMediaKeyEventToSessionAsSystemService(
+ event, mMediaController.getSessionToken())) {
return true;
}
}
diff --git a/core/java/com/android/internal/util/LocationPermissionChecker.java b/core/java/com/android/internal/util/LocationPermissionChecker.java
index cd8fc350362d..59c0c0009640 100644
--- a/core/java/com/android/internal/util/LocationPermissionChecker.java
+++ b/core/java/com/android/internal/util/LocationPermissionChecker.java
@@ -218,7 +218,7 @@ public class LocationPermissionChecker {
}
private boolean isTargetSdkLessThan(String packageName, int versionCode, int callingUid) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
if (mContext.getPackageManager().getApplicationInfoAsUser(
packageName, 0,
diff --git a/core/proto/android/telephony/enums.proto b/core/proto/android/telephony/enums.proto
index b56bd2bae29a..d2c0ed4e4736 100644
--- a/core/proto/android/telephony/enums.proto
+++ b/core/proto/android/telephony/enums.proto
@@ -199,10 +199,24 @@ enum SmsTypeEnum {
SMS_TYPE_WAP_PUSH = 4;
}
-// SMS errors
+// Incoming SMS errors
enum SmsIncomingErrorEnum {
SMS_SUCCESS = 0;
SMS_ERROR_GENERIC = 1;
SMS_ERROR_NO_MEMORY = 2;
SMS_ERROR_NOT_SUPPORTED = 3;
}
+
+// Outgoing SMS results
+enum SmsSendResultEnum {
+ // Unknown error
+ SMS_SEND_RESULT_UNKNOWN = 0;
+ // Success
+ SMS_SEND_RESULT_SUCCESS = 1;
+ // Permanent error
+ SMS_SEND_RESULT_ERROR = 2;
+ // Temporary error, retry
+ SMS_SEND_RESULT_ERROR_RETRY = 3;
+ // Error over IMS, retry on CS
+ SMS_SEND_RESULT_ERROR_FALLBACK = 4;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 761bddfac148..ed13069909d4 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -149,7 +149,7 @@
<protected-broadcast android:name="android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.device.action.UUID" />
<protected-broadcast android:name="android.bluetooth.device.action.MAS_INSTANCE" />
- <protected-broadcast android:name="android.bluetooth.action.ALIAS_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.device.action.ALIAS_CHANGED" />
<protected-broadcast android:name="android.bluetooth.device.action.FOUND" />
<protected-broadcast android:name="android.bluetooth.device.action.CLASS_CHANGED" />
<protected-broadcast android:name="android.bluetooth.device.action.ACL_CONNECTED" />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index e6b7c68e1c1d..bd81519e93b3 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"verander jou klankinstellings"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Laat die program toe om globale klankinstellings soos volume en watter luidspreker vir uitvoer gebruik word, te verander."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"neem klank op"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Hierdie die program kan oudio met die mikrofoon opneem terwyl die program gebruik word."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"neem oudio op die agtergrond op"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Hierdie program kan enige tyd oudio met die mikrofoon opneem."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"stuur bevele na die SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Laat die program toe om bevele na die SIM te stuur. Dit is baie gevaarlik."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"herken fisieke aktiwiteit"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Hierdie program kan jou fisieke aktiwiteit herken."</string>
<string name="permlab_camera" msgid="6320282492904119413">"neem foto\'s en video\'s"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Hierdie program kan met die kamera foto\'s neem en video\'s opneem terwyl die program gebruik word."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"neem foto\'s en video\'s op die agtergrond"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Hierdie program kan enige tyd met die kamera foto\'s neem en video\'s opneem."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Gee \'n program of diens toegang tot stelselkameras om foto\'s en video\'s te neem"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Hierdie bevoorregte of stelselprogram kan enige tyd met \'n stelselkamera foto\'s neem en video\'s opneem. Vereis dat die program ook die android.permission.CAMERA-toestemming het"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Laat \'n program of diens toe om terugbeloproepe te ontvang oor kameratoestelle wat oopgemaak of toegemaak word."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 9750a0c94f0c..0bbe23262c92 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"የድምፅ ቅንብሮችን ለውጥ"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"መተግበሪያው አንደ የድምጽ መጠን እና ለውጽአት የትኛውን የድምጽ ማጉያ ጥቅም ላይ እንደዋለ የመሳሰሉ ሁለንተናዊ የድምጽ ቅንብሮችን እንዲያስተካክል ይፈቅድለታል።"</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ኦዲዮ ይቅዱ"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"ይህ መተግበሪያ መተግበሪያው ስራ ላይ ሳለ ማይክሮፎኑን በመጠቀም ኦዲዮን መቅዳት ይችላል።"</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"በበስተጀርባ ኦዲዮን ይቅዱ"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"ይህ መተግበሪያ በማናቸውም ጊዜ ማይክራፎኑን በመጠቀም ኦዲዮን መቅዳት ይችላል።"</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"ወደ ሲሙ ትዕዛዞችን መላክ"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"መተግበሪያው ትዕዛዞችን ወደ ሲሙ እንዲልክ ያስችለዋል። ይሄ በጣማ አደገኛ ነው።"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"አካላዊ እንቅስቃሴን ለይቶ ማወቅ"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"ይህ መተግበሪያ አካላዊ እንቅስቃሴዎን ለይቶ ሊያውቅ ይችላል።"</string>
<string name="permlab_camera" msgid="6320282492904119413">"ፎቶዎች እና ቪዲዮዎች ያንሱ"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"ይህ መተግበሪያ መተግበሪያው ስራ ላይ ሳለ ካሜራውን በመጠቀም ሥዕሎችን ማንሳት እና ቪዲዮዎችን መቅዳት ይችላል።"</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"በበስተጀርባ ስዕሎችን እና ቪዲዮዎችን ያንሱ"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"ይህ መተግበሪያ በማናቸውም ጊዜ ካሜራውን በመጠቀም ፎቶ ሊያነሳ እና ቪዲዮዎችን ሊቀርጽ ይችላል።"</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"ሥዕሎችን ለማንሣት እና ቪዲዮዎችን ለመቅረጽ እንዲችሉ ወደ ሥርዓት ካሜራዎች ለመተግበሪያ ወይም ለአገልግሎት መዳረሻ ይፍቀዱ"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ይህ ልዩ ፈቃድ ያለው የሥርዓት መተግበሪያ በማንኛውም ጊዜ የሥርዓት ካሜራን በመጠቀም ሥዕሎችን ማንሣት እና ቪዲዮ መቅረጽ ይችላል። የandroid.permission.CAMERA ፈቃዱ በመተግበሪያውም ጭምር እንዲያዝ ያስፈልገዋል።"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"አንድ መተግበሪያ ወይም አገልግሎት እየተከፈቱ ወይም እየተዘጉ ስላሉ የካሜራ መሣሪያዎች መልሶ ጥሪዎችን እንዲቀበል ይፍቀዱ።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index e672de31f13b..8868fb67ccc8 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -444,23 +444,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"تغيير إعداداتك الصوتية"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"للسماح للتطبيق بتعديل إعدادات الصوت العامة مثل مستوى الصوت وأي السماعات يتم استخدامها للاستماع."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"تسجيل الصوت"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"يمكن لهذا التطبيق تسجيل الصوت باستخدام الميكروفون عندما يكون التطبيق قيد الاستخدام."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"تسجيل الصوت في الخلفية"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"يمكن لهذا التطبيق تسجيل الصوت باستخدام الميكروفون في أي وقت."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"‏إرسال أوامر إلى شريحة SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"‏السماح للتطبيق بإرسال أوامر إلى شريحة SIM. وهذا أمر بالغ الخطورة."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"التعرّف على النشاط البدني"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"يمكن لهذا التطبيق التعرّف على نشاطك البدني."</string>
<string name="permlab_camera" msgid="6320282492904119413">"التقاط صور وفيديوهات"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"يمكن لهذا التطبيق التقاط صور وتسجيل فيديوهات باستخدام الكاميرا عندما يكون التطبيق قيد الاستخدام."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"التقاط صور وتصوير فيديوهات في الخلفية"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"يمكن لهذا التطبيق التقاط صور وتسجيل فيديوهات باستخدام الكاميرا في أي وقت."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"السماح لتطبيق أو خدمة بالوصول إلى كاميرات النظام لالتقاط صور وتسجيل فيديوهات"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"‏إنّ تطبيق النظام هذا، أو التطبيق المزوّد بأذونات مميّزة، يمكنه التقاط صور وتسجيل فيديوهات باستخدام كاميرا النظام في أي وقت. ويجب أن يحصل التطبيق أيضًا على الإذن android.permission.CAMERA."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"يسمح الإذن لتطبيق أو خدمة بتلقّي استدعاءات عما إذا كانت أجهزة الكاميرات مفتوحة أو مغلقة."</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index b3e1680f2a40..619666b9bf0d 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"আপোনাৰ অডিঅ\' ছেটিংসমূহ সলনি কৰক"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"এপটোক ভলিউমৰ দৰে গ্ল\'বেল অডিঅ\' ছেটিংসমূহ যাৰ স্পীকাৰক আউটপুটৰ বাবে ব্যৱহাৰ হয় তাক সলনি কৰিবলৈ অনুমতি দিয়ে৷"</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"অডিঅ\' ৰেকর্ড কৰক"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"এই এপ্‌টোৱে ইয়াক ব্যৱহাৰ কৰি থাকোঁতে মাইক্ৰ’ফ’ন ব্যৱহাৰ কৰি অডিঅ’ ৰেকর্ড কৰিব পাৰে।"</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"নেপথ্যত অডিঅ’ ৰেকৰ্ড কৰক"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"এই এপ্‌টোৱে যিকোনো সময়তে মাইক্ৰ’ফ’ন ব্যৱহাৰ কৰি অডিঅ’ ৰেকৰ্ড কৰিব পাৰে।"</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"ছিমলৈ নিৰ্দেশ পঠিয়াব পাৰে"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"ছিমলৈ নিৰ্দেশসমূহ প্ৰেৰণ কৰিবলৈ এপক অনুমতি দিয়ে। ই অতি ক্ষতিকাৰক।"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"শাৰীৰিক কাৰ্যকলাপ চিনাক্ত কৰক"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"এই এপটোৱে আপোনাৰ শাৰীৰিক কাৰ্যকলাপ চিনাক্ত কৰিব পাৰে।"</string>
<string name="permlab_camera" msgid="6320282492904119413">"ফট\' তোলা আৰু ভিডিঅ\' ৰেকৰ্ড কৰা"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"এই এপ্‌টোৱে ইয়াক ব্যৱহাৰ কৰি থাকোঁতে কেমেৰা ব্যৱহাৰ কৰি ফট’ তুলিব আৰু ভিডিঅ’ ৰেকর্ড কৰিব পাৰে।"</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"নেপথ্যত ফট’ তোলক আৰু ভিডিঅ’ ৰেকৰ্ড কৰক"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"এই এপ্‌টোৱে যিকোনো সময়তে কেমেৰা ব্যৱহাৰ কৰি ফট’ তুলিব আৰু ভিডিঅ’ ৰেকর্ড কৰিব পাৰে।"</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"ফট’ উঠাবলৈ আৰু ভিডিঅ’ ৰেকৰ্ড কৰিবলৈ এটা এপ্লিকেশ্বন অথবা সেৱাক ছিষ্টেম কেমেৰাসমূহ এক্সেছ কৰিবলৈ দিয়ক"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"এই বিশেষাধিকাৰ প্ৰাপ্ত অথবা ছিষ্টেম এপ্‌টোৱে এটা ছিষ্টেম কেমেৰা ব্যৱহাৰ কৰি যিকোনো সময়তে ফট’ উঠাব পাৰে আৰু ভিডিঅ’ ৰেকৰ্ড কৰিব পাৰে। লগতে এপ্‌টোৰো android.permission.CAMERAৰ অনুমতি থকাটো প্ৰয়োজনীয়"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"কোনো এপ্লিকেশ্বন অথবা সেৱাক কেমেৰা ডিভাইচসমূহ খোলা অথবা বন্ধ কৰাৰ বিষয়ে কলবেকসমূহ গ্ৰহণ কৰিবলৈ অনুমতি দিয়ক।"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index de399df09e61..ed708cce9856 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"audio ayarlarınızı dəyişir"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Tətbiqə səs və hansı spikerin çıxış üçün istifadə olunduğu kimi qlobal səs ayarlarını dəyişdirməyə imkan verir."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"səs yaz"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Bu tətbiq istifadə edilən zaman mikrofondan istifadə edərək audio yaza bilər."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"arxa fonda audio yazmaq"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Bu tətbiq istənilən zaman mikrofondan istifadə edərək audio yaza bilər."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"əmrləri SIM\'ə göndərin"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Tətbiqə SIM-ə əmrlər göndərməyə imkan verir. Bu, çox təhlükəlidir."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"fiziki fəaliyyəti tanıyın"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Bu tətbiq fiziki fəaliyyətinizi tanıya bilər."</string>
<string name="permlab_camera" msgid="6320282492904119413">"şəkil və video çəkmək"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Bu tətbiq istifadə edilən zaman kameradan istifadə edərək şəkil çəkə və video yaza bilər."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"arxa fonda şəkillər və videolar çəkmək"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Bu tətbiq istənilən zaman kameradan istifadə edərək şəkil çəkə və video yaza bilər."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Şəkil və video çəkmək üçün tətbiq və ya xidmətlərin sistem kameralarına girişinə icazə verin"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Bu icazəli və ya sistem tətbiqi istənilən vaxt sistem kamerasından istifadə edərək şəkil və videolar çəkə bilər. android.permission.CAMERA icazəsinin də tətbiq tərəfindən saxlanılmasını tələb edir"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Tətbiqə və ya xidmətə kamera cihazlarının açılması və ya bağlanması haqqında geri zənglər qəbul etməyə icazə verin."</string>
@@ -714,7 +708,7 @@
<string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Bəzi ekran kilidi funksiyalarını deaktiv edin"</string>
<string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Bəzi ekran funksiyaları istifadəsinin qarşısını alın."</string>
<string-array name="phoneTypes">
- <item msgid="8996339953292723951">"Əsas səhifə"</item>
+ <item msgid="8996339953292723951">"Ev"</item>
<item msgid="7740243458912727194">"Mobil"</item>
<item msgid="8526146065496663766">"İş"</item>
<item msgid="8150904584178569699">"İş Faksı"</item>
@@ -724,19 +718,19 @@
<item msgid="6216981255272016212">"Şəxsi"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="7786349763648997741">"Ana səhifə"</item>
+ <item msgid="7786349763648997741">"Ev"</item>
<item msgid="435564470865989199">"İş"</item>
<item msgid="4199433197875490373">"Digər"</item>
<item msgid="3233938986670468328">"Fərdi"</item>
</string-array>
<string-array name="postalAddressTypes">
- <item msgid="3861463339764243038">"Əsas səhifə"</item>
+ <item msgid="3861463339764243038">"Ev"</item>
<item msgid="5472578890164979109">"İş"</item>
<item msgid="5718921296646594739">"Digər"</item>
<item msgid="5523122236731783179">"Düzənləyin"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="588088543406993772">"Əsas səhifə"</item>
+ <item msgid="588088543406993772">"Ev"</item>
<item msgid="5503060422020476757">"İş"</item>
<item msgid="2530391194653760297">"Digər"</item>
<item msgid="7640927178025203330">"Fərdi"</item>
@@ -782,16 +776,16 @@
<string name="eventTypeAnniversary" msgid="4684702412407916888">"İldönümü"</string>
<string name="eventTypeOther" msgid="530671238533887997">"Digər"</string>
<string name="emailTypeCustom" msgid="1809435350482181786">"Fərdi"</string>
- <string name="emailTypeHome" msgid="1597116303154775999">"Əsas səhifə"</string>
+ <string name="emailTypeHome" msgid="1597116303154775999">"Şəxsi"</string>
<string name="emailTypeWork" msgid="2020095414401882111">"İş"</string>
<string name="emailTypeOther" msgid="5131130857030897465">"Digər"</string>
<string name="emailTypeMobile" msgid="787155077375364230">"Mobil"</string>
<string name="postalTypeCustom" msgid="5645590470242939129">"Fərdi"</string>
- <string name="postalTypeHome" msgid="7562272480949727912">"Əsas səhifə"</string>
+ <string name="postalTypeHome" msgid="7562272480949727912">"Ev"</string>
<string name="postalTypeWork" msgid="8553425424652012826">"İş"</string>
<string name="postalTypeOther" msgid="7094245413678857420">"Digər"</string>
<string name="imTypeCustom" msgid="5653384545085765570">"Fərdi"</string>
- <string name="imTypeHome" msgid="6996507981044278216">"Ana səhifə"</string>
+ <string name="imTypeHome" msgid="6996507981044278216">"Ev"</string>
<string name="imTypeWork" msgid="2099668940169903123">"İş"</string>
<string name="imTypeOther" msgid="8068447383276219810">"Digər"</string>
<string name="imProtocolCustom" msgid="4437878287653764692">"Şəxsi"</string>
@@ -823,7 +817,7 @@
<string name="relationTypeSister" msgid="3721676005094140671">"Bacı"</string>
<string name="relationTypeSpouse" msgid="6916682664436031703">"Həyat yoldaşı"</string>
<string name="sipAddressTypeCustom" msgid="6283889809842649336">"Fərdi"</string>
- <string name="sipAddressTypeHome" msgid="5918441930656878367">"Əsas səhifə"</string>
+ <string name="sipAddressTypeHome" msgid="5918441930656878367">"Ev"</string>
<string name="sipAddressTypeWork" msgid="7873967986701216770">"İş"</string>
<string name="sipAddressTypeOther" msgid="6317012577345187275">"Digər"</string>
<string name="quick_contacts_not_available" msgid="1262709196045052223">"Bu kontakta baxmaq üçün heç bir tətbiq tapılmadı."</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 928ade146c31..0b215456b150 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -435,23 +435,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"promena audio podešavanja"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Dozvoljava aplikaciji da menja globalna audio podešavanja kao što su jačina zvuka i izbor zvučnika koji se koristi kao izlaz."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"snimanje audio zapisa"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Ova aplikacija može da snima zvuk pomoću mikrofona dok se aplikacija koristi."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"da snima zvuk u pozadini"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Ova aplikacija može da snima zvuk pomoću mikrofona u bilo kom trenutku."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"slanje komandi na SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Omogućava aplikaciji da šalje komande SIM kartici. To je veoma opasno."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"prepoznavanje fizičkih aktivnosti"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Ova aplikacija može da prepozna fizičke aktivnosti."</string>
<string name="permlab_camera" msgid="6320282492904119413">"snimanje fotografija i video snimaka"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Ova aplikacija može da snima slike i video snimke pomoću kamere dok se aplikacija koristi."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"da snima slike i video snimke u pozadini"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Ova aplikacija može da snima fotografije i video snimke pomoću kamere u bilo kom trenutku."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Dozvolite nekoj aplikaciji ili usluzi da pristupa kamerama sistema da bi snimala slike i video snimke"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ova privilegovana sistemska aplikacija može da snima slike i video snimke pomoću kamere sistema u bilo kom trenutku. Aplikacija treba da ima i dozvolu android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Dozvolite aplikaciji ili usluzi da dobija povratne pozive o otvaranju ili zatvaranju uređaja sa kamerom."</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index e31c4b73de67..6a0ad98d759d 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -98,9 +98,9 @@
<string name="notification_channel_wfc" msgid="9048240466765169038">"Wi-Fi-тэлефанія"</string>
<string name="notification_channel_sim" msgid="5098802350325677490">"Статус SIM-карты"</string>
<string name="notification_channel_sim_high_prio" msgid="642361929452850928">"Стан SIM-карты з высокім прыярытэтам"</string>
- <string name="peerTtyModeFull" msgid="337553730440832160">"Аднарангавая прылада запытала рэжым TTY FULL"</string>
- <string name="peerTtyModeHco" msgid="5626377160840915617">"Аднарангавая прылада запытала рэжым TTY НСО"</string>
- <string name="peerTtyModeVco" msgid="572208600818270944">"Аднарангавая прылада запытала рэжым TTY VCO"</string>
+ <string name="peerTtyModeFull" msgid="337553730440832160">"Аднарангавая прылада запытала рэжым поўнафункцыянальнага TTY"</string>
+ <string name="peerTtyModeHco" msgid="5626377160840915617">"Аднарангавая прылада запытала рэжым TTY з магчымасцю чуць суразмоўніка"</string>
+ <string name="peerTtyModeVco" msgid="572208600818270944">"Аднарангавая прылада запытала рэжым TTY з магчымасцю чуць суразмоўніка"</string>
<string name="peerTtyModeOff" msgid="2420380956369226583">"Аднарангавая прылада запытала рэжым TTY OFF"</string>
<string name="serviceClassVoice" msgid="2065556932043454987">"Голас"</string>
<string name="serviceClassData" msgid="4148080018967300248">"Дадзеныя"</string>
@@ -438,23 +438,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"змяняць налады аудыё"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Дазваляе прыкладанням змяняць глабальныя налады гуку, такія як моц і тое, што дынамік выкарыстоўваецца для выхаду."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"запіс аўдыя"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Гэта праграма падчас яе выкарыстання можа запісваць аўдыя з дапамогай мікрафона."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"запісваць аўдыя ў фонавым рэжыме"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Гэта праграма можа ў любы час запісваць аўдыя з дапамогай мікрафона."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"адпраўляць каманды на SIM-карту"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Дазваляе праграме адпраўляць каманды SIM-карце. Гэта вельмі небяспечна."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"распазнаваць фізічную актыўнасць"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Гэта праграма можа распазнаваць фізічную актыўнасць."</string>
<string name="permlab_camera" msgid="6320282492904119413">"рабіць фатаграфіі і відэа"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Гэта праграма падчас яе выкарыстання можа рабіць фота і запісваць відэа з дапамогай камеры."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"знімаць фота і відэа ў фонавым рэжыме"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Гэта праграма можа ў любы час рабіць фота і запісваць відэа з дапамогай камеры."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Дазволіць праграме або сэрвісу атрымліваць доступ да сістэмных камер, каб здымаць фота і запісваць відэа"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Гэта прыярытэтная ці сістэмная праграма можа здымаць фота і запісваць відэа з дапамогай сістэмнай камеры. Праграме таксама патрэбны дазвол android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Дазволіць праграме ці сэрвісу атрымліваць зваротныя выклікі наконт адкрыцця ці закрыцця прылад камеры."</string>
@@ -1552,7 +1546,7 @@
<string name="activitychooserview_choose_application_error" msgid="6937782107559241734">"Не атрымалася запусціць <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="shareactionprovider_share_with" msgid="2753089758467748982">"Апублікаваць з дапамогай"</string>
<string name="shareactionprovider_share_with_application" msgid="4902832247173666973">"Адправiць з дапамогай прыкладання <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
- <string name="content_description_sliding_handle" msgid="982510275422590757">"Ручка для перасоўвання. Націсніце і ўтрымлівайце."</string>
+ <string name="content_description_sliding_handle" msgid="982510275422590757">"Маркер для перасоўвання. Дакраніцеся і ўтрымлівайце."</string>
<string name="description_target_unlock_tablet" msgid="7431571180065859551">"Прагартайце, каб разблакаваць."</string>
<string name="action_bar_home_description" msgid="1501655419158631974">"Перайсці да пачатковай старонкі"</string>
<string name="action_bar_up_description" msgid="6611579697195026932">"Перайсці ўверх"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 5938fd999f90..cdd0ec04df0f 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"промяна на настройките ви за звука"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Разрешава на приложението да променя глобалните настройки за звука, като например силата и това, кой високоговорител се използва за изход."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"записва звук"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Когато се използва, това приложение може да записва аудио посредством микрофона."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"записва аудио на заден план"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Това приложение може по всяко време да записва аудио посредством микрофона."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"изпращане на команди до SIM картата"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Разрешава на приложението да изпраща команди до SIM картата. Това е много опасно."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"разпознаване на физическата активност"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Това приложение може да разпознава физическата ви активност."</string>
<string name="permlab_camera" msgid="6320282492904119413">"правене на снимки и видеоклипове"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Когато се използва, това приложение може да прави снимки и да записва видеоклипове посредством камерата."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"прави снимки и видеоклипове на заден план"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Това приложение може по всяко време да прави снимки и да записва видеоклипове посредством камерата."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Разрешаване на достъп на приложение или услуга до системните камери с цел правене на снимки и видеоклипове"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Това привилегировано или системно приложение може по всяко време да прави снимки и да записва видео посредством системна камера. Необходимо е също на приложението да бъде дадено разрешението android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Разрешаване на приложение или услуга да получават обратни повиквания за отварянето или затварянето на снимачни устройства."</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 3567d794a590..779fd3ef67e1 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"আপনার অডিও সেটিংস পরিবর্তন করে"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"ভলিউম এবং যেখানে স্পিকার আউটপুট হিসাবে ব্যবহৃত হয় সেই সব ক্ষেত্রে গ্লোবাল অডিও সেটিংসের সংশোধন করতে অ্যাপ্লিকেশনটিকে মঞ্জুর করে৷"</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"অডিও রেকর্ড"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"এই অ্যাপটি যখন ব্যবহার করা হচ্ছে, তখন মাইক্রোফোন ব্যবহার করে অডিও রেকর্ড করতে পারবে।"</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ব্যাকগ্রাউন্ডে অডিও রেকর্ড করতে পারবে"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"এই অ্যাপটি মাইক্রোফোন ব্যবহার করে যেকোনও সময় অডিও রেকর্ড করতে পারবে।"</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"সিম এ আদেশগুলি পাঠান"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"অ্যাপ্লিকেশানটিকে সিম কার্ডে কমান্ডগুলি পাঠানোর অনুমতি দেয়৷ এটি খুবই বিপজ্জনক৷"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"শারীরিক অ্যাক্টিভিটি শনাক্ত করুন"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"এই অ্যাপ আপনার শারীরিক অ্যাক্টিভিটি শনাক্ত করতে পারবে।"</string>
<string name="permlab_camera" msgid="6320282492904119413">"ছবি এবং ভিডিও তোলে"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"এই অ্যাপটি যখন ব্যবহার করা হচ্ছে, তখন ক্যামেরা ব্যবহার করে ছবি তুলতে বা ভিডিও রেকর্ড করতে পারবে।"</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"ব্যাকগ্রাউন্ডে ছবি এবং ভিডিও তুলতে পারবে"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"এই অ্যাপটি যেকোনও সময় ক্যামেরা ব্যবহার করে ছবি তুলতে বা ভিডিও রেকর্ড করতে পারবে।"</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"সিস্টেম ক্যামেরা ব্যবহার করে ফটো এবং ভিডিও নেওয়ার জন্য অ্যাপ্লিকেশন বা পরিষেবা অ্যাক্সেসের অনুমতি দিন"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"এই প্রিভিলেজ বা সিস্টেম অ্যাপ যেকোনও সময় সিস্টেম ক্যামেরা ব্যবহার করে ছবি তুলতে ও ভিডিও রেকর্ড করতে পারে। এই অ্যাপকে android.permission.CAMERA অনুমতি দিতে হবে"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"কোনও অ্যাপ্লিকেশন বা পরিষেবাকে ক্যামেরা ডিভাইসগুলি খোলা বা বন্ধ হওয়া সম্পর্কে কলব্যাকগুলি গ্রহণ করার অনুমতি দিন।"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 2c05aa5bc9b4..fab6c912d3fe 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -435,23 +435,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"izmjene postavki zvuka"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Omogućava aplikaciji izmjenu općih postavki zvuka, kao što su jačina zvuka i izbor izlaznog zvučnika."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"snimanje audiozapisa"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Za vrijeme korištenja, ova aplikacija može snimati zvuk koristeći mikrofon."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"snimanje zvuka u pozadini"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Ova aplikacija može u svakom trenutku snimati zvuk koristeći mikrofon."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"slanje komandi SIM kartici"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Omogućava aplikaciji slanje naredbi na SIM. Ovo je vrlo opasno."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"prepoznavanje fizičke aktivnosti"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Ova aplikacija može prepoznati vašu fizičku aktivnost."</string>
<string name="permlab_camera" msgid="6320282492904119413">"snimanje slika i videozapisa"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Za vrijeme korištenja, ova aplikacija može snimati slike i videozapise koristeći kameru."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"snimanje slika i videozapisa u pozadini"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Ova aplikacija može snimati slike i videozapise koristeći kameru bilo kada."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Dopustite aplikaciji ili usluzi da pristupa kamerama sistema radi snimanja fotografija i videozapisa"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ova povlaštena ili sistemska aplikacija u svakom trenutku može snimati fotografije i videozapise pomoću kamere sistema. Aplikacija također mora imati odobrenje android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Dozvoliti aplikaciji ili usluzi da prima povratne pozive o otvaranju ili zatvaranju kamera."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 0a25ba02b602..96c6b6a85736 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"canviar la configuració d\'àudio"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permet que l\'aplicació modifiqui la configuració d\'àudio general, com ara el volum i l\'altaveu de sortida que es fa servir."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"gravar àudio"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Aquesta aplicació pot gravar àudio amb el micròfon mentre s\'està utilitzant."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"gravar àudio en segon pla"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Aquesta aplicació pot gravar àudio amb el micròfon en qualsevol moment."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"enviar ordres a la SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Permet que l\'aplicació enviï ordres a la SIM. Això és molt perillós."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"reconèixer l\'activitat física"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Aquesta aplicació pot reconèixer la teva activitat física."</string>
<string name="permlab_camera" msgid="6320282492904119413">"fer fotos i vídeos"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Aquesta aplicació pot fer fotos i gravar vídeos amb la càmera mentre s\'està utilitzant."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"fer fotos i gravar vídeos en segon pla"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Aquesta aplicació pot fer fotos i gravar vídeos amb la càmera en qualsevol moment."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Permet que una aplicació o un servei tinguin accés a les càmeres del sistema per fer fotos i vídeos"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Aquesta aplicació del sistema amb privilegis pot fer fotos i gravar vídeos amb una càmera del sistema en qualsevol moment. L\'aplicació també ha de tenir el permís android.permission.CAMERA per accedir-hi."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permet que una aplicació o un servei pugui rebre crides de retorn sobre els dispositius de càmera que s\'obren o es tanquen."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 8321f2295026..9a5f069c8afb 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -438,23 +438,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"změna nastavení zvuku"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Umožňuje aplikaci změnit globální nastavení zvuku, například hlasitost či reproduktor pro výstup zvuku."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"nahrávání zvuku"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Tato aplikace může pomocí mikrofonu během svého používání zaznamenat zvuk."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"zaznamenávat zvuk na pozadí"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Tato aplikace může pomocí mikrofonu kdykoli zaznamenat zvuk."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"odesílání příkazů do SIM karty"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Umožňuje aplikaci odesílat příkazy na kartu SIM. Toto oprávnění je velmi nebezpečné."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"rozpoznávání fyzické aktivity"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Tyto aplikace dokážou rozpoznat vaši fyzickou aktivitu."</string>
<string name="permlab_camera" msgid="6320282492904119413">"pořizování fotografií a videí"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Tato aplikace může pomocí fotoaparátu během svého používání pořídit snímek nebo nahrát video."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"pořizovat snímky a nahrávat videa na pozadí"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Tato aplikace může pomocí fotoaparátu kdykoli pořídit snímek nebo nahrát video."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Povolte aplikaci nebo službě k systémovým fotoaparátům za účelem pořizování fotek a videí"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Tato privilegovaná nebo systémová aplikace může pomocí fotoaparátu kdykoli pořídit snímek nebo nahrát video. Aplikace musí zároveň mít oprávnění android.permission.CAMERA."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Povolte aplikaci nebo službě přijímat zpětná volání o otevření nebo zavření zařízení s fotoaparátem."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index d85db8fa82ca..480e87cfff2a 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"skifte dine lydindstillinger"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Tillader, at appen kan ændre globale lydindstillinger, som f.eks. lydstyrke og hvilken højttaler der bruges til output."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"optage lyd"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Denne app kan optage lyd med mikrofonen, mens appen er i brug."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"optag lyd i baggrunden"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Denne app kan optage lyd med mikrofonen når som helst."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"send kommandoer til SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Tillader, at appen sender kommandoer til SIM-kortet. Dette er meget farligt."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"genkend fysisk aktivitet"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Denne app kan genkende din fysiske aktivitet."</string>
<string name="permlab_camera" msgid="6320282492904119413">"tage billeder og optage video"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Denne app kan tage billeder og optage video med kameraet, mens appen er i brug."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"tag billeder, og optag video i baggrunden"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Med denne app kan du tage billeder og optage video med kameraet når som helst."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Giv en app eller tjeneste adgang til systemkameraer for at tage billeder og optage video"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Denne privilegerede app eller systemapp kan til enhver tid tage billeder og optage video med et systemkamera. Appen skal også have tilladelsen android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Tillad, at en app eller tjeneste modtager tilbagekald om kameraenheder, der åbnes eller lukkes."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index e4fabbcc548d..ff8e6ad43252 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"Audio-Einstellungen ändern"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Ermöglicht der App, globale Audio-Einstellungen zu ändern, etwa die Lautstärke und den Lautsprecher für die Ausgabe."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"Audio aufnehmen"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Diese App darf mit dem Mikrofon Audioaufnahmen machen, solange sie verwendet wird."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"Audioaufnahmen im Hintergrund machen"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Diese App darf mit dem Mikrofon jederzeit Audioaufnahmen machen."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"Befehle an die SIM senden"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Ermöglicht der App das Senden von Befehlen an die SIM-Karte. Dies ist äußerst risikoreich."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"Körperliche Aktivitäten erkennen"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Diese App kann deine körperliche Aktivität erkennen."</string>
<string name="permlab_camera" msgid="6320282492904119413">"Bilder und Videos aufnehmen"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Diese App darf mit der Kamera Bilder und Videos aufnehmen, solange die App verwendet wird."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"Bilder und Videos im Hintergrund aufnehmen"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Diese App darf mit der Kamera jederzeit Bilder und Videos aufnehmen."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Einer App oder einem Dienst Zugriff auf Systemkameras erlauben, um Fotos und Videos aufnehmen zu können"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Diese privilegierte App oder System-App kann jederzeit mit einer Systemkamera Bilder und Videos aufnehmen. Die App benötigt auch die Berechtigung \"android.permission.CAMERA\"."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Einer App oder einem Dienst den Empfang von Callbacks erlauben, wenn eine Kamera geöffnet oder geschlossen wird."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index d9badc6cf257..6f03f80e04cc 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"αλλάζει τις ρυθμίσεις ήχου"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Επιτρέπει στην εφαρμογή την τροποποίηση καθολικών ρυθμίσεων ήχου, όπως η ένταση και ποιο ηχείο χρησιμοποιείται για έξοδο."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"εγγράφει ήχο"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Αυτή η εφαρμογή μπορεί να εγγράφει ήχο μέσω του μικροφώνου, όταν τη χρησιμοποιείτε."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"εγγραφή ήχου στο παρασκήνιο"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Αυτή η εφαρμογή μπορεί να εγγράφει ήχο μέσω του μικροφώνου, ανά πάσα στιγμή."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"στέλνει εντολές στην κάρτα SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Επιτρέπει στην εφαρμογή την αποστολή εντολών στην κάρτα SIM. Αυτό είναι εξαιρετικά επικίνδυνο."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"αναγνώριση σωματικής δραστηριότητας"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Αυτή η εφαρμογή μπορεί να αναγνωρίσει τη σωματική σας δραστηριότητα."</string>
<string name="permlab_camera" msgid="6320282492904119413">"κάνει λήψη φωτογραφιών και βίντεο"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Αυτή η εφαρμογή μπορεί να τραβάει φωτογραφίες και να εγγράφει βίντεο μέσω της κάμερας, όταν τη χρησιμοποιείτε."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"λήψη φωτογραφιών και βίντεο στο παρασκήνιο"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Αυτή η εφαρμογή μπορεί να τραβάει φωτογραφίες και να εγγράφει βίντεο μέσω της κάμερας, ανά πάσα στιγμή."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Παραχωρήστε σε μια εφαρμογή ή υπηρεσία πρόσβαση στις κάμερες του συστήματος για τη λήψη φωτογραφιών και βίντεο"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Αυτή η προνομιακή εφαρμογή ή εφαρμογή συστήματος μπορεί να τραβάει φωτογραφίες και να εγγράφει βίντεο, χρησιμοποιώντας μια κάμερα του συστήματος ανά πάσα στιγμή. Απαιτείται, επίσης, η εφαρμογή να έχει την άδεια android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Επιτρέψτε σε μια εφαρμογή ή μια υπηρεσία να λαμβάνει επανάκλησεις σχετικά με το άνοιγμα ή το κλείσιμο συσκευών κάμερας."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index f933a2fae10f..8e7d1a33b98d 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"cambiar tu configuración de audio"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permite que la aplicación modifique la configuración de audio global, por ejemplo, el volumen y el altavoz de salida."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"grabar audio"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Esta app puede grabar audio con el micrófono mientras está en uso."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"grabar audio en segundo plano"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Esta app puede grabar audio con el micrófono en cualquier momento."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"enviar comandos a la tarjeta SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Permite que la aplicación envíe comandos a la tarjeta SIM. Usar este permiso es peligroso."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"reconocer actividad física"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Esta app puede reconocer tu actividad física."</string>
<string name="permlab_camera" msgid="6320282492904119413">"tomar fotografías y grabar videos"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Esta app puede tomar fotos y grabar videos con la cámara mientras está en uso."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"capturar fotos y videos en segundo plano"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Esta app puede tomar fotos y grabar videos con la cámara en cualquier momento."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Permitir que una aplicación o un servicio accedan a las cámaras del sistema para tomar fotos y grabar videos"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Esta app del sistema o con privilegios puede tomar fotografías y grabar videos con una cámara del sistema en cualquier momento. Para ello, requiere tener el permiso android.permission.CAMERA."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permite que una aplicación o un servicio reciba devoluciones de llamada cuando se abren o cierran dispositivos de cámara."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 834c901eea46..ffc5ff72f836 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"cambiar la configuración de audio"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permite que la aplicación modifique la configuración de audio global (por ejemplo, el volumen y el altavoz de salida)."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"grabar sonido"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Esta aplicación puede grabar audio con el micrófono mientras la estés usando."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"Grabar audio en segundo plano"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Esta aplicación puede grabar audio con el micrófono en cualquier momento."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"enviar comandos a la tarjeta SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Permite que la aplicación envíe comandos a la tarjeta SIM. Este permiso es muy peligroso."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"reconocer actividad física"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Esta aplicación puede reconocer tu actividad física."</string>
<string name="permlab_camera" msgid="6320282492904119413">"realizar fotografías y vídeos"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Esta aplicación puede hacer fotografías y grabar vídeos con la cámara mientras la estés usando."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"Hacer fotografías y grabar vídeos en segundo plano"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Esta aplicación puede hacer fotografías y grabar vídeos con la cámara en cualquier momento."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Permitir que una aplicación o servicio acceda a las cámaras del sistema para hacer fotos y vídeos"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Esta aplicación del sistema o con privilegios puede hacer fotos y grabar vídeos en cualquier momento con una cámara del sistema, aunque debe tener también el permiso android.permission.CAMERA para hacerlo"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permitir que una aplicación o servicio reciba retrollamadas cada vez que se abra o cierre una cámara."</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index babd58d310de..d825429032bb 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"muuda heliseadeid"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Võimaldab rakendusel muuta üldiseid heliseadeid, näiteks helitugevust ja seda, millist kõlarit kasutatakse väljundiks."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"salvesta heli"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"See rakendus saab mikrofoniga heli salvestada siis, kui rakendus on kasutusel."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"Taustal heli salvestamine."</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"See rakendus saab mikrofoniga heli salvestada mis tahes ajal."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM-kaardile käskluste saatmine"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Lubab rakendusel saata käske SIM-kaardile. See on väga ohtlik."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"füüsiliste tegevuste tuvastamine"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"See rakendus saab tuvastada teie füüsilised tegevused."</string>
<string name="permlab_camera" msgid="6320282492904119413">"piltide ja videote tegemine"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"See rakendus saab kaameraga pildistada ja videoid salvestada siis, kui rakendus on kasutusel."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"Taustal pildistamine ja videote salvestamine."</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"See rakendus saab kaameraga pildistada ja videoid salvestada mis tahes ajal."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Rakendusel või teenusel lubatakse süsteemi kaameratele juurde pääseda, et pilte ja videoid jäädvustada"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"See privileegidega või süsteemirakendus saab süsteemi kaameraga alati pilte ja videoid jäädvustada. Rakendusel peab olema ka luba android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Lubab rakendusel või teenusel kaameraseadmete avamise või sulgemise kohta tagasikutseid vastu võtta."</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 3ba099b3b411..05d40509e996 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"aldatu audio-ezarpenak"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Audio-ezarpen orokorrak aldatzeko baimena ematen dio; besteak beste, bolumena eta irteerarako zer bozgorailu erabiltzen den."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"grabatu audioa"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Aplikazioak abian den bitartean erabil dezake mikrofonoa audioa grabatzeko."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"Audioa grabatu atzeko planoan."</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Aplikazioak edonoiz erabil dezake mikrofonoa audioa grabatzeko."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"bidali aginduak SIM txartelera"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"SIM txartelera aginduak bidaltzeko aukera ematen die aplikazioei. Oso arriskutsua da."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"hauteman ariketa fisikoa"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Aplikazioak ariketa fisikoa hauteman dezake."</string>
<string name="permlab_camera" msgid="6320282492904119413">"atera argazkiak eta grabatu bideoak"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Aplikazioak abian den bitartean erabil dezake kamera argazkiak ateratzeko eta bideoak grabatzeko."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"Argazkiak atera eta bideoak grabatu atzeko planoan."</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Aplikazioak edonoiz erabil dezake kamera argazkiak ateratzeko eta bideoak grabatzeko."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"onartu aplikazio edo zerbitzu bati sistemako kamerak atzitzea argazkiak eta bideoak ateratzeko"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Pribilegioa duen edo sistemakoa den aplikazio honek edonoiz erabil dezake kamera argazkiak ateratzeko eta bideoak grabatzeko. Halaber, android.permission.CAMERA baimena izan behar du aplikazioak."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"eman jakinarazpenak jasotzeko baimena aplikazioari edo zerbitzuari kamerak ireki edo ixten direnean."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 7750d5d50342..a99d4d66b100 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"تغییر تنظیمات صوتی"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"به برنامه امکان می‌دهد تنظیمات صوتی کلی مانند میزان صدا و بلندگوی مورد استفاده برای پخش صدا را تغییر دهد."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ضبط صدا"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"این برنامه وقتی درحال استفاده است، می‌تواند بااستفاده از میکروفون صدا ضبط کند."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ضبط صدا در پس‌زمینه"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"این برنامه می‌تواند در هرزمانی با استفاده از میکروفون صدا ضبط کند."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"ارسال فرمان به سیم کارت"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"به برنامه اجازه ارسال دستورات به سیم کارت را می‌دهد. این بسیار خطرناک است."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"تشخیص فعالیت فیزیکی"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"این برنامه نمی‌تواند فعالیت فیزیکی‌تان را تشخیص دهد."</string>
<string name="permlab_camera" msgid="6320282492904119413">"عکسبرداری و فیلمبرداری"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"این برنامه وقتی درحال استفاده است، می‌تواند بااستفاده از دوربین عکس و فیلم بگیرد."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"گرفتن عکس و فیلم در پس‌زمینه"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"این برنامه می‌تواند در هرزمانی با استفاده از دوربین عکس و فیلم بگیرد."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"به برنامه یا سرویسی اجازه دهید برای عکس‌برداری و فیلم‌برداری به دوربین‌های سیستم دسترسی داشته باشد"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"‏این برنامه سیستم یا دارای امتیاز، می‌تواند با استفاده از دوربین سیستم در هرزمانی عکس‌برداری و فیلم‌برداری کند. برنامه به اجازه android.permission.CAMERA هم نیاز دارد."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"مجاز کردن برنامه یا سرویس برای دریافت پاسخ تماس درباره دستگاه‌های دوربینی که باز یا بسته می‌شوند."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 616223b38e0f..e7bcf4867203 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -304,7 +304,7 @@
<string name="permgrouplab_sms" msgid="795737735126084874">"Tekstiviestit"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"lähettää ja tarkastella tekstiviestejä"</string>
<string name="permgrouplab_storage" msgid="1938416135375282333">"Tiedostot ja media"</string>
- <string name="permgroupdesc_storage" msgid="6351503740613026600">"käyttää laitteellesi tallennettuja valokuvia, mediatiedostoja ja muita tiedostoja"</string>
+ <string name="permgroupdesc_storage" msgid="6351503740613026600">"käyttää laitteellesi tallennettuja kuvia, mediatiedostoja ja muita tiedostoja"</string>
<string name="permgrouplab_microphone" msgid="2480597427667420076">"Mikrofoni"</string>
<string name="permgroupdesc_microphone" msgid="1047786732792487722">"tallentaa ääntä"</string>
<string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"Liikkuminen"</string>
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"muuta ääniasetuksia"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Antaa sovelluksen muokata yleisiä ääniasetuksia, kuten äänenvoimakkuutta ja käytettävää kaiutinta."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"tallentaa ääntä"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Tämä sovellus voi tallentaa mikrofonilla audiota, kun sovellusta käytetään."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"tallentaa audiota taustalla"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Tämä sovellus voi tallentaa mikrofonilla audiota koska tahansa."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"lähettää komentoja SIM-kortille"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Antaa sovelluksen lähettää komentoja SIM-kortille. Tämä ei ole turvallista."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"tunnistaa liikkumisen"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Sovellus voi tunnistaa liikkumisesi."</string>
<string name="permlab_camera" msgid="6320282492904119413">"ota kuvia ja videoita"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Tämä sovellus voi ottaa kameralla kuvia ja videoita, kun sovellusta käytetään."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"ottaa kuvia ja videoita taustalla"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Tämä sovellus voi ottaa kameralla kuvia ja videoita koska tahansa."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Salli sovellukselle tai palvelulle pääsy järjestelmän kameroihin, jotta se voi ottaa kuvia ja nauhoittaa videoita"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Tämä oikeutettu tai järjestelmäsovellus voi ottaa järjestelmän kameralla kuvia ja videoita koska tahansa. Sovelluksella on oltava myös android.permission.CAMERA-lupa"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Salli sovelluksen tai palvelun vastaanottaa vastakutsuja kameralaitteiden avaamisesta tai sulkemisesta."</string>
@@ -1925,7 +1919,7 @@
<string name="app_category_game" msgid="4534216074910244790">"Pelit"</string>
<string name="app_category_audio" msgid="8296029904794676222">"Musiikki ja ääni"</string>
<string name="app_category_video" msgid="2590183854839565814">"Elokuvat ja videot"</string>
- <string name="app_category_image" msgid="7307840291864213007">"Kuvat ja valokuvat"</string>
+ <string name="app_category_image" msgid="7307840291864213007">"Kuvat ja kuvat"</string>
<string name="app_category_social" msgid="2278269325488344054">"Some ja viestintä"</string>
<string name="app_category_news" msgid="1172762719574964544">"Uutiset ja lehdet"</string>
<string name="app_category_maps" msgid="6395725487922533156">"Kartat ja navigointi"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 61112702f463..aad574946036 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"modifier vos paramètres audio"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permet à l\'application de modifier les paramètres audio généraux, tels que le volume et la sortie audio utilisée."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"enregistrer des fichiers audio"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Cette application peut enregistrer de l\'audio à l\'aide du microphone lorsque vous utilisez l\'application."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"enregistrer de l\'audio en arrière-plan"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Cette application peut enregistrer de l\'audio à l\'aide du microphone en tout temps."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"envoyer des commandes à la carte SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Permet à l\'application d\'envoyer des commandes à la carte SIM. Cette fonctionnalité est très dangereuse."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"reconnaître les activités physiques"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Cette application peut reconnaître vos activités physiques."</string>
<string name="permlab_camera" msgid="6320282492904119413">"prendre des photos et filmer des vidéos"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Cette application peut prendre des photos et enregistrer des vidéos à l\'aide de l\'appareil photo lorsque vous utilisez l\'application."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"prendre des photos et enregistrer des vidéos en arrière-plan"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Cette application peut prendre des photos et enregistrer des vidéos à l\'aide de l\'appareil photo en tout temps."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Autoriser une application ou un service à accéder aux appareils photo système pour prendre des photos et filmer des vidéos"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Cette application privilégiée ou système peut prendre des photos ou filmer des vidéos à l\'aide d\'un appareil photo système en tout temps. L\'application doit également posséder l\'autorisation android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Autoriser une application ou un service de recevoir des rappels relatifs à l\'ouverture ou à la fermeture des appareils photos."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index fa991a940ffd..59d4d77e9899 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"modifier vos paramètres audio"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permet à l\'application de modifier les paramètres audio généraux, tels que le volume et la sortie audio utilisée."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"enregistrer des fichiers audio"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Cette application peut utiliser le micro pour réaliser des enregistrements audio quand elle est en cours d\'utilisation."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"réaliser des enregistrements audio en arrière-plan"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Cette application peut utiliser le micro pour réaliser des enregistrements audio à tout moment."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"envoyer des commandes à la carte SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Autoriser l\'envoi de commandes à la carte SIM via l\'application. Cette fonctionnalité est très risquée."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"reconnaître l\'activité physique"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Cette application peut reconnaître votre activité physique."</string>
<string name="permlab_camera" msgid="6320282492904119413">"prendre des photos et enregistrer des vidéos"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Cette application peut utiliser l\'appareil photo pour prendre des photos et enregistrer des vidéos quand elle est en cours d\'utilisation."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"prendre des photos et enregistrer des vidéos en arrière-plan"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Cette application peut utiliser l\'appareil photo pour prendre des photos et enregistrer des vidéos à tout moment."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Autoriser une application ou un service à accéder aux caméras système pour prendre des photos et enregistrer des vidéos"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Cette application privilégiée ou système peut utiliser une caméra photo système pour prendre des photos et enregistrer des vidéos à tout moment. Pour cela, l\'application doit également disposer de l\'autorisation android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Autoriser une application ou un service à recevoir des rappels liés à l\'ouverture ou à la fermeture de caméras"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 115850a0b69b..79380d5398ca 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"cambiar a configuración de son"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permite á aplicación modificar a configuración de audio global, como o volume e que altofalante se utiliza para a saída."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"gravar audio"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Mentres a empregas, esta aplicación pode utilizar o micrófono para gravar audio."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"gravar audio en segundo plano"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Esta aplicación pode utilizar o micrófono en calquera momento para gravar audio."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"enviar comandos á SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Permite á aplicación enviar comandos á SIM. Isto é moi perigoso."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"recoñecer actividade física"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Esta aplicación pode recoñecer a túa actividade física."</string>
<string name="permlab_camera" msgid="6320282492904119413">"facer fotos e vídeos"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Mentres a empregas, esta aplicación pode utilizar a cámara para sacar fotos e gravar vídeos."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"sacar fotos e gravar vídeos en segundo plano"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Esta aplicación pode utilizar a cámara en calquera momento para sacar fotos e gravar vídeos."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Permitir que unha aplicación ou un servizo acceda ás cámaras do sistema para sacar fotos e gravar vídeos"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Esta aplicación do sistema con privilexios pode utilizar unha cámara do sistema en calquera momento para tirar fotos e gravar vídeos. Require que a aplicación tamén teña o permiso android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permitir que unha aplicación ou servizo reciba retrochamadas cando se abran ou se pechen dispositivos con cámara."</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 918a6ff33c48..bf4d6c0b8a09 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"તમારી ઑડિઓ સેટિંગ્સ બદલો"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"એપ્લિકેશનને વૈશ્વિક ઑડિઓ સેટિંગ્સને સંશોધિત કરવાની મંજૂરી આપે છે, જેમ કે વૉલ્યૂમ અને આઉટપુટ માટે કયા સ્પીકરનો ઉપયોગ કરવો."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ઑડિઓ રેકોર્ડ કરવાની"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"આ ઍપ ઉપયોગમાં હોય ત્યારે તે માઇક્રોફોનનો ઉપયોગ કરીને ઑડિયો રેકોર્ડ કરી શકે છે."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"બૅકગ્રાઉન્ડમાં ઑડિયો રેકોર્ડ કરો"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"આ ઍપ, માઇક્રોફોનનો ઉપયોગ કરીને કોઈપણ સમયે ઑડિયો રેકોર્ડ કરી શકે છે."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"સિમ ને આદેશો મોકલો"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"એપ્લિકેશનને સિમ પરા આદેશો મોકલવાની મંજૂરી આપે છે. આ ખૂબ જ ખતરનાક છે."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"શારીરિક પ્રવૃત્તિને ઓળખો"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"આ ઍપ તમારી શારીરિક પ્રવૃત્તિને ઓળખી શકે છે."</string>
<string name="permlab_camera" msgid="6320282492904119413">"ચિત્રો અને વિડિઓઝ લો"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"આ ઍપ ઉપયોગમાં હોય ત્યારે તે કૅમેરાનો ઉપયોગ કરીને ફોટા લઈ શકે છે અને વીડિયો રેકોર્ડ કરી શકે છે."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"બૅકગ્રાઉન્ડમાં ફોટા અને વીડિયો લો"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"આ ઍપ, કૅમેરાનો ઉપયોગ કરીને કોઈપણ સમયે ફોટા લઈ શકે છે અને વીડિયો રેકોર્ડ કરી શકે છે."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"ઍપ્લિકેશન અથવા સેવા ઍક્સેસને સિસ્ટમ કૅમેરાનો ઉપયોગ કરીને ફોટા અને વીડિયો લેવાની મંજૂરી આપો"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"આ વિશેષાધિકૃત અથવા સિસ્ટમ ઍપ કોઈપણ સમયે સિસ્ટમ કૅમેરાનો ઉપયોગ કરીને ફોટા લઈ અને વીડિયો રેકૉર્ડ કરી શકે છે. ઍપ દ્વારા આયોજિત કરવા માટે android.permission.CAMERAની પરવાનગી પણ જરૂરી છે"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"કૅમેરા ડિવાઇસ ચાલુ કે બંધ થવા વિશે કૉલબૅક પ્રાપ્ત કરવાની ઍપ્લિકેશન કે સેવાને મંજૂરી આપો."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index db049b19f5d5..b867e9d04f7d 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"अपनी ऑडियो सेटिंग बदलें"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"ऐप्स को वैश्विक ऑडियो सेटिंग, जैसे वॉल्‍यूम और कौन-सा स्पीकर आउटपुट के लिए उपयोग किया गया, संशोधित करने देता है."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ऑडियो रिकॉर्ड करने"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"जब इस ऐप्लिकेशन का इस्तेमाल किया जा रहा हो, तब यह माइक्रोफ़ोन का इस्तेमाल करके ऑडियो रिकॉर्ड कर सकता है."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ऐप्लिकेशन बैकग्राउंड में ऑडियो रिकॉर्ड कर सकता है"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"यह ऐप्लिकेशन जब चाहे, माइक्रोफ़ोन का इस्तेमाल करके ऑडियो रिकॉर्ड कर सकता है."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"सिम पर निर्देश भेजें"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"ऐप को सिम पर निर्देश भेजने देती है. यह बहुत ही खतरनाक है."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"शरीर की गतिविधि को पहचानना"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"यह ऐप्लिकेशन आपके शरीर की गतिविधि को पहचान सकता है."</string>
<string name="permlab_camera" msgid="6320282492904119413">"चित्र और वीडियो लें"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"जब इस ऐप्लिकेशन का इस्तेमाल किया जा रहा हो, तब यह कैमरे का इस्तेमाल करके, तस्वीरें ले सकता है और वीडियो रिकॉर्ड कर सकता है."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"ऐप्लिकेशन बैकग्राउंड में तस्वीरें ले सकता है और वीडियो रिकॉर्ड कर सकता है"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"यह ऐप्लिकेशन जब चाहे, कैमरे का इस्तेमाल करके तस्वीरें ले सकता है और वीडियो रिकॉर्ड कर सकता है."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"तस्वीरें और वीडियो लेने के लिए ऐप्लिकेशन या सेवा को सिस्टम के कैमरे का ऐक्सेस दें"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"यह खास सिस्टम ऐप्लिकेशन जब चाहे, तस्वीरें लेने और वीडियो रिकॉर्ड करने के लिए सिस्टम के कैमरे का इस्तेमाल कर सकता है. इसके लिए ऐप्लिकेशन को android.permission.CAMERA की अनुमति देना भी ज़रूरी है"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"डिवाइस का कैमरे चालू या बंद होने पर, किसी ऐप्लिकेशन या सेवा को कॉलबैक पाने की मंज़ूरी दें."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index b9b3665b5ebe..dd2bdbeb74c3 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -435,23 +435,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"promjena postavki zvuka"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Aplikaciji omogućuje izmjenu globalnih postavki zvuka, primjerice glasnoće i zvučnika koji se upotrebljava za izlaz."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"snimanje zvuka"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Aplikacija može snimati audiozapise pomoću mikrofona dok se upotrebljava."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"snimati audiozapise u pozadini"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Aplikacija može snimati audiozapise pomoću mikrofona u svakom trenutku."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"slati naredbe SIM-u"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Omogućuje aplikaciji slanje naredbi SIM-u. To je vrlo opasno."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"prepoznati tjelesnu aktivnost"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Ova aplikacija može prepoznati vašu tjelesnu aktivnost."</string>
<string name="permlab_camera" msgid="6320282492904119413">"snimi fotografije i videozapise"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Aplikacija može snimati fotografije i videozapise pomoću kamere dok se upotrebljava."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"snimati fotografije i videozapise u pozadini"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Aplikacija može snimati fotografije i videozapise pomoću kamere u svakom trenutku."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Dopustite aplikaciji ili usluzi da pristupa kamerama sustava radi snimanja fotografija i videozapisa"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ova povlaštena aplikacija ili aplikacija sustava u svakom trenutku može snimati fotografije i videozapise kamerom sustava. Aplikacija mora imati i dopuštenje android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Dopustite aplikaciji ili usluzi da prima povratne pozive o otvaranju ili zatvaranju fotoaparata."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 16d60dc1bf4a..9d1c2f491962 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"hangbeállítások módosítása"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Lehetővé teszi az alkalmazás számára az általános hangbeállítások, például a hangerő és a használni kívánt kimeneti hangszóró módosítását."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"hanganyag rögzítése"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Az alkalmazás a mikrofon használatával akkor készíthet hangfelvételt, amikor az alkalmazás használatban van."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"hangfelvétel készítése a háttérben"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Az alkalmazás a mikrofon használatával bármikor készíthet hangfelvételt."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"parancsok küldése a SIM-kártyára"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Engedélyezi, hogy az alkalmazás parancsokat küldjön a SIM kártyára. Ez rendkívül veszélyes lehet."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"testmozgás felismerése"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Az alkalmazás képes felismerni a testmozgást."</string>
<string name="permlab_camera" msgid="6320282492904119413">"fotók és videók készítése"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Az alkalmazás a kamera használatával akkor készíthet fényképeket és videókat, amikor az alkalmazás használatban van."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"fényképek és videók készítése a háttérben"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Az alkalmazás a kamera használatával bármikor készíthet fényképeket és videókat."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"A rendszerkamerákhoz való hozzáférés, illetve képek és videók rögzítésének engedélyezése alkalmazás vagy szolgáltatás számára"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"A rendszerkamera használatával ez az előnyben részesített vagy rendszeralkalmazás bármikor készíthet fényképeket és videókat. Az alkalmazásnak az „android.permission.CAMERA” engedéllyel is rendelkeznie kell."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Visszahívás fogadásának engedélyezése alkalmazás vagy szolgáltatás számára, ha a kamerákat megnyitják vagy bezárják."</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index aa4197fef8e6..4e2bbe2111b5 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"փոխել ձեր աուդիո կարգավորումները"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Թույլ է տալիս հավելվածին փոփոխել ձայնանյութի գլոբալ կարգավորումները, ինչպես օրինակ՝ ձայնը և թե որ խոսափողն է օգտագործված արտածման համար:"</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ձայնագրել աուդիո ֆայլ"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Այս հավելվածը կարող է օգտագործել խոսափողը՝ ձայնագրություններ անելու համար, միայն երբ հավելվածն ակտիվ է։"</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ձայնագրել ֆոնային ռեժիմում"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Այս հավելվածը կարող է ցանկացած ժամանակ օգտագործել խոսափողը՝ ձայնագրություններ անելու համար։"</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"ուղարկել հրամաններ SIM քարտին"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Թույլ է տալիս հավելվածին հրամաններ ուղարկել SIM-ին: Սա շատ վտանգավոր է:"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"ֆիզիկական ակտիվության ճանաչում"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Հավելվածը կարող է ճանաչել ձեր ֆիզիկական ակտիվությունը:"</string>
<string name="permlab_camera" msgid="6320282492904119413">"լուսանկարել և տեսանկարել"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Այս հավելվածը կարող է օգտագործել տեսախցիկը՝ լուսանկարելու և տեսագրելու համար, միայն երբ հավելվածն ակտիվ է։"</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"լուսանկարել և տեսագրել ֆոնային ռեժիմում"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Այս հավելվածը կարող է ցանկացած ժամանակ օգտագործել տեսախցիկը՝ լուսանկարելու և տեսագրելու համար։"</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Թույլատրել որևէ հավելվածի կամ ծառայության օգտագործել համակարգի տեսախցիկները՝ լուսանկարելու և տեսանկարելու համար"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Այս արտոնյալ կամ համակարգային հավելվածը կարող է ցանկացած պահի լուսանկարել և տեսագրել՝ օգտագործելով համակարգի տեսախցիկները։ Հավելվածին նաև անհրաժեշտ է android.permission.CAMERA թույլտվությունը։"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Թույլատրել հավելվածին կամ ծառայությանը հետզանգեր ստանալ՝ տեսախցիկների բացվելու և փակվելու դեպքում։"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 3e6c23edc7e1..202664f7caab 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"ubah setelan audio Anda"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Memungkinkan aplikasi mengubah setelan audio global, misalnya volume dan pengeras suara mana yang digunakan untuk keluaran."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"rekam audio"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Aplikasi ini dapat merekam audio menggunakan mikrofon saat aplikasi sedang digunakan."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"merekam audio di latar belakang"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Aplikasi ini dapat merekam audio menggunakan mikrofon kapan saja."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"kirimkan perintah ke SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Mengizinkan aplikasi mengirim perintah ke SIM. Ini sangat berbahaya."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"kenali aktivitas fisik"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Aplikasi ini dapat mengenali aktivitas fisik Anda."</string>
<string name="permlab_camera" msgid="6320282492904119413">"ambil gambar dan video"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Aplikasi ini dapat mengambil gambar dan merekam video menggunakan kamera saat aplikasi sedang digunakan."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"mengambil gambar dan merekam video di latar belakang"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Aplikasi ini dapat mengambil gambar dan merekam video menggunakan kamera kapan saja."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Izinkan akses aplikasi atau layanan ke kamera sistem untuk mengambil gambar dan video"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Aplikasi sistem atau yang diberi hak istimewa ini dapat mengambil gambar dan merekam video menggunakan kamera sistem kapan saja. Mewajibkan aplikasi untuk memiliki izin android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Izinkan aplikasi atau layanan untuk menerima callback tentang perangkat kamera yang sedang dibuka atau ditutup."</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 272145dde05b..efb23d4db012 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"breyta hljóðstillingum"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Leyfir forriti að breyta altækum hljóðstillingum, s.s. hljóðstyrk og hvaða hátalari er notaður sem úttak."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"taka upp hljóð"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Þetta forrit getur tekið upp hljóð með hljóðnemanum meðan forritið er í notkun."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"taka upp hljóð í bakgrunni"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Þetta forrit getur tekið upp hljóð með hljóðnemanum hvenær sem er."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"senda skipanir til SIM-kortsins"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Leyfir forriti að senda SIM-kortinu skipanir. Þetta er mjög hættulegt."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"greina hreyfingu"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Þetta forrit getur greint hreyfingu þína."</string>
<string name="permlab_camera" msgid="6320282492904119413">"taka myndir og myndskeið"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Þetta forrit getur tekið myndir og tekið upp myndskeið með myndavélinni þegar forritið er í notkun."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"taka myndir og taka upp myndskeið í bakgrunni"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Þetta forrit getur tekið myndir og tekið upp myndskeið með myndavélinni hvenær sem er."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Veittu forriti eða þjónustu aðgang að myndavélum kerfis til að taka myndir og myndskeið"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Þetta forgangs- eða kerfisforrit hefur heimild til að taka myndir og taka upp myndskeið með myndavél kerfisins hvenær sem er. Forritið þarf einnig að vera með heimildina android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Leyfa forriti eða þjónustu að taka við svörum um myndavélar sem verið er að opna eða loka."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 9970915ec4b9..ec446d7e2f57 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"modifica impostazioni audio"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Consente all\'applicazione di modificare le impostazioni audio globali, come il volume e quale altoparlante viene utilizzato per l\'uscita."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"registrazione audio"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Questa app può registrare audio tramite il microfono mentre l\'app è in uso."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"Registrazione di audio in background"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Questa app può registrare audio tramite il microfono in qualsiasi momento."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"invio di comandi alla SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Consente all\'app di inviare comandi alla SIM. Questo è molto pericoloso."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"riconoscimento dell\'attività fisica"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Questa app può riconoscere la tua attività fisica."</string>
<string name="permlab_camera" msgid="6320282492904119413">"acquisizione di foto e video"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Questa app può scattare foto e registrare video tramite la fotocamera mentre l\'app è in uso."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"Acquisizione di foto e video in background"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Questa app può scattare foto e registrare video tramite la fotocamera in qualsiasi momento."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Consenti a un\'applicazione o a un servizio di accedere alle videocamere del sistema per fare foto e video"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Questa app di sistema o con privilegi può scattare foto e registrare video tramite una videocamera di sistema in qualsiasi momento. Richiede che anche l\'app disponga dell\'autorizzazione android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Consenti a un\'applicazione o a un servizio di ricevere callback relativi all\'apertura o alla chiusura di videocamere."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index e8413d66a5fe..874d5770c32e 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -438,23 +438,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"שנה את הגדרות האודיו שלך"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"מאפשר לאפליקציה לשנות הגדרות אודיו גלובליות כמו עוצמת קול ובחירת הרמקול המשמש לפלט."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"הקלט אודיו"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"האפליקציה הזו יכולה להשתמש במיקרופון כדי להקליט אודיו כאשר היא בשימוש."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"הקלטת אודיו ברקע"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"האפליקציה הזו יכולה להשתמש במיקרופון כדי להקליט אודיו בכל זמן."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"‏שליחת פקודות אל ה-SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"‏מאפשרת ליישום לשלוח פקודות ל-SIM. זוהי הרשאה מסוכנת מאוד."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"זיהוי הפעילות הגופנית"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"האפליקציה מזהה את הפעילות הגופנית שלך."</string>
<string name="permlab_camera" msgid="6320282492904119413">"צלם תמונות וסרטונים"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"האפליקציה הזו יכולה להשתמש במצלמה כדי לצלם תמונות ולהקליט סרטונים כאשר היא בשימוש."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"צילום תמונות וסרטונים ברקע"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"האפליקציה הזו יכולה להשתמש במצלמה כדי לצלם תמונות ולהקליט סרטונים בכל זמן."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"הרשאת גישה לאפליקציה או לשירות למצלמות המערכת כדי לצלם תמונות וסרטונים"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"‏אפליקציה זו בעלת ההרשאות, או אפליקציית המערכת הזו, יכולה לצלם תמונות ולהקליט סרטונים באמצעות מצלמת מערכת בכל זמן. בנוסף, לאפליקציה נדרשת ההרשאה android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"‏אפליקציה או שירות יוכלו לקבל קריאות חוזרות (callback) כשמכשירי מצלמה ייפתחו או ייסגרו."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 012ee3f352fd..32a4dedd6290 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"音声設定の変更"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"音声全般の設定(音量、出力に使用するスピーカーなど)の変更をアプリに許可します。"</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"録音"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"このアプリは、ユーザーがアプリを使用している場合にマイクを使用して音声を録音できます。"</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"バックグラウンドでの音声の録音"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"このアプリは、いつでもマイクを使用して音声を録音できます。"</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"SIMへのコマンド送信"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"SIMにコマンドを送信することをアプリに許可します。この許可は非常に危険です。"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"身体活動の認識"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"このアプリで身体活動が認識されるようにします。"</string>
<string name="permlab_camera" msgid="6320282492904119413">"写真と動画の撮影"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"このアプリは、ユーザーがアプリを使用している場合にカメラを使用して写真や動画を撮影できます。"</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"バックグラウンドでの写真と動画の撮影"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"このアプリは、いつでもカメラを使用して写真や動画を撮影できます。"</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"写真と動画を撮影するには、システムカメラへのアクセスをアプリまたはサービスに許可してください"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"権限を付与されたこのアプリまたはシステムアプリは、いつでもシステムカメラを使用して写真と動画を撮影できます。アプリには android.permission.CAMERA 権限も必要です"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"カメラデバイスが起動または終了したときにコールバックを受け取ることを、アプリまたはサービスに許可してください。"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index f6e8f5d52ef6..349bd167ff56 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"თქვენი აუდიო პარამეტრების შეცვლა"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"აპს შეეძლება აუდიოს გლობალური პარამეტრების შეცვლა. მაგ.: ხმის სიმაღლე და რომელი დინამიკი გამოიყენება სიგნალის გამოსტანად."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"აუდიოს ჩაწერა"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"ამ აპს გამოყენების დროს შეუძლია მიკროფონით აუდიოს ჩაწერა."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ფონურად ჩაწერს აუდიოს"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"ამ აპს ნებისმიერ დროს შეუძლია მიკროფონით აუდიოს ჩაწერა."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"ბრძანებების SIM-ზე გაგზავნა"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"აპისთვის ნების დართვა გაუგზავნოს ბრძანებები SIM-ბარათს. ეს ძალიან საშიშია."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"ფიზიკური აქტივობის ამოცნობა"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"ამ აპს შეუძლია თქვენი ფიზიკური აქტივობის ამოცნობა."</string>
<string name="permlab_camera" msgid="6320282492904119413">"სურათებისა და ვიდეოების გადაღება"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"ამ აპს გამოყენების დროს შეუძლია კამერით სურათების გადაღება და ვიდეოების ჩაწერა."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"ფონურად გადაიღებს სურათებს და ჩაწერს ვიდეოს"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"ამ აპს ნებისმიერ დროს შეუძლია კამერით სურათების გადაღება და ვიდეოების ჩაწერა."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"ნება დაერთოს აპლიკაციას ან სერვისს, ჰქონდეს წვდომა სისტემის კამერებზე სურათების და ვიდეოების გადასაღებად"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ამ პრივილეგირებულ ან სისტემის აპს შეუძლია ფოტოების გადაღება და ვიდეოების ჩაწერა ნებისმიერ დროს სისტემის კამერის გამოყენებით. საჭიროა, რომ აპს ჰქოდეს android.permission.CAMERA ნებართვაც"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"ნება დაერთოს აპლიკაციას ან სერვისს, მიიღოს გადმორეკვები კამერის მოწყობილობის გახსნის ან დახურვისას."</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index b0d363c109a5..4d4eef0378dd 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"аудио параметрлерін өзгерту"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Қолданбаға дыбыс қаттылығы және аудио шығыс үндеткішін таңдау сияқты жаһандық аудио параметрлерін өзгерту мүмкіндігін береді."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"аудио жазу"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Бұл қолданба жұмыс барысында микрофон арқылы аудиомазмұн жаза алады."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"Фондық режимде аудиомазмұн жазу"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Бұл қолданба кез келген уақытта микрофон арқылы аудиомазмұн жаза алады."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM картасына пәрмендер жіберу"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Қолданбаға SIM картасына пәрмен жіберу мүмкіндігін береді. Бұл өте қауіпті."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"физикалық әрекетті тану"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Бұл қолданба физикалық әрекетті тани алады."</string>
<string name="permlab_camera" msgid="6320282492904119413">"фотосурет жасау және бейне жазу"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Бұл қолданба жұмыс барысында камерамен суретке түсіріп, бейнелер жаза алады."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"Фондық режимде сурет пен бейне түсіру"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Бұл қолданба кез келген уақытта камерамен суретке түсіріп, бейнелер жаза алады."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Суретке немесе бейнеге түсіру үшін қолданбаға немесе қызметке жүйелік камераларды пайдалануға рұқсат беру"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Осы айрықша немесе жүйе қолданбасы кез келген уақытта жүйелік камера арқылы суретке не бейнеге түсіре алады. Қолданбаға android.permission.CAMERA рұқсаты қажет болады."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Қолданбаға не қызметке ашылып не жабылып жатқан камера құрылғылары туралы кері шақыру алуға рұқсат ету"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index a16251dd0938..3ebd7364b2c9 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"ប្ដូរ​ការ​កំណត់​អូឌីយូ​របស់​អ្នក"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"ឲ្យ​កម្មវិធី​កែ​ការ​កំណត់​សំឡេង​សកល ដូច​ជា​កម្រិត​សំឡេង និង​អូប៉ាល័រ​ដែល​បាន​ប្រើ​សម្រាប់​លទ្ធផល។"</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ថត​សំឡេង"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"កម្មវិធី​នេះ​អាច​ថតសំឡេងដោយប្រើមីក្រូហ្វូន នៅពេលកំពុងប្រើប្រាស់កម្មវិធី។"</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ថតសំឡេងនៅផ្ទៃខាងក្រោយ"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"កម្មវិធី​នេះ​អាច​ថត​សំឡេង​ដោយ​ប្រើ​មីក្រូហ្វូន​បាន​គ្រប់​ពេល។"</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"ផ្ញើពាក្យបញ្ជាទៅស៊ីមកាត"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"ឲ្យ​កម្មវិធី​ផ្ញើ​ពាក្យ​បញ្ជា​ទៅ​ស៊ីម​កាត។ វា​គ្រោះ​ថ្នាក់​ណាស់។"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"ស្គាល់​សកម្មភាព​រាងកាយ"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"កម្មវិធីនេះ​អាចស្គាល់សកម្មភាព​រាងកាយ​របស់អ្នក។"</string>
<string name="permlab_camera" msgid="6320282492904119413">"ថត​រូប និងវីដេអូ"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"កម្មវិធី​នេះ​អាច​ថត​រូប​ និង​វីដេអូ​ដោយ​ប្រើ​កាមេរ៉ា នៅពេលកំពុងប្រើប្រាស់កម្មវិធី។"</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"ថតរូបភាព និងវីដេអូនៅផ្ទៃខាងក្រោយ"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"កម្មវិធី​នេះ​អាច​ថត​រូប​ និង​វីដេអូ​ដោយ​ប្រើ​កាមេរ៉ា​បាន​គ្រប់​ពេល​។"</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"អនុញ្ញាតឱ្យកម្មវិធី ឬសេវាកម្ម​ចូលប្រើកាមេរ៉ា​ប្រព័ន្ធ ដើម្បីថតរូប និង​ថតវីដេអូ"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"កម្មវិធីប្រព័ន្ធ ឬកម្មវិធីដែលមានសិទ្ធិអនុញ្ញាត​នេះអាចថត​រូប និង​ថតវីដេអូ ដោយប្រើ​កាមេរ៉ា​ប្រព័ន្ធបាន​គ្រប់ពេល។ តម្រូវឱ្យមាន​ការអនុញ្ញាត android.permission.CAMERA ដើម្បីឱ្យ​កម្មវិធីអាចធ្វើ​សកម្មភាព​បានផងដែរ"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"អនុញ្ញាតឱ្យកម្មវិធី ឬសេវាកម្ម​ទទួលការហៅត្រឡប់វិញអំពី​កាមេរ៉ាដែលកំពុងបិទ ឬបើក។"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 58ecb627de1d..0cf6f494677b 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"ನಿಮ್ಮ ಆಡಿಯೊ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಬದಲಾಯಿಸಿ"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"ವಾಲ್ಯೂಮ್ ರೀತಿಯ ಮತ್ತು ಔಟ್‍‍ಪುಟ್‍‍ಗಾಗಿ ಯಾವ ಸ್ಪೀಕರ್ ಬಳಸಬೇಕು ಎಂಬ ರೀತಿಯ ಜಾಗತಿಕ ಆಡಿಯೊ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ಆಡಿಯೊ ರೆಕಾರ್ಡ್ ಮಾಡಿ"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"ಆ್ಯಪ್ ಬಳಕೆಯಲ್ಲಿರುವಾಗ ಈ ಆ್ಯಪ್ ಮೈಕ್ರೊಫೋನ್ ಬಳಸಿ ಆಡಿಯೊವನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಬಹುದು."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಆಡಿಯೊವನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಿ"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"ಈ ಆ್ಯಪ್ ಮೈಕ್ರೋಫೋನ್ ಬಳಸುವ ಮೂಲಕ ಯಾವುದೇ ಸಮಯದಲ್ಲಾದರೂ ಆಡಿಯೊ ರೆಕಾರ್ಡ್ ಮಾಡಬಹುದು."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"ಸಿಮ್‌ಗೆ ಆಜ್ಞೆಗಳನ್ನು ಕಳುಹಿಸಿ"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"ಸಿಮ್‌ ಗೆ ಆದೇಶಗಳನ್ನು ಕಳುಹಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ. ಇದು ತುಂಬಾ ಅಪಾಯಕಾರಿ."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"ದೈಹಿಕ ಚಟುವಟಿಕೆಯನ್ನು ಗುರುತಿಸಿ"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"ಈ ಆ್ಯಪ್‌ ನಿಮ್ಮ ದೈಹಿಕ ಚಟುವಟಿಕೆಯನ್ನು ಗುರುತಿಸಬಹುದು."</string>
<string name="permlab_camera" msgid="6320282492904119413">"ಚಿತ್ರಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳನ್ನು ಸೆರೆಹಿಡಿಯಿರಿ"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"ಆ್ಯಪ್ ಬಳಕೆಯಲ್ಲಿರುವಾಗ, ಈ ಆ್ಯಪ್ ಕ್ಯಾಮರಾ ಬಳಸಿ ಚಿತ್ರಗಳನ್ನು ತೆಗೆಯಬಹುದು ಮತ್ತು ವೀಡಿಯೊಗಳನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಬಹುದು."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಚಿತ್ರಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳಿ"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"ಈ ಆ್ಯಪ್ ಯಾವ ಸಮಯದಲ್ಲಾದರೂ ಕ್ಯಾಮರಾ ಬಳಸಿಕೊಂಡು ಚಿತ್ರಗಳು ಮತ್ತು ವಿಡಿಯೋಗಳನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಬಹುದು."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"ಫೋಟೋಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳಲು ಸಿಸ್ಟಂ ಕ್ಯಾಮರಾಗಳಿಗೆ ಅಪ್ಲಿಕೇಶನ್ ಅಥವಾ ಸೇವಾ ಪ್ರವೇಶವನ್ನು ಅನುಮತಿಸಿ"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ಈ ವಿಶೇಷ ಅಥವಾ ಸಿಸ್ಟಂ ಆ್ಯಪ್, ಯಾವುದೇ ಸಮಯದಲ್ಲಾದರೂ ಸಿಸ್ಟಂ ಕ್ಯಾಮರಾವನ್ನು ಬಳಸಿಕೊಂಡು ಫೋಟೋಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳಬಹುದು ಮತ್ತು ವೀಡಿಯೋಗಳನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಬಹುದು. ಆ್ಯಪ್‌ಗೆ android.permission.CAMERA ಅನುಮತಿಯ ಅಗತ್ಯವಿರುತ್ತದೆ"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"ಕ್ಯಾಮರಾ ಸಾಧನಗಳನ್ನು ತೆರೆಯುತ್ತಿರುವ ಅಥವಾ ಮುಚ್ಚುತ್ತಿರುವ ಕುರಿತು ಕಾಲ್‌ಬ್ಯಾಕ್‌ಗಳನ್ನು ಸ್ವೀಕರಿಸಲು ಆ್ಯಪ್‌ ಅಥವಾ ಸೇವೆಗೆ ಅನುಮತಿಸಿ."</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 394bd218dc6a..3dfdf3d4ebd1 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"오디오 설정 변경"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"앱이 음량이나 출력을 위해 사용하는 스피커 등 전체 오디오 설정을 변경할 수 있도록 허용합니다."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"오디오 녹음"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"앱을 사용하는 동안 앱에서 마이크를 사용하여 오디오를 녹음할 수 있습니다."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"백그라운드에서 오디오 녹음"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"언제든지 앱에서 마이크를 사용하여 오디오를 녹음할 수 있습니다."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM 카드로 명령 전송"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"앱이 SIM에 명령어를 전송할 수 있도록 허용합니다. 이 기능은 매우 신중히 허용해야 합니다."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"신체 활동 확인"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"이 앱에서 내 신체 활동을 확인할 수 있습니다."</string>
<string name="permlab_camera" msgid="6320282492904119413">"사진과 동영상 찍기"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"앱을 사용하는 동안 앱에서 카메라를 사용하여 사진을 촬영하고 동영상을 녹화할 수 있습니다."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"백그라운드에서 사진 촬영 및 동영상 녹화"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"언제든지 앱에서 카메라를 사용하여 사진을 촬영하고 동영상을 녹화할 수 있습니다."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"사진 및 동영상 촬영을 위해 애플리케이션 또는 서비스에서 시스템 카메라에 액세스하도록 허용"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"이 권한이 있는 시스템 앱은 언제든지 시스템 카메라를 사용하여 사진을 촬영하고 동영상을 녹화할 수 있습니다. 또한 앱에 android.permission.CAMERA 권한이 필요합니다."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"애플리케이션 또는 서비스에서 카메라 기기 열림 또는 닫힘에 대한 콜백을 수신하도록 허용"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 0774f6a5e3b7..7057b844da7c 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"аудио жөндөөлөрүңүздү өзгөртүңүз"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Колдонмого үн деңгээли жана кайсы динамик аркылуу үн чыгарылышы керек сыяктуу түзмөктүн аудио тууралоолорун өзгөртүүгө уруксат берет."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"аудио жаздыруу"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Бул колдонмо иштеп жатканда микрофон менен аудио файлдарды жаздыра алат."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"Фондо аудио жаздыруу"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Бул колдонмо каалаган убакта микрофон менен аудио файлдарды жаздыра алат."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM-картага буйруктарды жөнөтүү"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Колдонмого SIM-картага буйруктарды жөнөтүү мүмкүнчүлүгүн берет. Бул абдан кооптуу."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"кыймыл-аракетти аныктоо"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Бул колдонмо кыймыл-аракетиңизди аныктап турат."</string>
<string name="permlab_camera" msgid="6320282492904119413">"сүрөт жана видео тартуу"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Бул колдонмо иштеп жатканда камера менен сүрөт же видеолорду тарта алат."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"Фондо сүрөткө жана видеого тартат"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Бул колдонмо каалаган убакта камера менен сүрөт же видеолорду тарта алат."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Сүрөткө тартып, видеолорду жаздыруу үчүн бул колдонмого же кызматка тутумдун камерасын колдонууга уруксат берүү"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Бул артыкчылыктуу тутум колдонмосу тутумдун камерасын каалаган убакта колдонуп, сүрөткө тартып, видео жаздыра алат. Ошондой эле колдонмого android.permission.CAMERA уруксатын берүү керек"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Колдонмого же кызматка камера ачылып же жабылып жатканда чалууларды кабыл алууга уруксат берүү."</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 875d6817e791..315ee322fa7c 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"ປ່ຽນການຕັ້ງຄ່າສຽງຂອງທ່ານ"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"ອະນຸຍາດໃຫ້ແອັບຯແກ້ໄຂການຕັ້ງຄ່າສຽງສ່ວນກາງ ເຊັ່ນ: ລະດັບສຽງ ແລະລຳໂພງໃດທີ່ຖືກໃຊ້ສົ່ງສຽງອອກ."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ບັນທຶກສຽງ"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"ແອັບນີ້ສາມາດບັນທຶກສຽງດ້ວຍໄມໂຄຣໂຟນໃນຂະນະທີ່ກຳລັງໃຊ້ແອັບຢູ່ໄດ້."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ບັນທຶກສຽງໃນພື້ນຫຼັງ"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"ແອັບນີ້ສາມາດບັນທຶກສຽງດ້ວຍໄມໂຄຣໂຟນຕອນໃດກໍໄດ້."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"ສົ່ງ​ຄຳ​ສັ່ງ​ຫາ SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"ອະນຸຍາດໃຫ້ແອັບຯສົ່ງຄຳສັ່ງຫາ SIM. ສິ່ງນີ້ອັນຕະລາຍຫຼາຍ."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"ຈຳແນກກິດຈະກຳທາງກາຍ"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"ແອັບນີ້ສາມາດຈັດລະບຽບການເຄື່ອນໄຫວທາງກາຍຂອງທ່ານໄດ້."</string>
<string name="permlab_camera" msgid="6320282492904119413">"ຖ່າຍຮູບ ແລະວິດີໂອ"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"ແອັບນີ້ສາມາດຖ່າຍຮູບ ແລະ ບັນທຶກວິດີໂອໂດຍໃຊ້ກ້ອງຖ່າຍຮູບໃນເວລາທີ່ກຳລັງໃຊ້ແອັບຢູ່ໄດ້."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"ຖ່າຍຮູບ ແລະ ວິດີໂອໃນພື້ນຫຼັງ"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"ແອັບນີ້ສາມາດຖ່າຍຮູບ ແລະ ບັນທຶກວິດີໂອໂດຍໃຊ້ກ້ອງຖ່າຍຮູບຕອນໃດກໍໄດ້."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນ ຫຼື ບໍລິການເຂົ້າເຖິງກ້ອງຂອງລະບົບໄດ້ເພື່ອຖ່າຍຮູບ ແລະ ວິດີໂອ"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ສິດ ຫຼື ແອັບລະບົບນີ້ສາມາດຖ່າຍຮູບ ແລະ ບັນທຶກວິດີໂອໂດຍໃຊ້ກ້ອງຂອງລະບົບຕອນໃດກໍໄດ້. ຕ້ອງໃຊ້ສິດອະນຸຍາດ android.permission.CAMERA ໃຫ້ແອັບຖືນຳ"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນ ຫຼື ບໍລິການຮັບການເອີ້ນກັບກ່ຽວກັບອຸປະກອນກ້ອງຖືກເປີດ ຫຼື ປິດໄດ້."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index a3e83918702e..1d6b2c7dbb45 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -438,23 +438,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"keisti garso nustatymus"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Leidžiama programai keisti visuotinius garso nustatymus, pvz., garsumą ir tai, kuris garsiakalbis naudojamas išvesčiai."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"įrašyti garsą"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Ši programa gali įrašyti garsą naudodama mikrofoną, kol programa naudojama."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"įrašyti garsą fone"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Ši programa gali bet kada įrašyti garsą naudodama mikrofoną."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"siųsti komandas į SIM kortelę"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Programai leidžiama siųsti komandas į SIM kortelę. Tai labai pavojinga."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"atpažinti fizinę veiklą"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Ši programa gali atpažinti jūsų fizinę veiklą."</string>
<string name="permlab_camera" msgid="6320282492904119413">"fotografuoti ir filmuoti"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Ši programa gali fotografuoti ir įrašyti vaizdo įrašų naudodama fotoaparatą, kol programa naudojama."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"fotografuoti ir įrašyti vaizdo įrašų fone"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Ši programa gali bet kada fotografuoti ir įrašyti vaizdo įrašų naudodama fotoaparatą."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Suteikti programai arba paslaugai prieigą prie sistemos fotoaparatų, kad būtų galima daryti nuotraukas ir įrašyti vaizdo įrašus"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ši privilegijuota arba sistemos programa gali daryti nuotraukas ir įrašyti vaizdo įrašus naudodama sistemos fotoaparatą bet kuriuo metu. Programai taip pat būtinas leidimas „android.permission.CAMERA“"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Leisti programai ar paslaugai sulaukti atgalinio skambinimo, kai atidaromas ar uždaromas fotoaparatas."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index f086662668f0..ba790a0714c0 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -435,23 +435,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"mainīt audio iestatījumus"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Ļauj lietotnei mainīt globālos audio iestatījumus, piemēram, skaļumu un izejai izmantoto skaļruni."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ierakstīt audio"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Šī lietotne var ierakstīt audio, izmantojot mikrofonu, kamēr lietotne tiek izmantota."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ierakstīt audio fonā"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Šī lietotne var jebkurā brīdī ierakstīt audio, izmantojot mikrofonu."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"Sūtīt komandas SIM kartei"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Ļauj lietotnei sūtīt komandas uz SIM karti. Tas ir ļoti bīstami!"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"noteikt fiziskās aktivitātes"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Šī lietotne var noteikt jūsu fiziskās aktivitātes."</string>
<string name="permlab_camera" msgid="6320282492904119413">"uzņemt attēlus un videoklipus"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Šī lietotne var uzņemt attēlus un ierakstīt videoklipus, izmantojot kameru, kamēr lietotne tiek izmantota."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"uzņemt attēlus un videoklipus fonā"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Šī lietotne var jebkurā brīdī uzņemt attēlus un ierakstīt videoklipus, izmantojot kameru."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Atļauja lietojumprogrammai vai pakalpojumam piekļūt sistēmas kamerām, lai uzņemtu attēlus un videoklipus"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Šī privileģētā vai sistēmas lietotne var jebkurā brīdī uzņemt attēlus un ierakstīt videoklipus, izmantojot sistēmas kameru. Lietotnei nepieciešama arī atļauja android.permission.CAMERA."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Atļaut lietojumprogrammai vai pakalpojumam saņemt atzvanus par kameras ierīču atvēršanu vai aizvēršanu"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index b57307c51457..c882cb1378e7 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"менува аудио поставки"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Овозможува апликацијата да ги менува глобалните аудио поставки, како што се јачината на звукот и кој звучник се користи за излез."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"снимај аудио"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Апликацијава може да снима аудио со микрофонот додека се користи апликацијата."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"снима аудио во заднината"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Апликацијава може да снима аудио со микрофонот во секое време."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"испраќање наредби до SIM-картичката"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Овозможува апликацијата да испраќа наредби до SIM картичката. Ова е многу опасно."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"препознавајте ја физичката активност"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Апликацијава може да ја препознава вашата физичка активност."</string>
<string name="permlab_camera" msgid="6320282492904119413">"снимај слики и видеа"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Апликацијава може да фотографира и снима видеа со камерата додека се користи апликацијата."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"снима слики и видеа во заднината"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Апликацијава може да фотографира и да снима видеа со камерата во секое време."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Дозволете апликацијата или услугата да пристапува до системските камери за да фотографира и да снима видеа"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Оваа привилегирана или системска апликација може да фотографира и да снима видеа со системската камера во секое време. Потребно е апликацијата да ја има и дозволата android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Дозволете апликацијатa или услугата да прима повратни повици за отворањето или затворањето на уредите со камера."</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index ce346c917f9a..fcf64c1933d4 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"നിങ്ങളുടെ ഓഡിയോ ക്രമീകരണങ്ങൾ മാറ്റുക"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"വോളിയവും ഔട്ട്പുട്ടിനായി ഉപയോഗിച്ച സ്‌പീക്കറും പോലുള്ള ആഗോള ഓഡിയോ ക്രമീകരണങ്ങൾ പരിഷ്‌ക്കരിക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ഓഡിയോ റെക്കോർഡ് ചെയ്യുക"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"ആപ്പ് ഉപയോഗത്തിലായിരിക്കുമ്പോൾ മൈക്രോഫോൺ ഉപയോഗിച്ച് ഓഡിയോ റെക്കോർഡ് ചെയ്യാൻ ഈ ആപ്പിന് കഴിയും."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"പശ്ചാത്തലത്തിൽ ഓഡിയോ റെക്കോർഡ് ചെയ്യുക"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"ഈ ആപ്പിന് ഏത് സമയത്തും മൈക്രോഫോൺ ഉപയോഗിച്ച് ഓഡിയോ റെക്കോർഡ് ചെയ്യാൻ കഴിയും."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM-ലേക്ക് കമാൻഡുകൾ അയയ്ക്കുക"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"സിമ്മിലേക്ക് കമാൻഡുകൾ അയയ്‌ക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഇത് വളരെ അപകടകരമാണ്."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"ശാരീരിക പ്രവർത്തനം തിരിച്ചറിയുക"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"നിങ്ങളുടെ ശാരീരിക പ്രവർത്തനം ഈ ആപ്പിന് തിരിച്ചറിയാനാവും."</string>
<string name="permlab_camera" msgid="6320282492904119413">"ചിത്രങ്ങളും വീഡിയോകളും എടുക്കുക"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"ആപ്പ് ഉപയോഗത്തിലായിരിക്കുമ്പോൾ ക്യാമറ ഉപയോഗിച്ച് ചിത്രങ്ങളെടുക്കാനും വീഡിയോകൾ റെക്കോർഡ് ചെയ്യാനും ഈ ആപ്പിന് കഴിയും."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"പശ്ചാത്തലത്തിൽ ചിത്രങ്ങളും വീഡിയോകളും എടുക്കുക"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"ഏതുസമയത്തും ക്യാമറ ഉപയോഗിച്ച് ചിത്രങ്ങൾ എടുക്കാനും വീഡിയോകൾ റെക്കോർഡ് ചെയ്യാനും ഈ ആപ്പിന് കഴിയും."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"ചിത്രങ്ങളും വീഡിയോകളും എടുക്കാൻ, സിസ്‌റ്റം ക്യാമറ ആക്‌സസ് ചെയ്യുന്നതിന് ആപ്പിനെയോ സേവനത്തെയോ അനുവദിക്കുക"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"സിസ്‌റ്റം ക്യാമറ ഉപയോഗിച്ച് ഏത് സമയത്തും ചിത്രങ്ങളെടുക്കാനും വീഡിയോകൾ റെക്കോർഡ് ചെയ്യാനും ഈ വിശേഷാധികാര അല്ലെങ്കിൽ സിസ്‌റ്റം ആപ്പിന് കഴിയും. ആപ്പിലും android.permission.CAMERA അനുമതി ഉണ്ടായിരിക്കണം"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"ക്യാമറയുള്ള ഉപകരണങ്ങൾ ഓണാക്കുന്നതിനെയോ അടയ്ക്കുന്നതിനെയോ കുറിച്ചുള്ള കോൾബാക്കുകൾ സ്വീകരിക്കാൻ ആപ്പിനെയോ സേവനത്തെയോ അനുവദിക്കുക."</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 313c4066cc9f..141824864086 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"Аудио тохиргоо солих"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Апп нь дууны хэмжээ, спикерын гаралтад ашиглагдах глобал аудио тохиргоог өөрчлөх боломжтой."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"аудио бичих"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Энэ аппыг ашиглаж байх үед энэ нь микрофон ашиглан аудио бичих боломжтой."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ард видео бичих"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Энэ апп ямар ч үед микрофон ашиглан аудио бичих боломжтой."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM картад тушаал илгээх"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Апп-д SIM рүү комманд илгээхийг зөвшөөрнө. Энэ маш аюултай."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"биеийн дасгал хөдөлгөөн таних"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Энэ апп таны биеийн дасгал хөдөлгөөнийг таних боломжтой."</string>
<string name="permlab_camera" msgid="6320282492904119413">"зураг авах болон видео бичих"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Энэ аппыг ашиглаж байх үед энэ нь камер ашиглан зураг авж, видео бичих боломжтой."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"ард зураг авж, видео хийх"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Энэ апп ямар ч үед камер ашиглан зураг авж, видео бичих боломжтой."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Видео болон зураг авахын тулд апп эсвэл үйлчилгээнд хандахыг системийн камерт зөвшөөрөх"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Энэ хамгаалагдсан эсвэл системийн апп нь системийн камер ашиглан ямар ч үед зураг авч, видео бичих боломжтой. Мөн түүнчлэн, апп нь android.permission.CAMERA-н зөвшөөрөлтэй байх шаардлагатай"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Аппликэйшн эсвэл үйлчилгээнд камерын төхөөрөмжүүдийг нээж эсвэл хааж байгаа тухай залгасан дуудлага хүлээн авахыг зөвшөөрөх."</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index effa6b6e0b35..3d2fbcb07af9 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"आपल्या ऑडिओ सेटिंग्ज बदला"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"व्हॉल्यूम आणि आउटपुटसाठी कोणता स्पीकर वापरला आहे यासारख्या समग्र ऑडिओ सेटिंग्ज सुधारित करण्यासाठी अ‍ॅप ला अनुमती देते."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ऑडिओ रेकॉर्ड"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"ॲप वापरात असताना, हे ॲप मायक्रोफोन वापरून ऑडिओ रेकॉर्ड करू शकते."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"बॅकग्राउंडमध्ये ऑडिओ रेकॉर्ड करा"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"हे ॲप मायक्रोफोन वापरून ऑडिओ कधीही रेकॉर्ड करू शकते."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"सिम वर कमांड पाठवा"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"अ‍ॅप ला सिम वर कमांड पाठविण्‍याची अनुमती देते. हे खूप धोकादायक असते."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"शारीरिक ॲक्टिव्हिटी ओळखा"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"हे अ‍ॅप तुमच्या शारीरिक ॲक्टिव्हिटी ओळखू शकते."</string>
<string name="permlab_camera" msgid="6320282492904119413">"चित्रे आणि व्हिडिओ घ्या"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"ॲप वापरात असताना, हे ॲप कॅमेरा वापरून फोटो काढू शकते आणि व्हिडिओ रेकॉर्ड करू शकते."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"बॅकग्राउंडमध्ये फोटो काढा आणि व्हिडिओ रेकॉर्ड करा"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"हे ॲप कॅमेरा वापरून कधीही फोटो काढू शकते आणि व्हिडिओ रेकॉर्ड करू शकते."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"फोटो आणि व्हिडिओ काढण्यासाठी ॲप्लिकेशन किंवा सेवेला सिस्टम कॅमेरे ॲक्सेस करण्याची अनुमती द्या"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"हे विशेषाधिकृत किंवा सिस्टम ॲप कधीही सिस्टम कॅमेरा वापरून फोटो आणि व्हिडिओ रेकॉर्ड करू शकते. ॲपकडे android.permission.CAMERA परवानगी असण्याचीदेखील आवश्यकता आहे"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"एखाद्या अ‍ॅप्लिकेशन किंवा सेवेला कॅमेरा डिव्हाइस सुरू किंवा बंद केल्याची कॉलबॅक मिळवण्याची अनुमती द्या."</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 5849c3698487..5c35ba13f599 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"tukar tetapan audio anda"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Membenarkan apl untuk mengubah suai tetapan audio global seperti kelantangan dan pembesar suara mana digunakan untuk output."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"rakam audio"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Aplikasi ini boleh merakam audio menggunakan mikrofon semasa apl sedang digunakan."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"rakam audio di latar"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Apl ini boleh merakam audio menggunakan mikrofon pada bila-bila masa."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"hantar perintah ke SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Membenarkan apl menghantar arahan kepada SIM. Ini amat berbahaya."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"camkan aktiviti fizikal"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Apl ini dapat mengecam aktiviti fizikal anda."</string>
<string name="permlab_camera" msgid="6320282492904119413">"ambil gambar dan video"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Apl ini boleh mengambil gambar dan merakam video menggunakan kamera semasa apl sedang digunakan."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"ambil gambar dan video di latar"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Apl ini boleh mengambil gambar dan merakam video menggunakan kamera pada bila-bila masa."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Benarkan aplikasi atau perkhidmatan mengakses kamera sistem untuk mengambil gambar dan video"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Apl terlindung atau apl sistem ini boleh mengambil gambar dan merakam video menggunakan kamera sistem pada bila-bila masa. Apl juga perlu mempunyai kebenaran android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Benarkan aplikasi atau perkhidmatan menerima panggilan balik tentang peranti kamera yang dibuka atau ditutup."</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index be8820824706..38f1aa8f8f6b 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"သင့်အသံအပြင်အဆင်အားပြောင်းခြင်း"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"အပလီကေးရှင်းအား အသံအတိုးအကျယ်နှင့် အထွက်ကို မည်သည့်စပီကာကို သုံးရန်စသည်ဖြင့် စက်တစ်ခုလုံးနှင့်ဆိုင်သော အသံဆိုင်ရာ ဆက်တင်များ ပြင်ဆင်ခွင့် ပြုရန်"</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"အသံဖမ်းခြင်း"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"ဤအက်ပ်ကို အသုံးပြုနေစဉ် ၎င်းက မိုက်ခရိုဖုန်းကို အသုံးပြု၍ အသံဖမ်းနိုင်သည်။"</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"နောက်ခံတွင် အသံဖမ်းပါ"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"ဤအက်ပ်သည် မိုက်ခရိုဖုန်းကို အသုံးပြု၍ အချိန်မရွေး အသံဖမ်းနိုင်သည်။"</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM ထံသို့ ညွှန်ကြားချက်များကို ပို့ပါ"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"အက်ပ်အား ဆင်းမ်ကဒ်ဆီသို့ အမိန့်များ ပေးပို့ခွင့် ပြုခြင်း။ ဤခွင့်ပြုမှုမှာ အန္တရာယ်အလွန် ရှိပါသည်။"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"ကိုယ်လက်လှုပ်ရှားမှုကို မှတ်သားပါ"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"ဤအက်ပ်က သင်၏ကိုယ်လက်လှုပ်ရှားမှုကို မှတ်သားနိုင်ပါသည်။"</string>
<string name="permlab_camera" msgid="6320282492904119413">"ဓါတ်ပုံနှင့်ဗွီဒီယိုရိုက်ခြင်း"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"ဤအက်ပ်ကို အသုံးပြုနေစဉ် ၎င်းက ကင်မရာကို အသုံးပြု၍ ဓာတ်ပုံနှင့် ဗီဒီယိုများကို ရိုက်ကူးနိုင်သည်။"</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"ဓာတ်ပုံနှင့် ဗီဒီယိုများကို နောက်ခံတွင် ရိုက်ကူးပါ"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"ဤအက်ပ်သည် ကင်မရာကို အသုံးပြု၍ ဓာတ်ပုံနှင့် ဗီဒီယိုများကို အချိန်မရွေး ရိုက်ကူးနိုင်သည်။"</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"ဓာတ်ပုံနှင့် ဗီဒီယိုများရိုက်ရန်အတွက် စနစ်ကင်မရာများကို အက်ပ် သို့မဟုတ် ဝန်‌ဆောင်မှုအား အသုံးပြုခွင့်ပေးခြင်း"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ဤခွင့်ပြုထားသည့် သို့မဟုတ် စနစ်အက်ပ်က စနစ်ကင်မရာအသုံးပြုပြီး ဓာတ်ပုံနှင့် ဗီဒီယိုများကို အချိန်မရွေး ရိုက်ကူးနိုင်သည်။ အက်ပ်ကလည်း android.permission.CAMERA ခွင့်ပြုချက် ရှိရပါမည်"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"ကင်မရာစက်များ ပွင့်နေခြင်း သို့မဟုတ် ပိတ်နေခြင်းနှင့် ပတ်သက်ပြီး ပြန်လည်ခေါ်ဆိုမှုများ ရယူရန် အပလီကေးရှင်း သို့မဟုတ် ဝန်ဆောင်မှုကို ခွင့်ပြုခြင်း။"</string>
@@ -1106,7 +1100,7 @@
<string name="cut" msgid="2561199725874745819">"ဖြတ်ရန်"</string>
<string name="copy" msgid="5472512047143665218">"ကူးရန်"</string>
<string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"ကလစ်ဘုတ်သို့ မိတ္တူကူးခြင်း မအောင်မြင်ပါ"</string>
- <string name="paste" msgid="461843306215520225">"Paste"</string>
+ <string name="paste" msgid="461843306215520225">"ကူးထည့်ရန်"</string>
<string name="paste_as_plain_text" msgid="7664800665823182587">"စာသားအတိုင်း ကူးထည့်ပါ"</string>
<string name="replace" msgid="7842675434546657444">"အစားထိုခြင်း"</string>
<string name="delete" msgid="1514113991712129054">"ဖျက်ရန်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index a18df1682e22..5b0a4ad1c124 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"endre lydinnstillinger"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Lar appen endre globale lydinnstillinger slik som volum og hvilken høyttaler som brukes for lydavspilling."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ta opp lyd"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Denne appen kan ta opp lyd med mikrofonen mens den er i bruk."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ta opp lyd i bakgrunnen"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Denne appen kan når som helst ta opp lyd med mikrofonen."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"sende kommandoer til SIM-kortet"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Lar appen sende kommandoer til SIM-kortet. Dette er veldig farlig."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"gjenkjenn fysisk aktivitet"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Denne appen kan gjenkjenne den fysiske aktiviteten din."</string>
<string name="permlab_camera" msgid="6320282492904119413">"ta bilder og videoer"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Denne appen kan ta bilder og spille inn videoer med kameraet mens den er i bruk."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"ta bilder og spille inn videoer i bakgrunnen"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Denne appen kan når som helst ta bilder og spille inn videoer med kameraet."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Gi en app eller tjeneste tilgang til systemkameraene for å ta bilder og spille inn videoer"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Denne privilegerte appen eller systemappen kan når som helst ta bilder og spille inn videoer med et systemkamera. Dette krever at appen også har tillatelsen android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Tillat at en app eller tjeneste mottar tilbakekallinger om kameraenheter som åpnes eller lukkes."</string>
@@ -1104,7 +1098,7 @@
<string name="elapsed_time_short_format_h_mm_ss" msgid="2302144714803345056">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="1532369154488982046">"Merk alt"</string>
<string name="cut" msgid="2561199725874745819">"Klipp ut"</string>
- <string name="copy" msgid="5472512047143665218">"Kopier"</string>
+ <string name="copy" msgid="5472512047143665218">"Kopiér"</string>
<string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"Kunne ikke kopiere til utklippstavlen"</string>
<string name="paste" msgid="461843306215520225">"Lim inn"</string>
<string name="paste_as_plain_text" msgid="7664800665823182587">"Lim inn som ren tekst"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 7b376ff2b32f..01ee79a9c6cf 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"तपाईँका अडियो सेटिङहरू परिवर्तन गर्नुहोस्"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"एपलाई ग्लोबल अडियो सेटिङहरू परिमार्जन गर्न अनुमति दिन्छ, जस्तै भोल्युम र आउटपुटको लागि कुन स्पिकर प्रयोग गर्ने।"</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"अडियो रेकर्ड गर्नुहोस्"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"यो एप प्रयोग भइरहेका बेला यसले माइक्रोफोन प्रयोग गरेर अडियो रेकर्ड गर्न सक्छ।"</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ब्याकग्राउन्डमा अडियो रेकर्ड गर्नुहोस्"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"यो एपले जुनसुकै बेला माइक्रोफोन प्रयोग गरी अडियो रेकर्ड गर्न सक्छ।"</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM मा आदेशहरू पठाउन दिनुहोस्"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"SIM लाई आदेश पठाउन एपलाई अनुमति दिन्छ। यो निकै खतरनाक हुन्छ।"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"शारीरिक गतिविधि पहिचान गर्नुहोस्‌"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"यो अनुप्रयोगले तपाईंको शारीरिक गतिविधिको पहिचान गर्न सक्छ।"</string>
<string name="permlab_camera" msgid="6320282492904119413">"फोटोहरू र भिडियोहरू लिनुहोस्।"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"यो एप प्रयोग भइरहेका बेला यसले क्यामेरा प्रयोग गरेर फोटो खिच्न तथा भिडियोहरू रेकर्ड गर्न सक्छ।"</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"ब्याकग्राउन्डमा फोटो खिच्नुहोस् तथा भिडियो रेकर्ड गर्नुहोस्"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"यो एपले जुनसुकै बेला क्यामेराको प्रयोग गरी फोटो खिच्न र भिडियो रेकर्ड गर्न सक्छ।"</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"एप वा सेवालाई फोटो र भिडियो खिच्न प्रणालीका क्यामेराहरूमाथि पहुँच राख्न दिनुहोस्"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"प्रणालीको यस विशेषाधिकार प्राप्त अनुप्रयोगले जुनसुकै बेला प्रणालीको क्यामेरा प्रयोग गरी फोटो खिच्न र भिडियो रेकर्ड गर्न सक्छ। अनुप्रयोगसँग पनि android.permission.CAMERA प्रयोग गर्ने अनुमति हुनु पर्छ"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"कुनै एप वा सेवालाई खोलिँदै वा बन्द गरिँदै गरेका क्यामेरा यन्त्रहरूका बारेमा कलब्याक प्राप्त गर्ने अनुमति दिनुहोस्।"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index d601905d8f10..17e988e4a344 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"je audio-instellingen wijzigen"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Hiermee kan de app algemene audio-instellingen wijzigen zoals het volume en welke luidspreker wordt gebruikt voor de uitvoer."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"audio opnemen"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Deze app kan audio opnemen met de microfoon als de app wordt gebruikt."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"audio opnemen op de achtergrond"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Deze app kan altijd audio opnemen met de microfoon."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"opdrachten verzenden naar de simkaart"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Hiermee kan de app opdrachten verzenden naar de simkaart. Dit is erg gevaarlijk."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"fysieke activiteit herkennen"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Deze app kan je fysieke activiteit herkennen."</string>
<string name="permlab_camera" msgid="6320282492904119413">"foto\'s en video\'s maken"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Deze app kan foto\'s maken en video\'s opnemen met de camera als de app wordt gebruikt."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"foto\'s maken en video\'s opnemen op de achtergrond"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Deze app kan altijd foto\'s maken en video\'s opnemen met de camera."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Een app of service toegang tot systeemcamera\'s geven om foto\'s en video\'s te maken"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Deze gemachtigde app of systeem-app kan op elk gewenst moment foto\'s maken en video\'s opnemen met een systeemcamera. De app moet ook het recht android.permission.CAMERA hebben."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Een app of service toestaan callbacks te ontvangen over camera-apparaten die worden geopend of gesloten."</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index f3a225a6c629..0f10cde4b9cb 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"ଆପଣଙ୍କ ଅଡିଓ ସେଟିଙ୍ଗକୁ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"ଆପ୍‌କୁ ଗ୍ଲୋବାଲ୍ ଅଡିଓ ସେଟିଙ୍ଗ, ଯେପରିକି ଭଲ୍ୟୁମ୍‌କୁ ସଂଶୋଧିତ କରିବାକୁ ଏବଂ ଆଉଟପୁଟ୍ ପାଇଁ ସ୍ପିକର୍‌ ବ୍ୟବହାର କରିବାକୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ଅଡିଓ ରେକର୍ଡ କରନ୍ତୁ"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"ଆପକୁ ବ୍ୟବହାର କରାଯାଉଥିବା ସମୟରେ ଏହା ମାଇକ୍ରୋଫୋନକୁ ବ୍ୟବହାର କରି ଅଡିଓ ରେକର୍ଡ କରିପାରିବ।"</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ପୃଷ୍ଠପଟରେ ଅଡିଓ ରେକର୍ଡ କରନ୍ତୁ"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"ଏହି ଆପ୍ ଯେ କୌଣସି ସମୟରେ ମାଇକ୍ରୋଫୋନକୁ ବ୍ୟବହାର କରି ଅଡିଓ ରେକର୍ଡ କରିପାରିବ।"</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"SIMକୁ କମାଣ୍ଡ ପଠାନ୍ତୁ"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"SIMକୁ କମାଣ୍ଡ ପଠାଇବା ପାଇଁ ଆପ୍‍କୁ ଅନୁମତି ଦେଇଥାଏ। ଏହା ବହୁତ ବିପଦପୂର୍ଣ୍ଣ।"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"ଶାରୀରିକ ଗତିବିଧି ଚିହ୍ନଟକରେ"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"ଏହି ଆପ୍‍ଣ ଆପଣଙ୍କ ଶାରୀରିକ ଗତିବିଧିକୁ ଚିହ୍ନଟ କରିପାରେ"</string>
<string name="permlab_camera" msgid="6320282492904119413">"ଫଟୋ ଓ ଭିଡିଓଗୁଡ଼ିକୁ ନିଅନ୍ତୁ"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"ଆପକୁ ବ୍ୟବହାର କରାଯାଉଥିବା ସମୟରେ ଏହା କ୍ୟାମେରାକୁ ବ୍ୟବହାର କରି ଛବି ନେଇପାରିବ ଏବଂ ଭିଡିଓ ରେକର୍ଡ କରିପାରିବ।"</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"ପୃଷ୍ଠପଟରେ ଛବି ନିଅନ୍ତୁ ଏବଂ ଭିଡିଓ ରେକର୍ଡ କରନ୍ତୁ"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"କ୍ୟାମେରାକୁ ବ୍ୟବହାର କରି ଯେ କୌଣସି ସମୟରେ ଏହି ଆପ୍ ଛବି ନେଇପାରିବ ଏବଂ ଭିଡିଓ ରେକର୍ଡ କରିପାରିବ।"</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"ଛବି ଏବଂ ଭିଡିଓଗୁଡ଼ିକୁ ନେବା ପାଇଁ ସିଷ୍ଟମ୍ କ୍ୟାମେରା‌ଗୁଡ଼ିକୁ କୌଣସି ଆପ୍ଲିକେସନ୍ କିମ୍ବା ସେବା ଆକ୍ସେସ୍ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ବିଶେଷ ଅଧିକାର ଥିବା ଏହି ଆପ୍ କିମ୍ବା ସିଷ୍ଟମ୍ ଆପ୍ ଯେ କୌଣସି ସମୟରେ ଏକ ସିଷ୍ଟମ୍ କ୍ୟାମେରା ବ୍ୟବହାର କରି ଛବି ଉଠାଇପାରିବ ଏବଂ ଭିଡିଓ ରେକର୍ଡ କରିପାରିବ। ଆପରେ ମଧ୍ୟ android.permission.CAMERA ଅନୁମତି ଆବଶ୍ୟକ"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"କ୍ୟାମେରା ଡିଭାଇସଗୁଡ଼ିକ ଖୋଲିବା କିମ୍ବା ବନ୍ଦ କରିବା ବିଷୟରେ କଲବ୍ୟାକଗୁଡ଼ିକ ପାଇବାକୁ ଏକ ଆପ୍ଲିକେସନ୍ କିମ୍ବା ସେବାକୁ ଅନୁମତି ଦିଅନ୍ତୁ।"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index ca8522b032de..d62651326645 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -438,23 +438,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"zmienianie ustawień audio"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Pozwala aplikacji na modyfikowanie globalnych ustawień dźwięku, takich jak głośność oraz urządzenie wyjściowe."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"nagrywanie dźwięku"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Ta aplikacja może nagrywać dźwięk przy użyciu mikrofonu, gdy jest używana."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"nagrywanie dźwięku w tle"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Ta aplikacja może w dowolnym momencie nagrywać dźwięk przy użyciu mikrofonu."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"wysyłanie poleceń do karty SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Pozwala aplikacji na wysyłanie poleceń do karty SIM. To bardzo niebezpieczne."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"rozpoznawanie aktywności fizycznej"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Ta aplikacja może rozpoznawać Twoją aktywność fizyczną."</string>
<string name="permlab_camera" msgid="6320282492904119413">"wykonywanie zdjęć i filmów wideo"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Ta aplikacja może robić zdjęcia i nagrywać filmy przy użyciu aparatu, gdy jest używana."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"robienie zdjęć i nagrywanie filmów w tle"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Ta aplikacja może w dowolnym momencie robić zdjęcia i nagrywać filmy przy użyciu aparatu."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Zezwól na dostęp aplikacji lub usługi do aparatów systemu i robienie zdjęć oraz nagrywanie filmów"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ta aplikacja systemowa z podwyższonymi uprawnieniami może w dowolnym momencie robić zdjęcia i nagrywać filmy przy użyciu aparatu systemowego. Wymaga przyznania uprawnień android.permission.CAMERA również aplikacji."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Zezwól na dostęp aplikacji lub usługi na otrzymywanie wywoływania zwrotnego o urządzeniach z aparatem, kiedy są one uruchamiane lub zamykane."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index c318a24c3bb8..6862001b874e 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"alterar as suas definições de áudio"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permite que a app modifique definições de áudio globais, tais como o volume e qual o altifalante utilizado para a saída de som."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"gravar áudio"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Esta app pode gravar áudio através do microfone enquanto estiver a ser utilizada."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"gravar áudio em segundo plano"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Esta app pode gravar áudio através do microfone em qualquer altura."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"enviar comandos para o SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Permite que a app envie comandos para o SIM. Esta ação é muito perigosa."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"reconhecer a atividade física"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Esta app consegue reconhecer a sua atividade física."</string>
<string name="permlab_camera" msgid="6320282492904119413">"tirar fotos e vídeos"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Esta app pode tirar fotos e gravar vídeos através da câmara enquanto estiver a ser utilizada."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"tirar fotos e gravar vídeos em segundo plano"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Esta app pode tirar fotos e gravar vídeos através da câmara em qualquer altura."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Permitir que uma app ou um serviço aceda às câmaras do sistema para tirar fotos e vídeos"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Esta app do sistema ou privilegiada pode tirar fotos e gravar vídeos através de uma câmara do sistema em qualquer altura. Também necessita da autorização android.permission.CAMERA para a app."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permitir que uma app ou um serviço receba chamadas de retorno sobre dispositivos de câmara que estão a ser abertos ou fechados"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 0efa74ac97cf..f9e608fd0b8e 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -435,23 +435,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"modificare setări audio"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Permite aplicației să modifice setările audio globale, cum ar fi volumul și difuzorul care este utilizat pentru ieșire."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"înregistreze sunet"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Această aplicație poate să înregistreze conținut audio folosind microfonul când este în uz."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"să înregistreze conținut audio în fundal"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Această aplicație poate înregistra conținut audio folosind microfonul oricând."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"să trimită comenzi către SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Permite aplicației să trimită comenzi pe cardul SIM. Această permisiune este foarte periculoasă."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"recunoașterea activității fizice"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Această aplicație vă poate recunoaște activitatea fizică."</string>
<string name="permlab_camera" msgid="6320282492904119413">"realizarea de fotografii și videoclipuri"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Această aplicație poate să fotografieze și să înregistreze videoclipuri folosind camera foto când este în uz."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"să fotografieze și să înregistreze videoclipuri în fundal"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Această aplicație poate să fotografieze și să înregistreze videoclipuri folosind camera foto oricând."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Permiteți unei aplicații sau unui serviciu accesul la camerele de sistem, ca să fotografieze și să înregistreze videoclipuri"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Această aplicație de sistem privilegiată poate să fotografieze și să înregistreze videoclipuri folosind o cameră de sistem în orice moment. Necesită și permisiunea android.permission.CAMERA pentru aplicație"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Permiteți unei aplicații sau unui serviciu să primească apeluri inverse atunci când sunt deschise sau închise dispozitive cu cameră."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index d0749601d697..be24770dcc2d 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -438,23 +438,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"Изменение настроек аудио"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Приложение сможет изменять системные настройки звука, например уровень громкости и активный динамик."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"Запись аудио"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Когда приложение используется, оно может записывать аудио с помощью микрофона."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"Записывать аудио в фоновом режиме"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Приложение может в любое время записывать аудио с помощью микрофона."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"Отправка команд SIM-карте"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Приложение сможет отправлять команды SIM-карте (данное разрешение представляет большую угрозу)."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"распознавать физическую активность"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Приложение может распознавать физическую активность."</string>
<string name="permlab_camera" msgid="6320282492904119413">"Фото- и видеосъемка"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Когда приложение используется, оно может делать фотографии и снимать видео с помощью камеры."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"Делать фотографии и снимать видео в фоновом режиме"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Приложение может в любое время делать фотографии и снимать видео с помощью камеры."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Доступ приложения или сервиса к системным настройкам камеры, позволяющим снимать фото и видео"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Это привилегированное или системное приложение может в любое время делать фотографии и записывать видео с помощью камеры. Для этого приложению также требуется разрешение android.permission.CAMERA."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Разрешить приложению или сервису получать обратные вызовы при открытии и закрытии камер"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 6d88677c8a84..c23e4757805b 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"ඔබගේ ශ්‍රව්‍ය සැකසීම් වෙනස් කරන්න"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"ශබ්දය ආදී ගෝලීය ශබ්ද සැකසීම් වෙනස් කිරීමට සහ ප්‍රතිදානය සඳහා භාවිත කරන්නේ කුමන නාදකය දැයි තේරීමට යෙදුමට අවසර දෙන්න."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ශබ්ද පටිගත කරන්න"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"මෙම යෙදුමට එය භාවිතයෙහි ඇති අතරතුර මයික්‍රෆෝනය භාවිත කර ඕඩියෝ පටිගත කිරීමට හැකිය."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"පසුබිමෙහි ඕඩියෝ පටිගත කරන්න"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"මෙම යෙදුමට ඕනෑම වේලාවක මයික්‍රෆෝනය භාවිත කර ඕඩියෝ පටිගත කිරීමට හැකිය."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM වෙත විධාන යැවීම"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"SIM වෙත විධාන ගෙන යාමට යෙදුමට අවසර දෙයි. මෙය ඉතා භයානක වේ."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"ශාරීරික ක්‍රියාකාරකම හඳුනා ගන්න"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"මෙම යෙදුමට ඔබේ ශාරීරික ක්‍රියාකාරකම හඳුනා ගැනීමට නොහැකිය"</string>
<string name="permlab_camera" msgid="6320282492904119413">"පින්තූර සහ වීඩියෝ ගන්න"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"මෙම යෙදුමට එය භාවිතයෙහි ඇති අතරතුර කැමරාව භාවිත කර පින්තූර ගැනීමට සහ වීඩියෝ පටිගත කිරීමට හැකිය."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"පසුබිමෙහි පින්තූර සහ වීඩියෝ ගන්න"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"මෙම යෙදුමට ඕනෑම වේලාවක කැමරාව භාවිත කර පින්තූර ගැනීමට සහ වීඩියෝ පටිගත කිරීමට හැකිය."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"පින්තූර සහ වීඩියෝ ගැනීමට පද්ධති කැමරාවලට යෙදුමකට හෝ සේවාවකට ප්‍රවේශය ඉඩ දෙන්න"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"මෙම වරප්‍රසාද ලත් හෝ පද්ධති යෙදුමට ඕනෑම වේලාවක පද්ධති කැමරාව භාවිත කර පින්තූර ගැනීමට සහ වීඩියෝ පටිගත කිරීමට හැකිය. යෙදුම විසින් රඳවා තබා ගැනීමට android.permission.CAMERA ප්‍රවේශයද අවශ්‍ය වේ"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"විවෘත වෙමින් හෝ වැසෙමින් පවතින කැමරා උපාංග පිළිබඳ පසු ඇමතුම් ලබා ගැනීමට යෙදුමකට හෝ සේවාවකට ඉඩ දෙන්න."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 5d7f8f64143c..980a9451bff3 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -438,23 +438,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"meniť nastavenia zvuku"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Umožňuje aplikácii upraviť globálne nastavenia zvuku, ako je hlasitosť, alebo určiť, z ktorého reproduktora bude zvuk vychádzať."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"nahrávať zvuk"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Táto aplikácia môže nahrávať zvuk pomocou mikrofónu, keď ju používate."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"nahrávanie zvuku na pozadí"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Táto aplikácia môže kedykoľvek nahrávať zvuk pomocou mikrofónu."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"posielanie príkazov do SIM karty"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Umožňuje aplikácii odosielať príkazy na SIM kartu. Toto je veľmi nebezpečné povolenie."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"rozpoznávanie fyzickej aktivity"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Táto aplikácia dokáže rozpoznať vašu fyzickú aktivitu."</string>
<string name="permlab_camera" msgid="6320282492904119413">"fotiť a nakrúcať videá"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Táto aplikácia môže fotiť a nahrávať videá pomocou fotoaparátu, keď ju používate."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"fotenie a nahrávanie videí na pozadí"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Táto aplikácia môže kedykoľvek fotiť a nahrávať videá pomocou fotoaparátu."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Povoľte aplikácii alebo službe prístup k fotoaparátom systému na snímanie fotiek a videí"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Táto oprávnená alebo systémová aplikácia môže kedykoľvek fotiť a nahrávať videá fotoaparátom systému. Aplikácia musí mať tiež povolenie android.permission.CAMERA."</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Povoliť aplikácii alebo službe prijímať spätné volanie, keď sú zariadenia s kamerou otvorené alebo zatvorené."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 7e6e300776f3..573a082e0439 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -438,23 +438,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"spreminjanje nastavitev zvoka"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Aplikaciji omogoča spreminjanje splošnih zvočnih nastavitev, na primer glasnost in kateri zvočnik se uporablja."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"snemanje zvoka"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Ta aplikacija lahko uporablja mikrofon za snemanje zvoka med uporabo aplikacije."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"snemanje zvoka v ozadju"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Ta aplikacija lahko poljubno uporablja mikrofon za snemanje zvoka."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"pošiljanje ukazov na kartico SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Aplikaciji dovoli pošiljanje ukazov kartici SIM. To je lahko zelo nevarno."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"prepoznavanje telesne dejavnosti"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Ta aplikacija lahko prepoznava vašo telesno dejavnost."</string>
<string name="permlab_camera" msgid="6320282492904119413">"fotografiranje in snemanje videoposnetkov"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Ta aplikacija lahko uporablja fotoaparat za snemanje fotografij in videoposnetkov med uporabo aplikacije."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"snemanje fotografij in videoposnetkov v ozadju"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Ta aplikacija lahko poljubno uporablja fotoaparat za snemanje fotografij in videoposnetkov."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Aplikaciji ali storitvi dovoli dostop do vgrajenih fotoaparatov za snemanje fotografij in videoposnetkov"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ta prednostna ali sistemska aplikacija lahko z vgrajenim fotoaparatom kadar koli snema fotografije in videoposnetke. Aplikacija mora imeti omogočeno tudi dovoljenje android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Aplikaciji ali storitvi dovoli prejemanje povratnih klicev o odpiranju ali zapiranju naprav s fotoaparati."</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index f6ef6e9bbfbe..f6f3594d0195 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"ndrysho cilësimet e audios"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Lejon aplikacionin të modifikojë cilësimet globale të audios siç është volumi dhe se cili altoparlant përdoret për daljen."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"regjistro audio"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Ky aplikacion mund të regjistrojë audion duke përdorur mikrofonin kur aplikacioni është në përdorim."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"të regjistrojë audion në sfond"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Ky aplikacion mund të regjistrojë audion me mikrofonin në çdo kohë."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"dërgo komanda te karta SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Lejon aplikacionin t\'i dërgojë komanda kartës SIM. Kjo është shumë e rrezikshme."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"njih aktivitetin fizik"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Ky aplikacion mund të njohë aktivitetin tënd fizik."</string>
<string name="permlab_camera" msgid="6320282492904119413">"bëj fotografi dhe video"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Ky aplikacion mund të nxjerrë fotografi dhe të regjistrojë video duke përdorur kamerën kur aplikacioni është në përdorim."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"të nxjerrë fotografi dhe video në sfond"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Ky aplikacion mund të nxjerrë fotografi dhe të regjistrojë video me kamerën tënde në çdo kohë."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Lejo një aplikacion ose shërbim të ketë qasje në kamerat e sistemit për të shkrepur fotografi dhe regjistruar video"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ky aplikacion sistemi ose i privilegjuar mund të nxjerrë fotografi dhe të regjistrojë video duke përdorur një kamerë në çdo moment. Kërkon që autorizimi i android.permission.CAMERA të mbahet edhe nga aplikacioni"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Lejo që një aplikacion ose shërbim të marrë telefonata mbrapsht për pajisjet e kamerës që hapen ose mbyllen."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index d799ae90afcf..366d29b15c93 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -435,23 +435,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"промена аудио подешавања"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Дозвољава апликацији да мења глобална аудио подешавања као што су јачина звука и избор звучника који се користи као излаз."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"снимање аудио записа"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Ова апликација може да снима звук помоћу микрофона док се апликација користи."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"да снима звук у позадини"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Ова апликација може да снима звук помоћу микрофона у било ком тренутку."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"слање команди на SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Омогућава апликацији да шаље команде SIM картици. То је веома опасно."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"препознавање физичких активности"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Ова апликација може да препозна физичке активности."</string>
<string name="permlab_camera" msgid="6320282492904119413">"снимање фотографија и видео снимака"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Ова апликација може да снима слике и видео снимке помоћу камере док се апликација користи."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"да снима слике и видео снимке у позадини"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Ова апликација може да снима фотографије и видео снимке помоћу камере у било ком тренутку."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Дозволите некој апликацији или услузи да приступа камерама система да би снимала слике и видео снимке"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ова привилегована системска апликација може да снима слике и видео снимке помоћу камере система у било ком тренутку. Апликација треба да има и дозволу android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Дозволите апликацији или услузи да добија повратне позиве о отварању или затварању уређаја са камером."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 318f5a811672..988fb9392025 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"ändra dina ljudinställningar"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Tillåter att appen ändrar globala ljudinställningar som volym och vilken högtalarutgång som används."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"spela in ljud"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Appen kan ta spela in ljud med mikrofonen när appen används."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"spela in ljud i bakgrunden"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Appen kan spela in ljud med mikrofonen när som helst."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"skicka kommandon till SIM-kortet"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Tillåter att appen skickar kommandon till SIM-kortet. Detta är mycket farligt."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"känn igen fysisk aktivitet"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Den här appen kan känna igen fysisk aktivitet."</string>
<string name="permlab_camera" msgid="6320282492904119413">"ta bilder och spela in videoklipp"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Appen kan ta bilder och spela in video med kameran när appen används."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"ta bilder och spela in video i bakgrunden"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Appen kan ta bilder och spela in video med kameran när som helst."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Ge en app eller tjänst behörighet att ta bilder och spela in videor med systemets kameror"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Denna systemapp med särskild behörighet kan ta bilder och spela in videor med systemets kamera när som helst. Appen måste även ha behörigheten android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Tillåt att en app eller tjänst får återanrop när en kameraenhet öppnas eller stängs."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index a59499f8bc36..fd390d80f76a 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"badilisha mipangilio yako ya sauti"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Inaruhusu programu kurekebisha mipangilio ya sauti kila mahali kama vile sauti na ni kipaza sauti kipi ambacho kinatumika kwa kutoa."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"kurekodi sauti"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Programu hii inaweza kurekodi sauti kwa kutumia maikrofoni wakati programu inatumika."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"rekodi sauti chinichini"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Programu hii inaweza kurekodi sauti kwa kutumia maikrofoni wakati wowote."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"tuma amri kwenye SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Huruhusu programu kutuma amri kwa SIM. Hii ni hatari sana."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"itambue shughuli unazofanya"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Programu hii inaweza kutambua shughuli unazofanya."</string>
<string name="permlab_camera" msgid="6320282492904119413">"Kupiga picha na kurekodi video"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Programu hii inaweza kupiga picha na kurekodi video kwa kutumia kamera wakati programu inatumika."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"piga picha na urekodi video chinichini"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Programu hii inaweza kupiga picha na kurekodi video kwa kutumia kamera wakati wowote."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Ruhusu programu au huduma ifikie kamera za mfumo ili ipige picha na irekodi video"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Programu hii ya mfumo au inayopendelewa inaweza kupiga picha na kurekodi video ikitumia kamera ya mfumo wakati wowote. Inahitaji ruhusa ya android.permission.CAMERA iwepo kwenye programu pia"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Ruhusu programu au huduma ipokee simu zinazopigwa tena kuhusu vifaa vya kamera kufunguliwa au kufungwa."</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 49e6c7c3ba0a..c764a205fe59 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"எனது ஆடியோ அமைப்புகளை மாற்றுதல்"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"ஒலியளவு மற்றும் வெளியீட்டிற்கு ஸ்பீக்கர்கள் பயன்படுத்தப்படுவது போன்ற ஒட்டுமொத்த ஆடியோ அமைப்புகளைக் கட்டுப்படுத்தப் ஆப்ஸை அனுமதிக்கிறது."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ஆடியோவைப் பதிவுசெய்தல்"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"இந்த ஆப்ஸ் உபயோகத்தில் இருக்கும்போதே இதனால் மைக்ரோஃபோனைப் பயன்படுத்தி ஆடியோவை ரெக்கார்டு செய்ய முடியும்."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"பின்புலத்தில் ஆடியோ ரெக்கார்டு செய்தல்"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"இந்த ஆப்ஸால் எப்போது வேண்டுமானாலும் மைக்ரோஃபோனைப் பயன்படுத்தி ஆடியோவை ரெக்கார்டு செய்ய முடியும்."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"கட்டளைகளை சிம்மிற்கு அனுப்புதல்"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"சிம் க்குக் கட்டளைகளை அனுப்ப ஆப்ஸை அனுமதிக்கிறது. இது மிகவும் ஆபத்தானதாகும்."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"உடல் செயல்பாட்டைக் கண்டறிதல்"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"உங்கள் உடல் செயல்பாட்டை இந்த ஆப்ஸால் கண்டறிய முடியும்."</string>
<string name="permlab_camera" msgid="6320282492904119413">"படங்கள் மற்றும் வீடியோக்களை எடுத்தல்"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"இந்த ஆப்ஸ் உபயோகத்தில் இருக்கும்போதே இதனால் கேமராவைப் பயன்படுத்தி படங்கள் எடுக்கவும் வீடியோக்களை ரெக்கார்டு செய்யவும் முடியும்."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"பின்புலத்தில் படங்களையும் வீடியோக்களையும் எடுத்தல்"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"இந்த ஆப்ஸால் எப்போது வேண்டுமானாலும் கேமராவைப் பயன்படுத்தி படங்கள் எடுக்கவும் வீடியோக்களை ரெக்கார்டு செய்யவும் முடியும்."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"படங்களையும் வீடியோக்களையும் எடுப்பதற்கு சிஸ்டம் கேமராக்களை அணுக ஆப்ஸையோ சேவையையோ அனுமதி"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"இந்த முன்னுரிமை பெற்ற அல்லது சிஸ்டம் ஆப்ஸால் சிஸ்டம் கேமராவைப் பயன்படுத்தி எப்போது வேண்டுமானாலும் படங்களை எடுக்கவோ வீடியோக்களை ரெக்கார்டு செய்யவோ முடியும். android.permission.CAMERA அனுமதியும் ஆப்ஸிற்குத் தேவை"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"கேமரா சாதனங்கள் திறக்கப்படும்போதோ மூடப்படும்போதோ அது குறித்த கால்பேக்குகளைப் பெற ஒரு ஆப்ஸையோ சேவையையோ அனுமதிக்கவும்."</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index caaf8a90e1b2..23292a2adc76 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"మీ ఆడియో సెట్టింగ్‌లను మార్చడం"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"వాల్యూమ్ మరియు అవుట్‌పుట్ కోసం ఉపయోగించాల్సిన స్పీకర్ వంటి సార్వజనీన ఆడియో సెట్టింగ్‌లను సవరించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ఆడియోను రికార్డ్ చేయడం"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"యాప్ ఉపయోగంలో ఉన్నపుడు మైక్రోఫోన్‌ను ఉపయోగించి ఈ యాప్, ఆడియోను రికార్డ్ చేయగలదు."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"బ్యాక్‌గ్రౌండ్‌లో ఆడియోను రికార్డ్ చేయగలదు"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"మైక్రోఫోన్‌ను ఉపయోగించి ఈ యాప్ ఎప్పుడైనా ఆడియోను రికార్డ్ చేయగలదు."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"SIMకి ఆదేశాలను పంపడం"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"సిమ్‌కు ఆదేశాలను పంపడానికి అనువర్తనాన్ని అనుమతిస్తుంది. ఇది చాలా ప్రమాదకరం."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"భౌతిక కార్యాకలాపాన్ని గుర్తించండి"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"ఈ యాప్ మీ భౌతిక కార్యాకలాపాన్ని గుర్తించగలదు."</string>
<string name="permlab_camera" msgid="6320282492904119413">"చిత్రాలు మరియు వీడియోలు తీయడం"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"యాప్ ఉపయోగంలో ఉన్నపుడు కెమెరాను ఉపయోగించి ఈ యాప్ ఎప్పుడైనా ఫోటోలను తీయగలదు, వీడియోలను రికార్డ్ చేయగలదు."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"బ్యాక్‌గ్రౌండ్‌లో ఫోటోలు, వీడియోలను తీయగలదు"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"కెమెరాను ఉపయోగించి ఈ యాప్ ఎప్పుడైనా ఫోటోలను తీయగలదు, వీడియోలను రికార్డ్ చేయగలదు."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"ఫోటోలు, వీడియోలు తీయడానికి సిస్టమ్ కెమెరాలకు యాప్, లేదా సేవా యాక్సెస్‌ను అనుమతించండి"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"ఈ విశేష లేదా సిస్టమ్ యాప్ ఎప్పుడైనా సిస్టమ్ కెమెరాను ఉపయోగించి ఫోటోలు తీయగలదు, వీడియోలను రికార్డ్ చేయగలదు. యాప్‌కు android.permission.CAMERA అనుమతి ఇవ్వడం కూడా అవసరం"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"కెమెరా పరికరాలు తెరుచుకుంటున్నప్పుడు లేదా మూసుకుంటున్నప్పుడు కాల్‌బ్యాక్‌లను స్వీకరించడానికి యాప్‌ను లేదా సర్వీస్‌ను అనుమతించండి."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 8c1917f49a69..d5d21c633d0a 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"เปลี่ยนการตั้งค่าเสียงของคุณ"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"อนุญาตให้แอปพลิเคชันปรับเปลี่ยนการตั้งค่าเสียงทั้งหมดได้ เช่น ระดับเสียงและลำโพงที่จะใช้งาน"</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"บันทึกเสียง"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"แอปนี้บันทึกเสียงด้วยไมโครโฟนขณะที่มีการใช้แอปได้"</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"บันทึกเสียงในเบื้องหลัง"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"แอปนี้บันทึกเสียงด้วยไมโครโฟนได้ทุกเมื่อ"</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"ส่งคำสั่งไปยังซิม"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"อนุญาตให้แอปส่งคำสั่งไปยัง SIM ซึ่งอันตรายมาก"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"จดจำกิจกรรมการเคลื่อนไหวร่างกาย"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"แอปนี้จดจำกิจกรรมการเคลื่อนไหวร่างกายของคุณได้"</string>
<string name="permlab_camera" msgid="6320282492904119413">"ถ่ายภาพและวิดีโอ"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"แอปนี้ถ่ายภาพและวิดีโอด้วยกล้องขณะที่มีการใช้แอปได้"</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"ถ่ายภาพและวิดีโอในเบื้องหลัง"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"แอปนี้ถ่ายภาพและวิดีโอด้วยกล้องได้ทุกเมื่อ"</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"อนุญาตให้แอปพลิเคชันหรือบริการเข้าถึงกล้องของระบบเพื่อถ่ายภาพและวิดีโอ"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"แอปของระบบหรือที่ได้รับสิทธิ์นี้จะถ่ายภาพและบันทึกวิดีโอโดยใช้กล้องของระบบได้ทุกเมื่อ แอปต้องมีสิทธิ์ android.permission.CAMERA ด้วย"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"อนุญาตให้แอปพลิเคชันหรือบริการได้รับโค้ดเรียกกลับเมื่อมีการเปิดหรือปิดอุปกรณ์กล้อง"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index af0073b3aa9e..f53851d74ff9 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"baguhin ang mga setting ng iyong audio"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Pinapayagan ang app na baguhin ang mga pandaigdigang setting ng audio gaya ng volume at kung aling speaker ang ginagamit para sa output."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"mag-record ng audio"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Makakapag-record ng audio ang app na ito gamit ang mikropono habang ginagamit ang app."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"mag-record ng audio sa background"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Makakapag-record ng audio ang app na ito gamit ang mikropono anumang oras."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"magpadala ng mga command sa SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Pinapahintulutang magpadala ang app ng mga command sa SIM. Napakapanganib nito."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"tukuyin ang pisikal na aktibidad"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Matutukoy ng app na ito ang iyong pisikal na aktibidad."</string>
<string name="permlab_camera" msgid="6320282492904119413">"kumuha ng mga larawan at video"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Makakakuha ng mga larawan at makakapag-record ng mga video ang app na ito gamit ang camera habang ginagamit ang app."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"kumuha ng mga larawan at video sa background"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Makakakuha ng mga larawan at makakapag-record ng mga video ang app na ito gamit ang camera anumang oras."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Bigyan ang isang application o serbisyo ng access sa mga camera ng system para kumuha ng mga larawan at video"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ang may pribilehiyong app o system app na ito ay makakakuha ng mga larawan at makakapag-record ng mga video gamit ang isang camera ng system anumang oras. Kinakailangang may android.permission.CAMERA na pahintulot din ang app"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Payagan ang isang application o serbisyo na makatanggap ng mga callback tungkol sa pagbubukas o pagsasara ng mga camera device."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index c0b28310dde6..5aa336e9b554 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"ses ayarlarınızı değiştirin"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Uygulamaya ses düzeyi ve ses çıkışı için kullanılan hoparlör gibi genel ses ayarlarını değiştirme izni verir."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ses kaydet"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Bu uygulama, kullanıldığı sırada mikrofonu kullanarak ses kaydedebilir."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"arka planda ses kaydeder"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Bu uygulama, herhangi bir zaman mikrofonu kullanarak ses kaydedebilir."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM karta komut gönderme"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Uygulamanın SIM karta komut göndermesine izin verir. Bu izin çok tehlikelidir."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"fiziksel aktiviteyi algıla"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Bu uygulama fiziksel aktivitenizi algılayabilir."</string>
<string name="permlab_camera" msgid="6320282492904119413">"resim çekme ve görüntü kaydetme"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Bu uygulama, kullanıldığı sırada kamerayı kullanarak fotoğraf ve video çekebilir."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"arka planda resim ve video çeker"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Bu uygulama, herhangi bir zaman kamerayı kullanarak fotoğraf ve video çekebilir."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Bir uygulama veya hizmetin fotoğraf ve video çekmek için sistem kameralarına erişmesine izin verin"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ayrıcalık tanınmış bu veya sistem uygulaması herhangi bir zamanda sistem kamerası kullanarak fotoğraf çekebilir ve video kaydedebilir. Uygulamanın da bu ayrıcalığa sahip olması için android.permission.CAMERA izni gerektirir"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Bir uygulama veya hizmetin açılıp kapatılan kamera cihazları hakkında geri çağırmalar almasına izin verin."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 4c5e13f14887..0c15f9e5c779 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -438,23 +438,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"змінювати налаштув-ня звуку"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Дозволяє програмі змінювати загальні налаштування звуку, як-от гучність і динамік, який використовується для виводу сигналу."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"запис-ти аудіо"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Цей додаток може записувати звук за допомогою мікрофона, коли ви використовуєте його."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"записувати звук у фоновому режимі"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Цей додаток може будь-коли записувати звук за допомогою мікрофона."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"надсилати команди на SIM-карту"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Дозволяє програмі надсилати команди на SIM-карту. Це дуже небезпечно."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"розпізнавати фізичну активність"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Цей додаток може розпізнавати фізичну активність."</string>
<string name="permlab_camera" msgid="6320282492904119413">"фотограф. та знімати відео"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Цей додаток може робити фотографії та записувати відео за допомогою камери, коли ви використовуєте його."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"робити фотографії та записувати відео у фоновому режимі"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Цей додаток може будь-коли робити фотографії та записувати відео за допомогою камери."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Дозволити додатку або сервісу отримувати доступ до системних камер, робити фото й записувати відео"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Цей пріоритетний системний додаток може будь-коли робити фото й записувати відео, використовуючи камеру системи. Додатку потрібен дозвіл android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Дозволити додатку або сервісу отримувати зворотні виклики щодо відкриття чи закриття камер."</string>
@@ -1866,7 +1860,7 @@
<item quantity="other">Протягом %1$d хв (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
</plurals>
<plurals name="zen_mode_duration_hours_summary" formatted="false" msgid="7725354244196466758">
- <item quantity="one">%1$d годину (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
+ <item quantity="one">%1$d година (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="few">%1$d години (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="many">%1$d годин (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
<item quantity="other">%1$d години (до <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 7809d5b6acf5..94fad2521efa 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"اپنے آڈیو کی ترتیبات کو تبدیل کریں"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"ایپ کو مجموعی آڈیو ترتیبات جیسے والیوم اور آؤٹ پٹ کیلئے جو اسپیکر استعمال ہوتا ہے اس میں ترمیم کرنے کی اجازت دیتا ہے۔"</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"آڈیو ریکارڈ کریں"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"ایپ کے استعمال ہونے کے دوران یہ ایپ مائیکروفون استعمال کرتے ہوئے آڈیو ریکارڈ کر سکتی ہے۔"</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"پس منظر میں آڈیو ریکارڈ کریں"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"یہ ایپ کسی بھی وقت مائیکروفون استعمال کرتے ہوئے آڈیو ریکارڈ کر سکتی ہے۔"</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"‏SIM کو ہدایات بھیجیں"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"‏ایپ کو SIM کو کمانڈز بھیجنے کی اجازت دیتا ہے۔ یہ بہت خطرناک ہے۔"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"جسمانی سرگرمی کی شناخت کریں"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"یہ ایپ آپ کی جسمانی سرگرمی کی شناخت کر سکتی ہے۔"</string>
<string name="permlab_camera" msgid="6320282492904119413">"تصاویر لیں اور ویڈیوز بنائیں"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"ایپ کے استعمال ہونے کے دوران یہ ایپ کیمرا استعمال کرتے ہوئے تصاویر لے سکتی ہے اور ویڈیوز ریکارڈ کر سکتی ہے۔"</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"پس منظر میں تصاویر لیں اور ویڈیوز ریکارڈ کریں"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"یہ ایپ کسی بھی وقت کیمرا استعمال کرتے ہوئے تصاویر لے سکتی ہے اور ویڈیوز ریکارڈ کر سکتی ہے۔"</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"ایپلیکیشن یا سروس کو سسٹم کے کیمرے تک رسائی حاصل کرنے کی اجازت دیتا ہے تاکہ وہ تصاویر لیں اور ویڈیوز ریکارڈ کریں۔"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"‏یہ مراعات یافتہ یا سسٹم ایپ کسی بھی وقت ایک سسٹم کیمرا استعمال کرتے ہوئے تصاویر اور ویڈیوز ریکارڈ کر سکتی ہے۔ ایپ کے پاس android.permission.CAMERA کے ليے بھی اجازت ہونا ضروری ہے۔"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"ایپلیکیشن یا سروس کو کیمرا کے آلات کے کُھلنے یا بند ہونے سے متعلق کال بیکس موصول کرنے کی اجازت دیں۔"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index c8ba3c6df1ee..61d29dce50b7 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"audio sozlamalaringizni o‘zgartirish"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Ilovalarga tovush va ovoz chiqarish uchun foydalaniladigan karnay kabi global audio sozlamalarini o‘zgartirish uchun ruxsat beradi."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ovoz yozib olish"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Bu ilova ishlayotganida u mikrofon orqali audio yozib olishi mumkin."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"orqa fonda ovoz yozib olish"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Bu ilova xohlagan vaqtda mikrofon yordami audio yozib olishi mumkin."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"SIM kartaga buyruqlar yuborish"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Dasturga SIM kartaga buyruqlar jo‘natishga ruxsat beradi. Bu juda ham xavfli."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"jismoniy harakatni aniqlash"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Bu ilova jismoniy harakatlaringizni aniqlay oladi."</string>
<string name="permlab_camera" msgid="6320282492904119413">"rasm va videoga olish"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Bu ilova ishlayotganida u kamera orqali suratga olishi va video yozib olishi mumkin."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"orqa fonda surat va videoga olish"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Bu ilova xohlagan vaqtda kamera orqali suratga olishi va video yozib olishi mumkin."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Ilova yoki xizmatga tizim kamerasi orqali surat va videolar olishga ruxsat berish"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Bu imtiyozli yoki tizim ilovasi istalgan vaqtda tizim kamerasi orqali surat va videolar olishi mumkin. Ilovada android.permission.CAMERA ruxsati ham yoqilgan boʻlishi talab qilinadi"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Ilova yoki xizmatga kamera qurilmalari ochilayotgani yoki yopilayotgani haqida qayta chaqiruvlar qabul qilishi uchun ruxsat berish."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index ea83fe8d6337..fd7205d24730 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"thay đổi cài đặt âm thanh của bạn"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Cho phép ứng dụng sửa đổi cài đặt âm thanh chung chẳng hạn như âm lượng và loa nào được sử dụng cho thiết bị ra."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"ghi âm"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Ứng dụng này có thể ghi âm bằng micrô khi bạn đang dùng ứng dụng."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ghi âm trong nền"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Ứng dụng này có thể ghi âm bằng micrô bất kỳ lúc nào."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"gửi lệnh đến SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Cho phép ứng dụng gửi lệnh đến SIM. Việc này rất nguy hiểm."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"nhận dạng hoạt động thể chất"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Ứng dụng này có thể nhận dạng hoạt động thể chất của bạn."</string>
<string name="permlab_camera" msgid="6320282492904119413">"chụp ảnh và quay video"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Ứng dụng này có thể chụp ảnh và quay video bằng máy ảnh khi bạn đang dùng ứng dụng."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"chụp ảnh và quay video trong nền"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Ứng dụng này có thể chụp ảnh và quay video bằng máy ảnh bất cứ lúc nào."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Cho phép một ứng dụng hoặc dịch vụ truy cập vào máy ảnh hệ thống để chụp ảnh và quay video"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Ứng dụng hệ thống có đặc quyền này có thể dùng máy ảnh hệ thống để chụp ảnh và quay video bất cứ lúc nào. Ngoài ra, ứng dụng này cũng cần có quyền android.permission.CAMERA"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Cho phép một ứng dụng hoặc dịch vụ nhận lệnh gọi lại khi các thiết bị máy ảnh đang được mở/đóng."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 7d3645bdd6a4..16775d5c0324 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"更改您的音频设置"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"允许该应用修改全局音频设置,例如音量和用于输出的扬声器。"</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"录音"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"当您使用此应用时,它可以使用麦克风录音。"</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"在后台录音"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"此应用可以随时使用麦克风录音。"</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"向 SIM 卡发送命令"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"允许应用向SIM卡发送命令(此权限具有很高的危险性)。"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"识别身体活动"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"此应用可以识别您的身体活动。"</string>
<string name="permlab_camera" msgid="6320282492904119413">"拍摄照片和视频"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"当您使用此应用时,它可以使用相机拍摄照片和录制视频。"</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"在后台拍摄照片和视频"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"此应用可以随时使用相机拍摄照片和录制视频。"</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"要拍照或录制视频,请允许应用或服务访问系统相机"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"这个具有特权的系统应用随时可以使用系统相机拍照及录制视频。另外,应用还需要获取 android.permission.CAMERA 权限"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"允许应用或服务接收与打开或关闭摄像头设备有关的回调。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 893f3e9954a2..bd13574b5135 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"更改音效設定"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"允許應用程式修改全域音頻設定,例如音量和用於輸出的喇叭。"</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"錄製音效"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"此應用程式在使用期間可使用麥克風錄音。"</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"在背景錄音"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"此應用程式可隨時使用麥克風錄音。"</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"發送指令至 SIM 卡"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"允許應用程式傳送指令到 SIM 卡。這項操作具有高危險性。"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"識別體能活動"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"此應用程式可識別您的體能活動。"</string>
<string name="permlab_camera" msgid="6320282492904119413">"拍照和拍攝影片"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"此應用程式在使用期間可使用相機拍照及錄影。"</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"在背景拍照及錄影"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"此應用程式可隨時使用相機拍照及錄影。"</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"允許應用程式或服務存取系統相機來拍照和攝錄"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"這個獲特別權限的系統應用程式可以在任何時候使用系統相機來拍照和攝錄。此外,應用程式亦需要 android.permission.CAMERA 權限"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"允許應用程式或服務接收相機裝置開啟或關閉的相關回電。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index f92cf4f8e983..0637742f1344 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"變更音訊設定"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"允許應用程式修改全域音訊設定,例如音量和用來輸出的喇叭。"</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"錄製音訊"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"這個應用程式在使用期間可以使用麥克風錄音。"</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"在背景錄音"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"這個應用程式隨時可以使用麥克風錄音。"</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"傳送指令到 SIM 卡"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"允許應用程式傳送指令到 SIM 卡。這麼做非常危險。"</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"辨識體能活動"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"這個應用程式可以辨識你從事的體能活動。"</string>
<string name="permlab_camera" msgid="6320282492904119413">"拍攝相片和影片"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"這個應用程式在使用期間可以使用相機拍照及錄影。"</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"在背景拍照及錄影"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"這個應用程式隨時可以使用相機拍照及錄影。"</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"如要拍照或錄影,請允許應用程式或服務存取系統攝影機"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"這個具有特殊權限的系統應用程式隨時可以使用系統攝影機拍照及錄影。此外,你也必須將 android.permission.CAMERA 權限授予這個應用程式"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"允許應用程式或服務接收相機裝置開啟或關閉的相關回呼。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index c43588b5c84a..ea97a6e3fd4f 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -432,23 +432,17 @@
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"shintsha izilungiselelo zakho zomsindo"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"Ivumela uhlelo lokusebenza ukushintsha izilungiselelo zomsindo we-global njengevolomu nokuthi isiphi isipika esisetshenziselwa okukhiphayo."</string>
<string name="permlab_recordAudio" msgid="1208457423054219147">"qopha umsindo"</string>
- <!-- no translation found for permdesc_recordAudio (5857246765327514062) -->
- <skip />
- <!-- no translation found for permlab_recordBackgroundAudio (5891032812308878254) -->
- <skip />
- <!-- no translation found for permdesc_recordBackgroundAudio (1992623135737407516) -->
- <skip />
+ <string name="permdesc_recordAudio" msgid="5857246765327514062">"Lolu hlelo lokusebenza lungarekhoda umsindo lisebenzisa imakrofoni kuyilapho uhlelo lokusebenza lusetshenziswa."</string>
+ <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"rekhoda umsindo ngemuva"</string>
+ <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Lolu hlelo lokusebenza lungafunda umsindo lisebenzisa imakrofoni noma kunini."</string>
<string name="permlab_sim_communication" msgid="176788115994050692">"thumela imilayezo ku-SIM"</string>
<string name="permdesc_sim_communication" msgid="4179799296415957960">"Ivumela uhlelo lokusebenza ukuthumela imiyalo ku-SIM. Lokhu kuyingozi kakhulu."</string>
<string name="permlab_activityRecognition" msgid="1782303296053990884">"bona umsebenzi"</string>
<string name="permdesc_activityRecognition" msgid="8667484762991357519">"Lolu hlelo lokusebenza lingabona umsebenzi wakho."</string>
<string name="permlab_camera" msgid="6320282492904119413">"thatha izithombe namavidiyo"</string>
- <!-- no translation found for permdesc_camera (5240801376168647151) -->
- <skip />
- <!-- no translation found for permlab_backgroundCamera (7549917926079731681) -->
- <skip />
- <!-- no translation found for permdesc_backgroundCamera (1615291686191138250) -->
- <skip />
+ <string name="permdesc_camera" msgid="5240801376168647151">"Lolu hlelo lokusebenza lungathatha izithombe futhi lirekhode amavidiyo lisebenzisa ikhamera kuyilapho uhlelo lokusebenza lusetshenziswa."</string>
+ <string name="permlab_backgroundCamera" msgid="7549917926079731681">"thatha izithombe namavidiyo ngemuva"</string>
+ <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"Lolu hlelo lokusebenza lungathatha izithombe futhi lirekhode amavidiyo lusebenzisa ikhamera noma kunini."</string>
<string name="permlab_systemCamera" msgid="3642917457796210580">"Vumela uhlelo lokusebenza noma isevisi ukufinyelela kumakhamera wesistimu ukuze uthathe izithombe namavidiyo"</string>
<string name="permdesc_systemCamera" msgid="5938360914419175986">"Lolu hlelo lokusebenza oluhle noma lwesistimu lingathatha izithombe futhi lirekhode amavidiyo lisebenzisa ikhamera yesistimu noma kunini. Idinga imvume ye-android.permission.CAMERA ukuthi iphathwe nawuhlelo lokusebenza"</string>
<string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"Vumela uhlelo lokusebenza noma isevisi ukwamukela ukuphinda ufonelwe mayelana namadivayisi wekhamera avuliwe noma avaliwe."</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 644ed3a6ee13..64de32c9ad09 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -199,6 +199,9 @@
<!-- The underline color and thickness for auto correction suggestion -->
<attr name="textAppearanceAutoCorrectionSuggestion" format="reference" />
+ <!-- The underline color and thickness for grammar error suggestion -->
+ <attr name="textAppearanceGrammarErrorSuggestion" format="reference" />
+
<!-- The underline color -->
<attr name="textUnderlineColor" format="reference|color" />
<!-- The underline thickness -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index f920083f5cb3..24afe07b57cf 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -306,6 +306,10 @@ please see styles_device_defaults.xml.
<item name="textUnderlineColor">@color/holo_blue_light</item>
</style>
+ <style name="TextAppearance.GrammarErrorSuggestion" parent="TextAppearance.Suggestion">
+ <item name="textUnderlineColor">@color/holo_blue_light</item>
+ </style>
+
<!-- Widget Styles -->
<style name="Widget">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d896a265a755..600968943d71 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -263,6 +263,7 @@
<java-symbol type="attr" name="searchDialogTheme" />
<java-symbol type="attr" name="textAppearanceAutoCorrectionSuggestion" />
<java-symbol type="attr" name="textAppearanceEasyCorrectSuggestion" />
+ <java-symbol type="attr" name="textAppearanceGrammarErrorSuggestion" />
<java-symbol type="attr" name="textAppearanceMisspelledSuggestion" />
<java-symbol type="attr" name="textColorSearchUrl" />
<java-symbol type="attr" name="timePickerStyle" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 47a0e7d071f8..049ba23a1a97 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -93,6 +93,7 @@ please see themes_device_defaults.xml.
<item name="textAppearanceEasyCorrectSuggestion">@style/TextAppearance.EasyCorrectSuggestion</item>
<item name="textAppearanceMisspelledSuggestion">@style/TextAppearance.MisspelledSuggestion</item>
<item name="textAppearanceAutoCorrectionSuggestion">@style/TextAppearance.AutoCorrectionSuggestion</item>
+ <item name="textAppearanceGrammarErrorSuggestion">@style/TextAppearance.GrammarErrorSuggestion</item>
<item name="textAppearanceButton">@style/TextAppearance.Widget.Button</item>
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 56f18d5dc1d7..6f55b8832bde 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -138,6 +138,9 @@
<!-- accessibility test permissions -->
<uses-permission android:name="android.permission.RETRIEVE_WINDOW_CONTENT" />
+ <!-- vibrator test permissions -->
+ <uses-permission android:name="android.permission.VIBRATE" />
+
<!-- vr test permissions -->
<uses-permission android:name="android.permission.RESTRICTED_VR_ACCESS" />
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index cb20130e742d..400b05c09fa5 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -31,6 +31,7 @@ import static org.junit.Assert.assertTrue;
import android.annotation.Nullable;
import android.app.Activity;
+import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.ActivityThread.ActivityClientRecord;
import android.app.IApplicationThread;
@@ -57,9 +58,9 @@ import android.util.MergedConfiguration;
import android.view.Display;
import android.view.View;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
+import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
@@ -542,6 +543,53 @@ public class ActivityThreadTest {
}
@Test
+ public void testHandleProcessConfigurationChanged_DependOnProcessState() {
+ final ActivityThread activityThread = ActivityThread.currentActivityThread();
+ final Configuration origConfig = activityThread.getConfiguration();
+ final int newDpi = origConfig.densityDpi + 10;
+ final Configuration newConfig = new Configuration(origConfig);
+ newConfig.seq++;
+ newConfig.densityDpi = newDpi;
+
+ activityThread.updateProcessState(ActivityManager.PROCESS_STATE_CACHED_ACTIVITY,
+ false /* fromIPC */);
+
+ applyProcessConfiguration(activityThread, newConfig);
+ try {
+ // In the cached state, the configuration is only set as pending and not applied.
+ assertEquals(origConfig.densityDpi, activityThread.getConfiguration().densityDpi);
+ assertTrue(activityThread.isCachedProcessState());
+ } finally {
+ // The foreground state is the default state of instrumentation.
+ activityThread.updateProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
+ false /* fromIPC */);
+ }
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ try {
+ // The state becomes non-cached, the pending configuration should be applied.
+ assertEquals(newConfig.densityDpi, activityThread.getConfiguration().densityDpi);
+ assertFalse(activityThread.isCachedProcessState());
+ } finally {
+ // Restore to the original configuration.
+ activityThread.getConfiguration().seq = origConfig.seq - 1;
+ applyProcessConfiguration(activityThread, origConfig);
+ }
+ }
+
+ private static void applyProcessConfiguration(ActivityThread thread, Configuration config) {
+ final ClientTransaction clientTransaction = newTransaction(thread,
+ null /* activityToken */);
+ clientTransaction.addCallback(ConfigurationChangeItem.obtain(config));
+ final IApplicationThread appThread = thread.getApplicationThread();
+ try {
+ appThread.scheduleTransaction(clientTransaction);
+ } catch (Exception ignored) {
+ }
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+
+ @Test
public void testResumeAfterNewIntent() {
final Activity activity = mActivityTestRule.launchActivity(new Intent());
final ActivityThread activityThread = activity.getActivityThread();
diff --git a/core/tests/coretests/src/android/app/appsearch/AppSearchSchemaTest.java b/core/tests/coretests/src/android/app/appsearch/AppSearchSchemaTest.java
deleted file mode 100644
index cdc6d250feeb..000000000000
--- a/core/tests/coretests/src/android/app/appsearch/AppSearchSchemaTest.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.appsearch;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.testng.Assert.assertThrows;
-import static org.testng.Assert.expectThrows;
-
-import android.app.appsearch.AppSearchSchema.PropertyConfig;
-import android.app.appsearch.proto.IndexingConfig;
-import android.app.appsearch.proto.PropertyConfigProto;
-import android.app.appsearch.proto.SchemaTypeConfigProto;
-import android.app.appsearch.proto.TermMatchType;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-
-@SmallTest
-public class AppSearchSchemaTest {
- @Test
- public void testGetProto_Email() {
- AppSearchSchema emailSchema = new AppSearchSchema.Builder("Email")
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder("body")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).build();
-
- SchemaTypeConfigProto expectedEmailProto = SchemaTypeConfigProto.newBuilder()
- .setSchemaType("Email")
- .addProperties(PropertyConfigProto.newBuilder()
- .setPropertyName("subject")
- .setDataType(PropertyConfigProto.DataType.Code.STRING)
- .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
- .setIndexingConfig(
- android.app.appsearch.proto.IndexingConfig.newBuilder()
- .setTokenizerType(IndexingConfig.TokenizerType.Code.PLAIN)
- .setTermMatchType(TermMatchType.Code.PREFIX)
- )
- ).addProperties(PropertyConfigProto.newBuilder()
- .setPropertyName("body")
- .setDataType(PropertyConfigProto.DataType.Code.STRING)
- .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
- .setIndexingConfig(
- android.app.appsearch.proto.IndexingConfig.newBuilder()
- .setTokenizerType(
- android.app.appsearch.proto.IndexingConfig
- .TokenizerType.Code.PLAIN)
- .setTermMatchType(TermMatchType.Code.PREFIX)
- )
- ).build();
-
- assertThat(emailSchema.getProto()).isEqualTo(expectedEmailProto);
- }
-
- @Test
- public void testGetProto_MusicRecording() {
- AppSearchSchema musicRecordingSchema = new AppSearchSchema.Builder("MusicRecording")
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("artist")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_REPEATED)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder("pubDate")
- .setDataType(PropertyConfig.DATA_TYPE_INT64)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_NONE)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_NONE)
- .build()
- ).build();
-
- SchemaTypeConfigProto expectedMusicRecordingProto = SchemaTypeConfigProto.newBuilder()
- .setSchemaType("MusicRecording")
- .addProperties(PropertyConfigProto.newBuilder()
- .setPropertyName("artist")
- .setDataType(PropertyConfigProto.DataType.Code.STRING)
- .setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED)
- .setIndexingConfig(
- android.app.appsearch.proto.IndexingConfig.newBuilder()
- .setTokenizerType(
- android.app.appsearch.proto.IndexingConfig
- .TokenizerType.Code.PLAIN)
- .setTermMatchType(TermMatchType.Code.PREFIX)
- )
- ).addProperties(PropertyConfigProto.newBuilder()
- .setPropertyName("pubDate")
- .setDataType(PropertyConfigProto.DataType.Code.INT64)
- .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
- .setIndexingConfig(
- android.app.appsearch.proto.IndexingConfig.newBuilder()
- .setTokenizerType(
- android.app.appsearch.proto.IndexingConfig
- .TokenizerType.Code.NONE)
- .setTermMatchType(TermMatchType.Code.UNKNOWN)
- )
- ).build();
-
- assertThat(musicRecordingSchema.getProto()).isEqualTo(expectedMusicRecordingProto);
- }
-
- @Test
- public void testInvalidEnums() {
- PropertyConfig.Builder builder = new AppSearchSchema.PropertyConfig.Builder("test");
- assertThrows(IllegalArgumentException.class, () -> builder.setDataType(99));
- assertThrows(IllegalArgumentException.class, () -> builder.setCardinality(99));
- }
-
- @Test
- public void testMissingFields() {
- PropertyConfig.Builder builder = new AppSearchSchema.PropertyConfig.Builder("test");
- Exception e = expectThrows(IllegalSchemaException.class, builder::build);
- assertThat(e).hasMessageThat().contains("Missing field: dataType");
-
- builder.setDataType(PropertyConfig.DATA_TYPE_DOCUMENT);
- e = expectThrows(IllegalSchemaException.class, builder::build);
- assertThat(e).hasMessageThat().contains("Missing field: schemaType");
-
- builder.setSchemaType("TestType");
- e = expectThrows(IllegalSchemaException.class, builder::build);
- assertThat(e).hasMessageThat().contains("Missing field: cardinality");
-
- builder.setCardinality(PropertyConfig.CARDINALITY_REPEATED);
- builder.build();
- }
-
- @Test
- public void testDuplicateProperties() {
- AppSearchSchema.Builder builder = new AppSearchSchema.Builder("Email")
- .addProperty(new AppSearchSchema.PropertyConfig.Builder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- ).addProperty(new AppSearchSchema.PropertyConfig.Builder("subject")
- .setDataType(PropertyConfig.DATA_TYPE_STRING)
- .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
- .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
- .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
- .build()
- );
-
- Exception e = expectThrows(IllegalSchemaException.class, builder::build);
- assertThat(e).hasMessageThat().contains("Property defined more than once: subject");
- }
-}
diff --git a/core/tests/coretests/src/android/app/appsearch/SearchResultsTest.java b/core/tests/coretests/src/android/app/appsearch/SearchResultsTest.java
index 1d71ec4520c3..ac0f44bb17e4 100644
--- a/core/tests/coretests/src/android/app/appsearch/SearchResultsTest.java
+++ b/core/tests/coretests/src/android/app/appsearch/SearchResultsTest.java
@@ -59,7 +59,7 @@ public class SearchResultsTest {
@Test
public void buildSearchSpecWithoutTermMatchType() {
- assertThrows(RuntimeException.class, () -> SearchSpec.newBuilder()
+ assertThrows(RuntimeException.class, () -> new SearchSpec.Builder()
.setSchemaTypes("testSchemaType")
.build());
}
diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/AppSearchSchemaTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/AppSearchSchemaTest.java
new file mode 100644
index 000000000000..c171270e23ea
--- /dev/null
+++ b/core/tests/coretests/src/android/app/appsearch/external/app/AppSearchSchemaTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.app.appsearch;
+
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.expectThrows;
+
+import android.app.appsearch.AppSearchSchema.PropertyConfig;
+import android.app.appsearch.exceptions.IllegalSchemaException;
+
+import org.junit.Test;
+
+public class AppSearchSchemaTest {
+ @Test
+ public void testInvalidEnums() {
+ PropertyConfig.Builder builder = new PropertyConfig.Builder("test");
+ expectThrows(IllegalArgumentException.class, () -> builder.setDataType(99));
+ expectThrows(IllegalArgumentException.class, () -> builder.setCardinality(99));
+ }
+
+ @Test
+ public void testMissingFields() {
+ PropertyConfig.Builder builder = new PropertyConfig.Builder("test");
+ IllegalSchemaException e = expectThrows(IllegalSchemaException.class, builder::build);
+ assertThat(e).hasMessageThat().contains("Missing field: dataType");
+
+ builder.setDataType(PropertyConfig.DATA_TYPE_DOCUMENT);
+ e = expectThrows(IllegalSchemaException.class, builder::build);
+ assertThat(e).hasMessageThat().contains("Missing field: schemaType");
+
+ builder.setSchemaType("TestType");
+ e = expectThrows(IllegalSchemaException.class, builder::build);
+ assertThat(e).hasMessageThat().contains("Missing field: cardinality");
+
+ builder.setCardinality(PropertyConfig.CARDINALITY_REPEATED);
+ builder.build();
+ }
+
+ @Test
+ public void testDuplicateProperties() {
+ AppSearchSchema.Builder builder = new AppSearchSchema.Builder("Email")
+ .addProperty(new PropertyConfig.Builder("subject")
+ .setDataType(PropertyConfig.DATA_TYPE_STRING)
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ );
+ IllegalSchemaException e = expectThrows(IllegalSchemaException.class,
+ () -> builder.addProperty(new PropertyConfig.Builder("subject")
+ .setDataType(PropertyConfig.DATA_TYPE_STRING)
+ .setCardinality(PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(PropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()));
+ assertThat(e).hasMessageThat().contains("Property defined more than once: subject");
+ }
+}
diff --git a/core/tests/coretests/src/android/os/VibratorTest.java b/core/tests/coretests/src/android/os/VibratorTest.java
new file mode 100644
index 000000000000..c3d84ecc2abf
--- /dev/null
+++ b/core/tests/coretests/src/android/os/VibratorTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import static junit.framework.TestCase.assertEquals;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.media.AudioAttributes;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.junit.MockitoJUnitRunner;
+
+/**
+ * Tests for {@link Vibrator}.
+ *
+ * Build/Install/Run:
+ * atest FrameworksCoreTests:VibratorTest
+ */
+@Presubmit
+@RunWith(MockitoJUnitRunner.class)
+public class VibratorTest {
+
+ private Vibrator mVibratorSpy;
+
+ @Before
+ public void setUp() {
+ mVibratorSpy = spy(InstrumentationRegistry.getContext().getSystemService(Vibrator.class));
+ }
+
+ @Test
+ public void vibrate_withAudioAttributes_createsVibrationAttributesWithSameUsage() {
+ VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
+ AudioAttributes audioAttributes = new AudioAttributes.Builder().setUsage(
+ AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY).build();
+
+ mVibratorSpy.vibrate(effect, audioAttributes);
+
+ ArgumentCaptor<VibrationAttributes> captor = ArgumentCaptor.forClass(
+ VibrationAttributes.class);
+ verify(mVibratorSpy).vibrate(anyInt(), anyString(), eq(effect), isNull(), captor.capture());
+
+ VibrationAttributes vibrationAttributes = captor.getValue();
+ assertEquals(VibrationAttributes.USAGE_COMMUNICATION_REQUEST,
+ vibrationAttributes.getUsage());
+ // Keeps original AudioAttributes usage to be used by the VibratorService.
+ assertEquals(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY,
+ vibrationAttributes.getAudioUsage());
+ }
+
+ @Test
+ public void vibrate_withUnknownAudioAttributes_hasTouchUsageFromEffect() {
+ VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
+ AudioAttributes audioAttributes = new AudioAttributes.Builder().setUsage(
+ AudioAttributes.USAGE_UNKNOWN).build();
+
+ mVibratorSpy.vibrate(effect, audioAttributes);
+
+ ArgumentCaptor<VibrationAttributes> captor = ArgumentCaptor.forClass(
+ VibrationAttributes.class);
+ verify(mVibratorSpy).vibrate(anyInt(), anyString(), eq(effect), isNull(), captor.capture());
+
+ VibrationAttributes vibrationAttributes = captor.getValue();
+ assertEquals(VibrationAttributes.USAGE_TOUCH,
+ vibrationAttributes.getUsage());
+ // Sets AudioAttributes usage based on effect.
+ assertEquals(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION,
+ vibrationAttributes.getAudioUsage());
+ }
+
+ @Test
+ public void vibrate_withoutAudioAttributes_hasTouchUsageFromEffect() {
+ mVibratorSpy.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_CLICK));
+
+ ArgumentCaptor<VibrationAttributes> captor = ArgumentCaptor.forClass(
+ VibrationAttributes.class);
+ verify(mVibratorSpy).vibrate(anyInt(), anyString(), any(), isNull(), captor.capture());
+
+ VibrationAttributes vibrationAttributes = captor.getValue();
+ assertEquals(VibrationAttributes.USAGE_TOUCH, vibrationAttributes.getUsage());
+ // Sets AudioAttributes usage based on effect.
+ assertEquals(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION,
+ vibrationAttributes.getAudioUsage());
+ }
+
+ @Test
+ public void vibrate_withoutAudioAttributesAndLongEffect_hasUnknownUsage() {
+ mVibratorSpy.vibrate(VibrationEffect.createOneShot(10_000, 255));
+
+ ArgumentCaptor<VibrationAttributes> captor = ArgumentCaptor.forClass(
+ VibrationAttributes.class);
+ verify(mVibratorSpy).vibrate(anyInt(), anyString(), any(), isNull(), captor.capture());
+
+ VibrationAttributes vibrationAttributes = captor.getValue();
+ assertEquals(VibrationAttributes.USAGE_UNKNOWN, vibrationAttributes.getUsage());
+ assertEquals(AudioAttributes.USAGE_UNKNOWN, vibrationAttributes.getAudioUsage());
+ }
+}
diff --git a/core/tests/coretests/src/android/text/TextUtilsTest.java b/core/tests/coretests/src/android/text/TextUtilsTest.java
index be6ef195fa96..285ad9fae13c 100644
--- a/core/tests/coretests/src/android/text/TextUtilsTest.java
+++ b/core/tests/coretests/src/android/text/TextUtilsTest.java
@@ -792,5 +792,6 @@ public class TextUtilsTest {
assertEquals("ABC...", TextUtils.trimToLengthWithEllipsis("ABCDEF", 3));
assertEquals("ABC", TextUtils.trimToLengthWithEllipsis("ABC", 3));
assertEquals("", TextUtils.trimToLengthWithEllipsis("", 3));
+ assertNull(TextUtils.trimToLengthWithEllipsis(null, 3));
}
}
diff --git a/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java b/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java
index 403c1c219a52..b5720a262b3d 100644
--- a/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/KernelSingleProcessCpuThreadReaderTest.java
@@ -38,8 +38,6 @@ import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.util.Comparator;
-import java.util.List;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -59,31 +57,21 @@ public class KernelSingleProcessCpuThreadReaderTest {
}
@Test
- public void getThreadCpuUsage() throws IOException {
+ public void getProcessCpuUsage() throws IOException {
setupDirectory(42,
new int[] {42, 1, 2, 3},
new int[] {1000, 2000},
// Units are 10ms aka 10000Us
- new int[][] {{100, 200}, {0, 200}, {100, 300}, {0, 400}},
- new int[] {1400, 1500});
+ new int[][] {{100, 200}, {0, 200}, {100, 300}, {0, 600}},
+ new int[] {4500, 500});
KernelSingleProcessCpuThreadReader reader = new KernelSingleProcessCpuThreadReader(42,
mProcDirectory.toPath());
KernelSingleProcessCpuThreadReader.ProcessCpuUsage processCpuUsage =
- reader.getProcessCpuUsage();
- assertThat(processCpuUsage.cpuTimeMillis).isEqualTo(29000);
- List<KernelSingleProcessCpuThreadReader.ThreadCpuUsage> threadCpuUsage =
- processCpuUsage.threadCpuUsages;
- threadCpuUsage.sort(Comparator.comparingInt(o -> o.threadId));
- assertThat(threadCpuUsage).hasSize(4);
- assertThat(threadCpuUsage.get(0).threadId).isEqualTo(1);
- assertThat(threadCpuUsage.get(0).usageTimesMillis).isEqualTo(new long[]{0, 2000});
- assertThat(threadCpuUsage.get(1).threadId).isEqualTo(2);
- assertThat(threadCpuUsage.get(1).usageTimesMillis).isEqualTo(new long[]{1000, 3000});
- assertThat(threadCpuUsage.get(2).threadId).isEqualTo(3);
- assertThat(threadCpuUsage.get(2).usageTimesMillis).isEqualTo(new long[]{0, 4000});
- assertThat(threadCpuUsage.get(3).threadId).isEqualTo(42);
- assertThat(threadCpuUsage.get(3).usageTimesMillis).isEqualTo(new long[]{1000, 2000});
+ reader.getProcessCpuUsage(new int[] {2, 3});
+ assertThat(processCpuUsage.threadCpuTimesMillis).isEqualTo(new long[] {2000, 13000});
+ assertThat(processCpuUsage.selectedThreadCpuTimesMillis).isEqualTo(new long[] {1000, 9000});
+ assertThat(processCpuUsage.processCpuTimesMillis).isEqualTo(new long[] {6666, 43333});
}
@Test
diff --git a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
index 37e1efdecfd1..bd0bbe99ee2f 100644
--- a/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/SystemServicePowerCalculatorTest.java
@@ -66,7 +66,7 @@ public class SystemServicePowerCalculatorTest {
public void testCalculateApp() {
// Test Power Profile has two CPU clusters with 3 and 4 speeds, thus 7 freq times total
mMockSystemServerCpuThreadReader.setCpuTimes(
- 210000,
+ new long[] {10000, 15000, 20000, 25000, 30000, 35000, 40000},
new long[] {30000, 40000, 50000, 60000, 70000, 80000, 90000},
new long[] {20000, 30000, 40000, 50000, 60000, 70000, 80000});
@@ -107,13 +107,13 @@ public class SystemServicePowerCalculatorTest {
mMockBatteryStats.getUidStatsLocked(workSourceUid1), 0);
mSystemServicePowerCalculator.calculateApp(app1, app1.uidObj, 0, 0,
BatteryStats.STATS_SINCE_CHARGED);
- assertEquals(0.00018958, app1.systemServiceCpuPowerMah, 0.0000001);
+ assertEquals(0.00016269, app1.systemServiceCpuPowerMah, 0.0000001);
BatterySipper app2 = new BatterySipper(BatterySipper.DrainType.APP,
mMockBatteryStats.getUidStatsLocked(workSourceUid2), 0);
mSystemServicePowerCalculator.calculateApp(app2, app2.uidObj, 0, 0,
BatteryStats.STATS_SINCE_CHARGED);
- assertEquals(0.00170625, app2.systemServiceCpuPowerMah, 0.0000001);
+ assertEquals(0.00146426, app2.systemServiceCpuPowerMah, 0.0000001);
}
private static class MockKernelCpuUidFreqTimeReader extends
@@ -148,9 +148,9 @@ public class SystemServicePowerCalculatorTest {
super(null);
}
- public void setCpuTimes(long processCpuTimeUs, long[] threadCpuTimesUs,
+ public void setCpuTimes(long[] processCpuTimesUs, long[] threadCpuTimesUs,
long[] binderThreadCpuTimesUs) {
- mThreadTimes.processCpuTimeUs = processCpuTimeUs;
+ mThreadTimes.processCpuTimesUs = processCpuTimesUs;
mThreadTimes.threadCpuTimesUs = threadCpuTimesUs;
mThreadTimes.binderThreadCpuTimesUs = binderThreadCpuTimesUs;
}
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index b94721e37138..59727d5b2555 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -2467,6 +2467,12 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimation.java"
},
+ "781471998": {
+ "message": "moveWindowTokenToDisplay: Cannot move to the original display for token: %s",
+ "level": "WARN",
+ "group": "WM_ERROR",
+ "at": "com\/android\/server\/wm\/WindowManagerService.java"
+ },
"791468751": {
"message": "Pausing rotation during re-position",
"level": "DEBUG",
@@ -2671,6 +2677,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "1033274509": {
+ "message": "moveWindowTokenToDisplay: Attempted to move non-existing token: %s",
+ "level": "WARN",
+ "group": "WM_ERROR",
+ "at": "com\/android\/server\/wm\/WindowManagerService.java"
+ },
"1040675582": {
"message": "Can't report activity configuration update - client not running, activityRecord=%s",
"level": "WARN",
@@ -3457,6 +3469,12 @@
"group": "WM_DEBUG_REMOTE_ANIMATIONS",
"at": "com\/android\/server\/wm\/WallpaperAnimationAdapter.java"
},
+ "2060978050": {
+ "message": "moveWindowTokenToDisplay: Attempted to move token: %s to non-exiting displayId=%d",
+ "level": "WARN",
+ "group": "WM_ERROR",
+ "at": "com\/android\/server\/wm\/WindowManagerService.java"
+ },
"2081291430": {
"message": "Focus not requested for window=%s because it has no surface",
"level": "DEBUG",
diff --git a/drm/jni/Android.bp b/drm/jni/Android.bp
index 1e33f0ea5094..68757d86fb89 100644
--- a/drm/jni/Android.bp
+++ b/drm/jni/Android.bp
@@ -21,6 +21,7 @@ cc_library_shared {
shared_libs: [
"libdrmframework",
+ "libdrmframeworkcommon",
"liblog",
"libutils",
"libandroid_runtime",
diff --git a/errorprone/java/com/google/errorprone/bugpatterns/android/PendingIntentMutabilityChecker.java b/errorprone/java/com/google/errorprone/bugpatterns/android/PendingIntentMutabilityChecker.java
new file mode 100644
index 000000000000..2561b41028cc
--- /dev/null
+++ b/errorprone/java/com/google/errorprone/bugpatterns/android/PendingIntentMutabilityChecker.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.errorprone.bugpatterns.android;
+
+import static com.google.errorprone.BugPattern.SeverityLevel.WARNING;
+import static com.google.errorprone.matchers.FieldMatchers.staticField;
+import static com.google.errorprone.matchers.Matchers.anyOf;
+import static com.google.errorprone.matchers.Matchers.contains;
+import static com.google.errorprone.matchers.Matchers.methodInvocation;
+import static com.google.errorprone.matchers.Matchers.staticMethod;
+
+
+import com.google.auto.service.AutoService;
+import com.google.errorprone.BugPattern;
+import com.google.errorprone.VisitorState;
+import com.google.errorprone.bugpatterns.BugChecker;
+import com.google.errorprone.bugpatterns.BugChecker.MethodInvocationTreeMatcher;
+import com.google.errorprone.matchers.Description;
+import com.google.errorprone.matchers.Matcher;
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.MethodInvocationTree;
+
+import java.util.regex.Pattern;
+
+/**
+ * Any method calls to create a PendingIntent require that one of the
+ * mutability flags, FLAG_MUTABLE or FLAG_IMMUTABLE, be explicitly specified.
+ * This checker verifies that one of these mutability flags are used when
+ * creating PendingIntents.
+ */
+@AutoService(BugChecker.class)
+@BugPattern(
+ name = "AndroidFrameworkPendingIntentMutability",
+ summary = "Verifies that FLAG_MUTABLE or FLAG_IMMUTABLE is always set",
+ severity = WARNING)
+public final class PendingIntentMutabilityChecker extends BugChecker
+ implements MethodInvocationTreeMatcher {
+
+ private static final Matcher<ExpressionTree> PENDING_INTENT_METHOD = methodInvocation(
+ staticMethod()
+ .onClass("android.app.PendingIntent")
+ .withNameMatching(Pattern.compile(
+ "^(getActivity|getActivityAsUser|getActivities|getActivitiesAsUser|"
+ + "getBroadcast|getBroadcastAsUser|getService|getForegroundService).*")));
+
+ private static final Matcher<ExpressionTree> VALID_FLAGS = anyOf(
+ staticField("android.app.PendingIntent", "FLAG_MUTABLE"),
+ staticField("android.app.PendingIntent", "FLAG_IMMUTABLE"));
+
+ private static final Matcher<ExpressionTree> CONTAINS_VALID_FLAGS = contains(
+ ExpressionTree.class, VALID_FLAGS);
+
+ @Override
+ public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState state) {
+ if (PENDING_INTENT_METHOD.matches(tree, state)) {
+ final ExpressionTree arg = tree.getArguments().get(3);
+ if (!(VALID_FLAGS.matches(arg, state) || CONTAINS_VALID_FLAGS.matches(arg, state))) {
+ return buildDescription(arg)
+ .setMessage("To improve security, PendingIntents must declare one of"
+ + " FLAG_MUTABLE or FLAG_IMMUTABLE explicitly; see"
+ + " go/immutable-pendingintents for more details")
+ .build();
+ }
+ }
+ return Description.NO_MATCH;
+ }
+}
diff --git a/errorprone/tests/java/com/google/errorprone/bugpatterns/android/PendingIntentMutabilityCheckerTest.java b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/PendingIntentMutabilityCheckerTest.java
new file mode 100644
index 000000000000..a8badf6bdb0b
--- /dev/null
+++ b/errorprone/tests/java/com/google/errorprone/bugpatterns/android/PendingIntentMutabilityCheckerTest.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.errorprone.bugpatterns.android;
+
+import com.google.errorprone.CompilationTestHelper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class PendingIntentMutabilityCheckerTest {
+ private CompilationTestHelper mCompilationHelper;
+
+ @Before
+ public void setUp() {
+ mCompilationHelper = CompilationTestHelper.newInstance(
+ PendingIntentMutabilityChecker.class, getClass());
+ }
+
+ @Test
+ public void testGetActivity() {
+ mCompilationHelper
+ .addSourceFile("/android/app/PendingIntent.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceFile("/android/content/Intent.java")
+ .addSourceFile("/android/os/UserHandle.java")
+ .addSourceFile("/android/os/Bundle.java")
+ .addSourceLines("Example.java",
+ "import android.app.PendingIntent;",
+ "import android.content.Context;",
+ "import android.content.Intent;",
+ "public class Example {",
+ " Context context;",
+ " Intent intent;",
+ " void example() {",
+ " PendingIntent.getActivity(context, 42, intent, PendingIntent.FLAG_MUTABLE);",
+ " PendingIntent.getActivity(context, 42, intent, PendingIntent.FLAG_IMMUTABLE);",
+ " PendingIntent.getActivity(context, 42, intent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);",
+ " PendingIntent.getActivity(context, 42, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);",
+ " PendingIntent.getActivity(context, 42, intent, 0 | PendingIntent.FLAG_MUTABLE);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivity(context, 42, intent, PendingIntent.FLAG_ONE_SHOT);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivity(context, 42, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_NO_CREATE);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivity(context, 42, intent, 0);",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testGetActivityAsUser() {
+ mCompilationHelper
+ .addSourceFile("/android/app/PendingIntent.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceFile("/android/content/Intent.java")
+ .addSourceFile("/android/os/UserHandle.java")
+ .addSourceFile("/android/os/Bundle.java")
+ .addSourceLines("Example.java",
+ "import android.app.PendingIntent;",
+ "import android.content.Context;",
+ "import android.content.Intent;",
+ "public class Example {",
+ " Context context;",
+ " Intent intent;",
+ " void example() {",
+ " PendingIntent.getActivityAsUser(context, 42, intent, PendingIntent.FLAG_MUTABLE, null, null);",
+ " PendingIntent.getActivityAsUser(context, 42, intent, PendingIntent.FLAG_IMMUTABLE, null, null);",
+ " PendingIntent.getActivityAsUser(context, 42, intent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT, null, null);",
+ " PendingIntent.getActivityAsUser(context, 42, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT, null, null);",
+ " PendingIntent.getActivityAsUser(context, 42, intent, 0 | PendingIntent.FLAG_MUTABLE, null, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivityAsUser(context, 42, intent, PendingIntent.FLAG_ONE_SHOT, null, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivityAsUser(context, 42, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_NO_CREATE, null, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivityAsUser(context, 42, intent, 0, null, null);",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testGetActivities() {
+ mCompilationHelper
+ .addSourceFile("/android/app/PendingIntent.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceFile("/android/content/Intent.java")
+ .addSourceFile("/android/os/UserHandle.java")
+ .addSourceFile("/android/os/Bundle.java")
+ .addSourceLines("Example.java",
+ "import android.app.PendingIntent;",
+ "import android.content.Context;",
+ "import android.content.Intent;",
+ "public class Example {",
+ " Context context;",
+ " Intent[] intents;",
+ " void example() {",
+ " PendingIntent.getActivities(context, 42, intents, PendingIntent.FLAG_MUTABLE, null);",
+ " PendingIntent.getActivities(context, 42, intents, PendingIntent.FLAG_IMMUTABLE, null);",
+ " PendingIntent.getActivities(context, 42, intents, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT, null);",
+ " PendingIntent.getActivities(context, 42, intents, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT, null);",
+ " PendingIntent.getActivities(context, 42, intents, 0 | PendingIntent.FLAG_MUTABLE, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivities(context, 42, intents, PendingIntent.FLAG_ONE_SHOT, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivities(context, 42, intents, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_NO_CREATE, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivities(context, 42, intents, 0, null);",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testGetActivitiesAsUser() {
+ mCompilationHelper
+ .addSourceFile("/android/app/PendingIntent.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceFile("/android/content/Intent.java")
+ .addSourceFile("/android/os/UserHandle.java")
+ .addSourceFile("/android/os/Bundle.java")
+ .addSourceLines("Example.java",
+ "import android.app.PendingIntent;",
+ "import android.content.Context;",
+ "import android.content.Intent;",
+ "public class Example {",
+ " Context context;",
+ " Intent[] intents;",
+ " void example() {",
+ " PendingIntent.getActivitiesAsUser(context, 42, intents, PendingIntent.FLAG_MUTABLE, null, null);",
+ " PendingIntent.getActivitiesAsUser(context, 42, intents, PendingIntent.FLAG_IMMUTABLE, null, null);",
+ " PendingIntent.getActivitiesAsUser(context, 42, intents, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT, null, null);",
+ " PendingIntent.getActivitiesAsUser(context, 42, intents, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT, null, null);",
+ " PendingIntent.getActivitiesAsUser(context, 42, intents, 0 | PendingIntent.FLAG_MUTABLE, null, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivitiesAsUser(context, 42, intents, PendingIntent.FLAG_ONE_SHOT, null, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivitiesAsUser(context, 42, intents, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_NO_CREATE, null, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getActivitiesAsUser(context, 42, intents, 0, null, null);",
+ " }",
+ "}")
+ .doTest();
+ }
+
+
+ @Test
+ public void testGetBroadcast() {
+ mCompilationHelper
+ .addSourceFile("/android/app/PendingIntent.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceFile("/android/content/Intent.java")
+ .addSourceFile("/android/os/UserHandle.java")
+ .addSourceFile("/android/os/Bundle.java")
+ .addSourceLines("Example.java",
+ "import android.app.PendingIntent;",
+ "import android.content.Context;",
+ "import android.content.Intent;",
+ "public class Example {",
+ " Context context;",
+ " Intent intent;",
+ " void example() {",
+ " PendingIntent.getBroadcast(context, 42, intent, PendingIntent.FLAG_MUTABLE);",
+ " PendingIntent.getBroadcast(context, 42, intent, PendingIntent.FLAG_IMMUTABLE);",
+ " PendingIntent.getBroadcast(context, 42, intent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);",
+ " PendingIntent.getBroadcast(context, 42, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);",
+ " PendingIntent.getBroadcast(context, 42, intent, 0 | PendingIntent.FLAG_MUTABLE);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getBroadcast(context, 42, intent, PendingIntent.FLAG_ONE_SHOT);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getBroadcast(context, 42, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_NO_CREATE);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getBroadcast(context, 42, intent, 0);",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testGetBroadcastAsUser() {
+ mCompilationHelper
+ .addSourceFile("/android/app/PendingIntent.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceFile("/android/content/Intent.java")
+ .addSourceFile("/android/os/UserHandle.java")
+ .addSourceFile("/android/os/Bundle.java")
+ .addSourceLines("Example.java",
+ "import android.app.PendingIntent;",
+ "import android.content.Context;",
+ "import android.content.Intent;",
+ "public class Example {",
+ " Context context;",
+ " Intent intent;",
+ " void example() {",
+ " PendingIntent.getBroadcastAsUser(context, 42, intent, PendingIntent.FLAG_MUTABLE, null);",
+ " PendingIntent.getBroadcastAsUser(context, 42, intent, PendingIntent.FLAG_IMMUTABLE, null);",
+ " PendingIntent.getBroadcastAsUser(context, 42, intent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT, null);",
+ " PendingIntent.getBroadcastAsUser(context, 42, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT, null);",
+ " PendingIntent.getBroadcastAsUser(context, 42, intent, 0 | PendingIntent.FLAG_MUTABLE, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getBroadcastAsUser(context, 42, intent, PendingIntent.FLAG_ONE_SHOT, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getBroadcastAsUser(context, 42, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_NO_CREATE, null);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getBroadcastAsUser(context, 42, intent, 0, null);",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testGetService() {
+ mCompilationHelper
+ .addSourceFile("/android/app/PendingIntent.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceFile("/android/content/Intent.java")
+ .addSourceFile("/android/os/UserHandle.java")
+ .addSourceFile("/android/os/Bundle.java")
+ .addSourceLines("Example.java",
+ "import android.app.PendingIntent;",
+ "import android.content.Context;",
+ "import android.content.Intent;",
+ "public class Example {",
+ " Context context;",
+ " Intent intent;",
+ " void example() {",
+ " PendingIntent.getService(context, 42, intent, PendingIntent.FLAG_MUTABLE);",
+ " PendingIntent.getService(context, 42, intent, PendingIntent.FLAG_IMMUTABLE);",
+ " PendingIntent.getService(context, 42, intent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);",
+ " PendingIntent.getService(context, 42, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);",
+ " PendingIntent.getService(context, 42, intent, 0 | PendingIntent.FLAG_MUTABLE);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getService(context, 42, intent, PendingIntent.FLAG_ONE_SHOT);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getService(context, 42, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_NO_CREATE);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getService(context, 42, intent, 0);",
+ " }",
+ "}")
+ .doTest();
+ }
+
+ @Test
+ public void testGetForegroundService() {
+ mCompilationHelper
+ .addSourceFile("/android/app/PendingIntent.java")
+ .addSourceFile("/android/content/Context.java")
+ .addSourceFile("/android/content/Intent.java")
+ .addSourceFile("/android/os/UserHandle.java")
+ .addSourceFile("/android/os/Bundle.java")
+ .addSourceLines("Example.java",
+ "import android.app.PendingIntent;",
+ "import android.content.Context;",
+ "import android.content.Intent;",
+ "public class Example {",
+ " Context context;",
+ " Intent intent;",
+ " void example() {",
+ " PendingIntent.getForegroundService(context, 42, intent, PendingIntent.FLAG_MUTABLE);",
+ " PendingIntent.getForegroundService(context, 42, intent, PendingIntent.FLAG_IMMUTABLE);",
+ " PendingIntent.getForegroundService(context, 42, intent, PendingIntent.FLAG_NO_CREATE | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);",
+ " PendingIntent.getForegroundService(context, 42, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);",
+ " PendingIntent.getForegroundService(context, 42, intent, 0 | PendingIntent.FLAG_MUTABLE);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getForegroundService(context, 42, intent, PendingIntent.FLAG_ONE_SHOT);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getForegroundService(context, 42, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_NO_CREATE);",
+ " // BUG: Diagnostic contains:",
+ " PendingIntent.getForegroundService(context, 42, intent, 0);",
+ " }",
+ "}")
+ .doTest();
+ }
+}
diff --git a/errorprone/tests/res/android/app/PendingIntent.java b/errorprone/tests/res/android/app/PendingIntent.java
new file mode 100644
index 000000000000..a0cdedfd1d7a
--- /dev/null
+++ b/errorprone/tests/res/android/app/PendingIntent.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+public class PendingIntent {
+ public static final int FLAG_ONE_SHOT = 1<<30;
+ public static final int FLAG_IMMUTABLE = 1<<26;
+ public static final int FLAG_MUTABLE = 1<<25;
+ public static final int FLAG_NO_CREATE = 1<<29;
+
+ public static PendingIntent getActivity(Context context, int requestCode,
+ Intent intent, int flags) {
+ throw new UnsupportedOperationException();
+ }
+
+ public static PendingIntent getActivityAsUser(Context context, int requestCode,
+ Intent intent, int flags, Bundle options, UserHandle user) {
+ throw new UnsupportedOperationException();
+ }
+
+ public static PendingIntent getActivities(Context context, int requestCode,
+ Intent[] intents, int flags, Bundle options) {
+ throw new UnsupportedOperationException();
+ }
+
+ public static PendingIntent getActivitiesAsUser(Context context, int requestCode,
+ Intent[] intents, int flags, Bundle options, UserHandle user) {
+ throw new UnsupportedOperationException();
+ }
+
+ public static PendingIntent getBroadcast(Context context, int requestCode,
+ Intent intent, int flags) {
+ throw new UnsupportedOperationException();
+ }
+
+ public static PendingIntent getBroadcastAsUser(Context context, int requestCode,
+ Intent intent, int flags, UserHandle userHandle) {
+ throw new UnsupportedOperationException();
+ }
+
+ public static PendingIntent getService(Context context, int requestCode,
+ Intent intent, int flags) {
+ throw new UnsupportedOperationException();
+ }
+
+ public static PendingIntent getForegroundService(Context context, int requestCode,
+ Intent intent, int flags) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/errorprone/tests/res/android/content/Intent.java b/errorprone/tests/res/android/content/Intent.java
new file mode 100644
index 000000000000..9d22d04b8cb8
--- /dev/null
+++ b/errorprone/tests/res/android/content/Intent.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+public class Intent {
+}
diff --git a/errorprone/tests/res/android/os/Bundle.java b/errorprone/tests/res/android/os/Bundle.java
new file mode 100644
index 000000000000..6d2f7b899502
--- /dev/null
+++ b/errorprone/tests/res/android/os/Bundle.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+public class Bundle {
+}
diff --git a/graphics/java/android/graphics/GraphicsStatsService.java b/graphics/java/android/graphics/GraphicsStatsService.java
index 2d6848b618a1..dc785c5b0309 100644
--- a/graphics/java/android/graphics/GraphicsStatsService.java
+++ b/graphics/java/android/graphics/GraphicsStatsService.java
@@ -175,7 +175,7 @@ public class GraphicsStatsService extends IGraphicsStats.Stub {
int uid = Binder.getCallingUid();
int pid = Binder.getCallingPid();
ParcelFileDescriptor pfd = null;
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
mAppOps.checkPackage(uid, packageName);
PackageInfo info = mContext.getPackageManager().getPackageInfoAsUser(
@@ -214,7 +214,7 @@ public class GraphicsStatsService extends IGraphicsStats.Stub {
}
}
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
pullGraphicsStatsImpl(lastFullDay, pulledData);
} finally {
diff --git a/graphics/java/android/graphics/RuntimeShader.java b/graphics/java/android/graphics/RuntimeShader.java
index 5a0b4a9b8086..63089e2d9d98 100644
--- a/graphics/java/android/graphics/RuntimeShader.java
+++ b/graphics/java/android/graphics/RuntimeShader.java
@@ -34,6 +34,7 @@ public class RuntimeShader extends Shader {
}
private byte[] mUniforms;
+ private Shader[] mInputShaders;
private boolean mIsOpaque;
/**
@@ -50,13 +51,30 @@ public class RuntimeShader extends Shader {
* @param isOpaque True if all pixels have alpha 1.0f.
*/
public RuntimeShader(@NonNull String sksl, @Nullable byte[] uniforms, boolean isOpaque) {
- this(sksl, uniforms, isOpaque, ColorSpace.get(ColorSpace.Named.SRGB));
+ this(sksl, uniforms, null, isOpaque, ColorSpace.get(ColorSpace.Named.SRGB));
}
- private RuntimeShader(@NonNull String sksl, @Nullable byte[] uniforms, boolean isOpaque,
- ColorSpace colorSpace) {
+ /**
+ * Creates a new RuntimeShader.
+ *
+ * @param sksl The text of SKSL program to run on the GPU.
+ * @param uniforms Array of parameters passed by the SKSL shader. Array size depends
+ * on number of uniforms declared by sksl.
+ * @param shaderInputs Array of shaders passed to the SKSL shader. Array size depends
+ * on the number of input shaders declared in the sksl
+ * @param isOpaque True if all pixels have alpha 1.0f.
+ */
+ public RuntimeShader(@NonNull String sksl, @Nullable byte[] uniforms,
+ @Nullable Shader[] shaderInputs, boolean isOpaque) {
+ this(sksl, uniforms, shaderInputs, isOpaque, ColorSpace.get(ColorSpace.Named.SRGB));
+ }
+
+ private RuntimeShader(@NonNull String sksl, @Nullable byte[] uniforms,
+ @Nullable Shader[] shaderInputs, boolean isOpaque,
+ ColorSpace colorSpace) {
super(colorSpace);
mUniforms = uniforms;
+ mInputShaders = shaderInputs;
mIsOpaque = isOpaque;
mNativeInstanceRuntimeShaderFactory = nativeCreateShaderFactory(sksl);
NoImagePreloadHolder.sRegistry.registerNativeAllocation(this,
@@ -74,15 +92,31 @@ public class RuntimeShader extends Shader {
discardNativeInstance();
}
+ /**
+ * Sets new values for the shaders that serve as inputs to this shader.
+ *
+ * @param shaderInputs Array of Shaders passed into the SKSL shader. Array size depends
+ * on number of input shaders declared by sksl.
+ */
+ public void updateInputShaders(@Nullable Shader[] shaderInputs) {
+ mInputShaders = shaderInputs;
+ discardNativeInstance();
+ }
+
/** @hide */
@Override
protected long createNativeInstance(long nativeMatrix) {
+ long[] nativeShaders = mInputShaders.length > 0 ? new long[mInputShaders.length] : null;
+ for (int i = 0; i < mInputShaders.length; i++) {
+ nativeShaders[i] = mInputShaders[i].getNativeInstance();
+ }
+
return nativeCreate(mNativeInstanceRuntimeShaderFactory, nativeMatrix, mUniforms,
- colorSpace().getNativeInstance(), mIsOpaque);
+ nativeShaders, colorSpace().getNativeInstance(), mIsOpaque);
}
private static native long nativeCreate(long shaderFactory, long matrix, byte[] inputs,
- long colorSpaceHandle, boolean isOpaque);
+ long[] shaderInputs, long colorSpaceHandle, boolean isOpaque);
private static native long nativeCreateShaderFactory(String sksl);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java
index 9c78fc5e57b8..9bb709f9a82a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java
@@ -27,11 +27,6 @@ import java.io.PrintWriter;
*/
public interface OneHanded {
/**
- * Return whether the device has one handed feature or not.
- */
- boolean hasOneHandedFeature();
-
- /**
* Return one handed settings enabled or not.
*/
boolean isOneHandedEnabled();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
index d060f6444463..7d039d4d92f6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java
@@ -30,9 +30,10 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.provider.Settings;
-import android.util.Log;
+import android.util.Slog;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.wm.shell.common.DisplayChangeController;
@@ -54,7 +55,6 @@ public class OneHandedController implements OneHanded {
static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode";
- private final boolean mHasOneHandedFeature;
private boolean mIsOneHandedEnabled;
private boolean mIsSwipeToNotificationEnabled;
private boolean mTaskChangeToExit;
@@ -77,7 +77,7 @@ public class OneHandedController implements OneHanded {
private final DisplayChangeController.OnDisplayChangingListener mRotationController =
(display, fromRotation, toRotation, wct) -> {
if (mDisplayAreaOrganizer != null) {
- mDisplayAreaOrganizer.onRotateDisplay(fromRotation, toRotation);
+ mDisplayAreaOrganizer.onRotateDisplay(fromRotation, toRotation, wct);
}
};
@@ -160,10 +160,16 @@ public class OneHandedController implements OneHanded {
};
/**
- * The static constructor method to create OneHnadedController.
+ * Creates {@link OneHandedController}, returns {@code null} if the feature is not supported.
*/
+ @Nullable
public static OneHandedController create(
Context context, DisplayController displayController) {
+ if (!SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false)) {
+ Slog.w(TAG, "Device doesn't support OneHanded feature");
+ return null;
+ }
+
OneHandedTutorialHandler tutorialHandler = new OneHandedTutorialHandler(context);
OneHandedAnimationController animationController =
new OneHandedAnimationController(context);
@@ -186,43 +192,30 @@ public class OneHandedController implements OneHanded {
OneHandedTutorialHandler tutorialHandler,
OneHandedGestureHandler gestureHandler,
IOverlayManager overlayManager) {
- mHasOneHandedFeature = SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false);
- if (!mHasOneHandedFeature) {
- Log.i(TAG, "Device config SUPPORT_ONE_HANDED_MODE off");
- mContext = null;
- mDisplayAreaOrganizer = null;
- mDisplayController = null;
- mTouchHandler = null;
- mTutorialHandler = null;
- mGestureHandler = null;
- mTimeoutHandler = null;
- mOverlayManager = null;
- } else {
- mContext = context;
- mDisplayAreaOrganizer = displayAreaOrganizer;
- mDisplayController = displayController;
- mTouchHandler = touchHandler;
- mTutorialHandler = tutorialHandler;
- mGestureHandler = gestureHandler;
- mOverlayManager = overlayManager;
-
- mOffSetFraction = SystemProperties.getInt(ONE_HANDED_MODE_OFFSET_PERCENTAGE, 50)
- / 100.0f;
- mIsOneHandedEnabled = OneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
- context.getContentResolver());
- mIsSwipeToNotificationEnabled =
- OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
- context.getContentResolver());
- mTimeoutHandler = OneHandedTimeoutHandler.get();
-
- mDisplayController.addDisplayChangingController(mRotationController);
-
- setupCallback();
- setupSettingObservers();
- setupTimeoutListener();
- setupGesturalOverlay();
- updateSettings();
- }
+ mContext = context;
+ mDisplayAreaOrganizer = displayAreaOrganizer;
+ mDisplayController = displayController;
+ mTouchHandler = touchHandler;
+ mTutorialHandler = tutorialHandler;
+ mGestureHandler = gestureHandler;
+ mOverlayManager = overlayManager;
+
+ mOffSetFraction = SystemProperties.getInt(ONE_HANDED_MODE_OFFSET_PERCENTAGE, 50)
+ / 100.0f;
+ mIsOneHandedEnabled = OneHandedSettingsUtil.getSettingsOneHandedModeEnabled(
+ context.getContentResolver());
+ mIsSwipeToNotificationEnabled =
+ OneHandedSettingsUtil.getSettingsSwipeToNotificationEnabled(
+ context.getContentResolver());
+ mTimeoutHandler = OneHandedTimeoutHandler.get();
+
+ mDisplayController.addDisplayChangingController(mRotationController);
+
+ setupCallback();
+ setupSettingObservers();
+ setupTimeoutListener();
+ setupGesturalOverlay();
+ updateSettings();
}
/**
@@ -249,11 +242,6 @@ public class OneHandedController implements OneHanded {
}
@Override
- public boolean hasOneHandedFeature() {
- return mHasOneHandedFeature;
- }
-
- @Override
public boolean isOneHandedEnabled() {
return mIsOneHandedEnabled;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
index 6bc838fcc8be..17418f934691 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizer.java
@@ -27,6 +27,7 @@ import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemProperties;
+import android.util.ArrayMap;
import android.util.Log;
import android.view.SurfaceControl;
import android.window.DisplayAreaInfo;
@@ -42,7 +43,6 @@ import com.android.wm.shell.common.DisplayController;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Objects;
@@ -76,7 +76,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
private int mEnterExitAnimationDurationMs;
@VisibleForTesting
- HashMap<DisplayAreaInfo, SurfaceControl> mDisplayAreaMap = new HashMap();
+ ArrayMap<DisplayAreaInfo, SurfaceControl> mDisplayAreaMap = new ArrayMap();
private DisplayController mDisplayController;
private OneHandedAnimationController mAnimationController;
private OneHandedSurfaceTransactionHelper.SurfaceControlTransactionFactory
@@ -117,12 +117,13 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
private Handler.Callback mUpdateCallback = (msg) -> {
SomeArgs args = (SomeArgs) msg.obj;
final Rect currentBounds = args.arg1 != null ? (Rect) args.arg1 : mDefaultDisplayBounds;
+ final WindowContainerTransaction wctFromRotate = (WindowContainerTransaction) args.arg2;
final int yOffset = args.argi2;
final int direction = args.argi3;
switch (msg.what) {
case MSG_RESET_IMMEDIATE:
- resetWindowsOffset();
+ resetWindowsOffset(wctFromRotate);
mDefaultDisplayBounds.set(currentBounds);
mLastVisualDisplayBounds.set(currentBounds);
finishOffset(0, TRANSITION_DIRECTION_EXIT);
@@ -165,47 +166,44 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
@NonNull SurfaceControl leash) {
Objects.requireNonNull(displayAreaInfo, "displayAreaInfo must not be null");
Objects.requireNonNull(leash, "leash must not be null");
-
- if (displayAreaInfo.featureId != FEATURE_ONE_HANDED) {
- Log.w(TAG, "Bypass onDisplayAreaAppeared()! displayAreaInfo=" + displayAreaInfo);
- return;
+ synchronized (this) {
+ if (mDisplayAreaMap.get(displayAreaInfo) == null) {
+ // mDefaultDisplayBounds may out of date after removeDisplayChangingController()
+ mDefaultDisplayBounds.set(getDisplayBounds());
+ mDisplayAreaMap.put(displayAreaInfo, leash);
+ }
}
- // mDefaultDisplayBounds may out of date after removeDisplayChangingController()
- mDefaultDisplayBounds.set(getDisplayBounds());
- mDisplayAreaMap.put(displayAreaInfo, leash);
}
@Override
public void onDisplayAreaVanished(@NonNull DisplayAreaInfo displayAreaInfo) {
Objects.requireNonNull(displayAreaInfo,
"Requires valid displayArea, and displayArea must not be null");
-
- if (!mDisplayAreaMap.containsKey(displayAreaInfo)) {
- Log.w(TAG, "Unrecognized token: " + displayAreaInfo.token);
- return;
+ synchronized (this) {
+ if (!mDisplayAreaMap.containsKey(displayAreaInfo)) {
+ Log.w(TAG, "Unrecognized token: " + displayAreaInfo.token);
+ return;
+ }
+ mDisplayAreaMap.remove(displayAreaInfo);
}
- mDisplayAreaMap.remove(displayAreaInfo);
}
@Override
public void unregisterOrganizer() {
super.unregisterOrganizer();
- resetWindowsOffset();
-
- // Ensure all cached instance are cleared after resetWindowsOffset
- mUpdateHandler.post(() -> {
- if (mDisplayAreaMap != null && !mDisplayAreaMap.isEmpty()) {
- mDisplayAreaMap.clear();
- }
- });
+ mUpdateHandler.post(() -> resetWindowsOffset(null));
}
/**
* Handler for display rotation changes by below policy which
- * handles 90 degree display rotation changes {@link Surface.Rotation}
+ * handles 90 degree display rotation changes {@link Surface.Rotation}.
*
+ * @param fromRotation starting rotation of the display.
+ * @param toRotation target rotation of the display (after rotating).
+ * @param wct A task transaction {@link WindowContainerTransaction} from
+ * {@link DisplayChangeController} to populate.
*/
- public void onRotateDisplay(int fromRotation, int toRotation) {
+ public void onRotateDisplay(int fromRotation, int toRotation, WindowContainerTransaction wct) {
// Stop one handed without animation and reset cropped size immediately
final Rect newBounds = new Rect(mDefaultDisplayBounds);
final boolean isOrientationDiff = Math.abs(fromRotation - toRotation) % 2 == 1;
@@ -214,6 +212,7 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
newBounds.set(newBounds.left, newBounds.top, newBounds.bottom, newBounds.right);
SomeArgs args = SomeArgs.obtain();
args.arg1 = newBounds;
+ args.arg2 = wct;
args.argi1 = 0 /* xOffset */;
args.argi2 = 0 /* yOffset */;
args.argi3 = TRANSITION_DIRECTION_EXIT;
@@ -239,18 +238,19 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
throw new RuntimeException("Callers should call scheduleOffset() instead of this "
+ "directly");
}
- final WindowContainerTransaction wct = new WindowContainerTransaction();
- mDisplayAreaMap.forEach(
- (key, leash) -> {
- animateWindows(leash, fromBounds, toBounds, direction,
- durationMs);
- wct.setBounds(key.token, toBounds);
- });
- applyTransaction(wct);
+ synchronized (this) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ mDisplayAreaMap.forEach(
+ (key, leash) -> {
+ animateWindows(leash, fromBounds, toBounds, direction, durationMs);
+ wct.setBounds(key.token, toBounds);
+ });
+ applyTransaction(wct);
+ }
}
- private void resetWindowsOffset() {
- mUpdateHandler.post(() -> {
+ private void resetWindowsOffset(WindowContainerTransaction wct) {
+ synchronized (this) {
final SurfaceControl.Transaction tx =
mSurfaceControlTransactionFactory.getTransaction();
mDisplayAreaMap.forEach(
@@ -262,9 +262,13 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
}
tx.setPosition(leash, 0, 0)
.setWindowCrop(leash, -1/* reset */, -1/* reset */);
+ // DisplayRotationController will applyTransaction() after finish rotating
+ if (wct != null) {
+ wct.setBounds(key.token, null/* reset */);
+ }
});
tx.apply();
- });
+ }
}
private void animateWindows(SurfaceControl leash, Rect fromBounds, Rect toBounds,
@@ -335,8 +339,8 @@ public class OneHandedDisplayAreaOrganizer extends DisplayAreaOrganizer {
}
@VisibleForTesting
- Handler getUpdateHandler() {
- return mUpdateHandler;
+ void setUpdateHandler(Handler updateHandler) {
+ mUpdateHandler = updateHandler;
}
/**
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
new file mode 100644
index 000000000000..0cedc0a7147f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/ImeAppHelper.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.helpers
+
+import android.app.Instrumentation
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.helpers.FIND_TIMEOUT
+import com.android.server.wm.flicker.helpers.waitForIME
+import org.junit.Assert
+
+open class ImeAppHelper(
+ instr: Instrumentation,
+ launcherName: String = "ImeApp",
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : FlickerAppHelper(instr, launcherName, launcherStrategy) {
+ open fun openIME(device: UiDevice) {
+ val editText = device.wait(
+ Until.findObject(By.res(getPackage(), "plain_text_input")),
+ FIND_TIMEOUT)
+ Assert.assertNotNull("Text field not found, this usually happens when the device " +
+ "was left in an unknown state (e.g. in split screen)", editText)
+ editText.click()
+ if (!device.waitForIME()) {
+ Assert.fail("IME did not appear")
+ }
+ }
+
+ open fun closeIME(device: UiDevice) {
+ device.pressBack()
+ // Using only the AccessibilityInfo it is not possible to identify if the IME is active
+ device.waitForIdle(1000)
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index c3c576d3f28c..010aa0d7d832 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -39,7 +39,7 @@ import org.junit.runners.Parameterized
/**
* Test Pip launch.
- * To run this test: `atest FlickerTests:PipToAppTest`
+ * To run this test: `atest WMShellFlickerTests:PipToAppTest`
*/
@RequiresDevice
@RunWith(Parameterized::class)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
new file mode 100644
index 000000000000..43e022538685
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.pip
+
+import android.content.ComponentName
+import android.graphics.Region
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import android.util.Log
+import android.view.Surface
+import android.view.WindowManager
+import androidx.test.filters.RequiresDevice
+import com.android.compatibility.common.util.SystemUtil
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.dsl.runWithFlicker
+import com.android.server.wm.flicker.helpers.closePipWindow
+import com.android.server.wm.flicker.helpers.hasPipWindow
+import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.wm.shell.flicker.helpers.ImeAppHelper
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+import java.io.IOException
+
+/**
+ * Test Pip launch.
+ * To run this test: `atest WMShellFlickerTests:PipKeyboardTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class PipKeyboardTest(
+ rotationName: String,
+ rotation: Int
+) : PipTestBase(rotationName, rotation) {
+ private val windowManager: WindowManager =
+ instrumentation.context.getSystemService(WindowManager::class.java)
+
+ private val keyboardApp = ImeAppHelper(instrumentation, "ImeApp",
+ LauncherStrategyFactory.getInstance(instrumentation).launcherStrategy)
+
+ private val KEYBOARD_ACTIVITY: ComponentName = ComponentName.createRelative(
+ "com.android.wm.shell.flicker.testapp", ".ImeActivity")
+ private val PIP_ACTIVITY_WINDOW_NAME = "PipActivity"
+ private val INPUT_METHOD_WINDOW_NAME = "InputMethod"
+
+ private val testRepetitions = 10
+
+ private val keyboardScenario: FlickerBuilder
+ get() = FlickerBuilder(instrumentation).apply {
+ repeat { testRepetitions }
+ // disable layer tracing
+ withLayerTracing { null }
+ setup {
+ test {
+ device.wakeUpAndGoToHomeScreen()
+ device.pressHome()
+ // launch our target pip app
+ testApp.open()
+ this.setRotation(rotation)
+ testApp.clickEnterPipButton(device)
+ // open an app with an input field and a keyboard
+ // UiAutomator doesn't support to launch the multiple Activities in a task.
+ // So use launchActivity() for the Keyboard Activity.
+ launchActivity(KEYBOARD_ACTIVITY)
+ }
+ }
+ teardown {
+ test {
+ keyboardApp.exit()
+
+ if (device.hasPipWindow()) {
+ device.closePipWindow()
+ }
+ testApp.exit()
+ this.setRotation(Surface.ROTATION_0)
+ }
+ }
+ }
+
+ /** Ensure the pip window remains visible throughout any keyboard interactions. */
+ @Test
+ fun pipWindow_doesNotLeaveTheScreen_onKeyboardOpenClose() {
+ val testTag = "pipWindow_doesNotLeaveTheScreen_onKeyboardOpenClose"
+ runWithFlicker(keyboardScenario) {
+ withTestName { testTag }
+ transitions {
+ // open the soft keyboard
+ keyboardApp.openIME(device)
+
+ // then close it again
+ keyboardApp.closeIME(device)
+ }
+ assertions {
+ windowManagerTrace {
+ all("PiP window must remain inside visible bounds") {
+ coversAtMostRegion(
+ partialWindowTitle = "PipActivity",
+ region = Region(windowManager.maximumWindowMetrics.bounds)
+ )
+ }
+ }
+ }
+ }
+ }
+
+ /** Ensure the pip window does not obscure the keyboard. */
+ @Test
+ fun pipWindow_doesNotObscure_keyboard() {
+ val testTag = "pipWindow_doesNotObscure_keyboard"
+ runWithFlicker(keyboardScenario) {
+ withTestName { testTag }
+ transitions {
+ // open the soft keyboard
+ keyboardApp.openIME(device)
+ }
+ teardown {
+ eachRun {
+ // close the keyboard
+ keyboardApp.closeIME(device)
+ }
+ }
+ assertions {
+ windowManagerTrace {
+ end {
+ isAboveWindow(INPUT_METHOD_WINDOW_NAME, PIP_ACTIVITY_WINDOW_NAME)
+ }
+ }
+ }
+ }
+ }
+
+ private fun launchActivity(
+ activity: ComponentName? = null,
+ action: String? = null,
+ flags: Set<Int> = setOf(),
+ boolExtras: Map<String, Boolean> = mapOf(),
+ intExtras: Map<String, Int> = mapOf(),
+ stringExtras: Map<String, String> = mapOf()
+ ) {
+ require(activity != null || !action.isNullOrBlank()) {
+ "Cannot launch an activity with neither activity name nor action!"
+ }
+ val command = composeCommand(
+ "start", activity, action, flags, boolExtras, intExtras, stringExtras)
+ executeShellCommand(command)
+ }
+
+ private fun composeCommand(
+ command: String,
+ activity: ComponentName?,
+ action: String?,
+ flags: Set<Int>,
+ boolExtras: Map<String, Boolean>,
+ intExtras: Map<String, Int>,
+ stringExtras: Map<String, String>
+ ): String = buildString {
+ append("am ")
+ append(command)
+ activity?.let {
+ append(" -n ")
+ append(it.flattenToShortString())
+ }
+ action?.let {
+ append(" -a ")
+ append(it)
+ }
+ flags.forEach {
+ append(" -f ")
+ append(it)
+ }
+ boolExtras.forEach {
+ append(it.withFlag("ez"))
+ }
+ intExtras.forEach {
+ append(it.withFlag("ei"))
+ }
+ stringExtras.forEach {
+ append(it.withFlag("es"))
+ }
+ }
+
+ private fun Map.Entry<String, *>.withFlag(flag: String): String = " --$flag $key $value"
+
+ private fun executeShellCommand(cmd: String): String {
+ try {
+ return SystemUtil.runShellCommand(instrumentation, cmd)
+ } catch (e: IOException) {
+ Log.e("FlickerTests", "Error running shell command: $cmd")
+ throw e
+ }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<Array<Any>> {
+ val supportedRotations = intArrayOf(Surface.ROTATION_0)
+ return supportedRotations.map { arrayOf(Surface.rotationToString(it), it) }
+ }
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml
index 95dc1d48eee8..3b66c58414e0 100644
--- a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/AndroidManifest.xml
@@ -33,5 +33,14 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
+ <activity android:name=".ImeActivity"
+ android:taskAffinity="com.android.wm.shell.flicker.testapp.ImeActivity"
+ android:label="ImeApp"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_ime.xml b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_ime.xml
new file mode 100644
index 000000000000..4708cfd48381
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/res/layout/activity_ime.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:focusableInTouchMode="true"
+ android:background="@android:color/holo_green_light">
+ <EditText android:id="@+id/plain_text_input"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:inputType="text"/>
+</LinearLayout>
diff --git a/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/ImeActivity.java b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/ImeActivity.java
new file mode 100644
index 000000000000..856728715c1c
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/test-apps/flickerapp/src/com/android/wm/shell/flicker/testapp/ImeActivity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.testapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+public class ImeActivity extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ WindowManager.LayoutParams p = getWindow().getAttributes();
+ p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
+ .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+ getWindow().setAttributes(p);
+ setContentView(R.layout.activity_ime);
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java
index 5ff94b6308ef..6d1a3c472245 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedDisplayAreaOrganizerTest.java
@@ -25,6 +25,7 @@ import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -38,18 +39,17 @@ import android.view.SurfaceControl;
import android.window.DisplayAreaInfo;
import android.window.IWindowContainerToken;
import android.window.WindowContainerToken;
+import android.window.WindowContainerTransaction;
import androidx.test.filters.SmallTest;
import com.android.wm.shell.common.DisplayController;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.mockito.Spy;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -65,6 +65,7 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {
OneHandedAnimationController.OneHandedTransitionAnimator mFakeAnimator;
WindowContainerToken mToken;
SurfaceControl mLeash;
+ TestableLooper mTestableLooper;
@Mock
IWindowContainerToken mMockRealToken;
@Mock
@@ -77,12 +78,16 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {
DisplayController mMockDisplayController;
@Mock
SurfaceControl mMockLeash;
- @Spy
- Handler mUpdateHandler;
+ @Mock
+ WindowContainerTransaction mMockWindowContainerTransaction;
+
+ Handler mSpyUpdateHandler;
+ Handler.Callback mUpdateCallback = (msg) -> false;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ mTestableLooper = TestableLooper.get(this);
mToken = new WindowContainerToken(mMockRealToken);
mLeash = new SurfaceControl();
mDisplay = mContext.getDisplay();
@@ -107,17 +112,14 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {
mMockDisplayController,
mMockAnimationController,
mTutorialHandler);
- mUpdateHandler = mDisplayAreaOrganizer.getUpdateHandler();
- }
-
- @Test
- public void testGetDisplayAreaUpdateHandler_isNotNull() {
- assertThat(mUpdateHandler).isNotNull();
+ mSpyUpdateHandler = spy(new Handler(OneHandedThread.get().getLooper(), mUpdateCallback));
+ mDisplayAreaOrganizer.setUpdateHandler(mSpyUpdateHandler);
}
@Test
public void testOnDisplayAreaAppeared() {
mDisplayAreaOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash);
+ mTestableLooper.processAllMessages();
verify(mMockAnimationController, never()).getAnimator(any(), any(), any());
}
@@ -125,162 +127,195 @@ public class OneHandedDisplayAreaOrganizerTest extends OneHandedTestCase {
@Test
public void testOnDisplayAreaVanished() {
mDisplayAreaOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash);
+ mTestableLooper.processAllMessages();
mDisplayAreaOrganizer.onDisplayAreaVanished(mDisplayAreaInfo);
- }
- @Test
- public void testOnDisplayAreaInfoChanged_updateDisplayAreaInfo() {
- final DisplayAreaInfo newDisplayAreaInfo = new DisplayAreaInfo(mToken, DEFAULT_DISPLAY,
- FEATURE_ONE_HANDED);
- mDisplayAreaOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash);
- mDisplayAreaOrganizer.onDisplayAreaInfoChanged(newDisplayAreaInfo);
-
- assertThat(mDisplayAreaOrganizer.mDisplayAreaMap.containsKey(mDisplayAreaInfo)).isTrue();
+ assertThat(mDisplayAreaOrganizer.mDisplayAreaMap).isEmpty();
}
- @Ignore("b/160848002")
@Test
public void testScheduleOffset() {
final int xOffSet = 0;
final int yOffSet = 100;
-
- TestableLooper.get(this).processAllMessages();
- mDisplayAreaOrganizer.onDisplayAreaAppeared(mDisplayAreaInfo, mLeash);
mDisplayAreaOrganizer.scheduleOffset(xOffSet, yOffSet);
+ mTestableLooper.processAllMessages();
- assertThat(mUpdateHandler.hasMessages(
- OneHandedDisplayAreaOrganizer.MSG_OFFSET_ANIMATE)).isEqualTo(true);
+ verify(mSpyUpdateHandler).sendMessage(any());
}
- @Ignore("b/160848002")
@Test
- public void testRotation_portraitToLandscape() {
+ public void testRotation_portrait_0_to_landscape_90() {
when(mMockLeash.isValid()).thenReturn(false);
// Rotate 0 -> 90
- TestableLooper.get(this).processAllMessages();
- mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_0, Surface.ROTATION_90);
+ mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_0, Surface.ROTATION_90,
+ mMockWindowContainerTransaction);
+ mTestableLooper.processAllMessages();
- assertThat(mUpdateHandler.hasMessages(
- OneHandedDisplayAreaOrganizer.MSG_RESET_IMMEDIATE)).isEqualTo(true);
+ verify(mSpyUpdateHandler).sendMessage(any());
+ }
+ @Test
+ public void testRotation_portrait_0_to_seascape_270() {
+ when(mMockLeash.isValid()).thenReturn(false);
// Rotate 0 -> 270
- TestableLooper.get(this).processAllMessages();
- mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_0, Surface.ROTATION_270);
+ mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_0, Surface.ROTATION_270,
+ mMockWindowContainerTransaction);
+ mTestableLooper.processAllMessages();
- assertThat(mUpdateHandler.hasMessages(
- OneHandedDisplayAreaOrganizer.MSG_RESET_IMMEDIATE)).isEqualTo(true);
+ verify(mSpyUpdateHandler).sendMessage(any());
+ }
+ @Test
+ public void testRotation_portrait_180_to_landscape_90() {
+ when(mMockLeash.isValid()).thenReturn(false);
// Rotate 180 -> 90
- TestableLooper.get(this).processAllMessages();
- mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_180, Surface.ROTATION_90);
+ mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_180, Surface.ROTATION_90,
+ mMockWindowContainerTransaction);
+ mTestableLooper.processAllMessages();
- assertThat(mUpdateHandler.hasMessages(
- OneHandedDisplayAreaOrganizer.MSG_RESET_IMMEDIATE)).isEqualTo(true);
+ verify(mSpyUpdateHandler).sendMessage(any());
+ }
+ @Test
+ public void testRotation_portrait_180_to_seascape_270() {
+ when(mMockLeash.isValid()).thenReturn(false);
// Rotate 180 -> 270
- TestableLooper.get(this).processAllMessages();
- mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_180, Surface.ROTATION_270);
+ mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_180, Surface.ROTATION_270,
+ mMockWindowContainerTransaction);
+ mTestableLooper.processAllMessages();
- assertThat(mUpdateHandler.hasMessages(
- OneHandedDisplayAreaOrganizer.MSG_RESET_IMMEDIATE)).isEqualTo(true);
+ verify(mSpyUpdateHandler).sendMessage(any());
}
- @Ignore("b/160848002")
@Test
- public void testRotation_landscapeToPortrait() {
+ public void testRotation_landscape_90_to_portrait_0() {
when(mMockLeash.isValid()).thenReturn(false);
// Rotate 90 -> 0
- TestableLooper.get(this).processAllMessages();
- mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_90, Surface.ROTATION_0);
+ mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_90, Surface.ROTATION_0,
+ mMockWindowContainerTransaction);
+ mTestableLooper.processAllMessages();
- assertThat(mUpdateHandler.hasMessages(
- OneHandedDisplayAreaOrganizer.MSG_RESET_IMMEDIATE)).isEqualTo(true);
+ verify(mSpyUpdateHandler).sendMessage(any());
+ }
+ @Test
+ public void testRotation_landscape_90_to_portrait_180() {
+ when(mMockLeash.isValid()).thenReturn(false);
// Rotate 90 -> 180
- TestableLooper.get(this).processAllMessages();
- mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_90, Surface.ROTATION_180);
+ mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_90, Surface.ROTATION_180,
+ mMockWindowContainerTransaction);
+ mTestableLooper.processAllMessages();
- assertThat(mUpdateHandler.hasMessages(
- OneHandedDisplayAreaOrganizer.MSG_RESET_IMMEDIATE)).isEqualTo(true);
+ verify(mSpyUpdateHandler).sendMessage(any());
+ }
+ @Test
+ public void testRotation_Seascape_270_to_portrait_0() {
+ when(mMockLeash.isValid()).thenReturn(false);
// Rotate 270 -> 0
- TestableLooper.get(this).processAllMessages();
- mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_270, Surface.ROTATION_0);
+ mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_270, Surface.ROTATION_0,
+ mMockWindowContainerTransaction);
+ mTestableLooper.processAllMessages();
- assertThat(mUpdateHandler.hasMessages(
- OneHandedDisplayAreaOrganizer.MSG_RESET_IMMEDIATE)).isEqualTo(true);
+ verify(mSpyUpdateHandler).sendMessage(any());
+ }
+ @Test
+ public void testRotation_seascape_90_to_portrait_180() {
+ when(mMockLeash.isValid()).thenReturn(false);
// Rotate 270 -> 180
- TestableLooper.get(this).processAllMessages();
- mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_270, Surface.ROTATION_180);
+ mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_270, Surface.ROTATION_180,
+ mMockWindowContainerTransaction);
+ mTestableLooper.processAllMessages();
- assertThat(mUpdateHandler.hasMessages(
- OneHandedDisplayAreaOrganizer.MSG_RESET_IMMEDIATE)).isEqualTo(true);
+ verify(mSpyUpdateHandler).sendMessage(any());
}
- @Ignore("b/160848002")
@Test
- public void testRotation_portraitToPortrait() {
+ public void testRotation_portrait_0_to_portrait_0() {
when(mMockLeash.isValid()).thenReturn(false);
// Rotate 0 -> 0
- TestableLooper.get(this).processAllMessages();
- mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_0, Surface.ROTATION_0);
+ mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_0, Surface.ROTATION_0,
+ mMockWindowContainerTransaction);
+ mTestableLooper.processAllMessages();
- assertThat(mUpdateHandler.hasMessages(
- OneHandedDisplayAreaOrganizer.MSG_RESET_IMMEDIATE)).isEqualTo(false);
+ verify(mSpyUpdateHandler, never()).sendMessage(any());
+ }
+ @Test
+ public void testRotation_portrait_0_to_portrait_180() {
+ when(mMockLeash.isValid()).thenReturn(false);
// Rotate 0 -> 180
- TestableLooper.get(this).processAllMessages();
- mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_0, Surface.ROTATION_180);
+ mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_0, Surface.ROTATION_180,
+ mMockWindowContainerTransaction);
+ mTestableLooper.processAllMessages();
- assertThat(mUpdateHandler.hasMessages(
- OneHandedDisplayAreaOrganizer.MSG_RESET_IMMEDIATE)).isEqualTo(false);
+ verify(mSpyUpdateHandler, never()).sendMessage(any());
+ }
+ @Test
+ public void testRotation_portrait_180_to_portrait_180() {
+ when(mMockLeash.isValid()).thenReturn(false);
// Rotate 180 -> 180
- TestableLooper.get(this).processAllMessages();
- mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_180, Surface.ROTATION_180);
+ mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_180, Surface.ROTATION_180,
+ mMockWindowContainerTransaction);
+ mTestableLooper.processAllMessages();
- assertThat(mUpdateHandler.hasMessages(
- OneHandedDisplayAreaOrganizer.MSG_RESET_IMMEDIATE)).isEqualTo(false);
+ verify(mSpyUpdateHandler, never()).sendMessage(any());
+ }
- // Rotate 180 -> 180
- TestableLooper.get(this).processAllMessages();
- mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_180, Surface.ROTATION_0);
+ @Test
+ public void testRotation_portrait_180_to_portrait_0() {
+ when(mMockLeash.isValid()).thenReturn(false);
+ // Rotate 180 -> 0
+ mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_180, Surface.ROTATION_0,
+ mMockWindowContainerTransaction);
+ mTestableLooper.processAllMessages();
- assertThat(mUpdateHandler.hasMessages(
- OneHandedDisplayAreaOrganizer.MSG_RESET_IMMEDIATE)).isEqualTo(false);
+ verify(mSpyUpdateHandler, never()).sendMessage(any());
}
- @Ignore("b/160848002")
@Test
- public void testRotation_landscapeToLandscape() {
+ public void testRotation_landscape_90_to_landscape_90() {
when(mMockLeash.isValid()).thenReturn(false);
// Rotate 90 -> 90
- TestableLooper.get(this).processAllMessages();
- mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_90, Surface.ROTATION_90);
+ mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_90, Surface.ROTATION_90,
+ mMockWindowContainerTransaction);
+ mTestableLooper.processAllMessages();
- assertThat(mUpdateHandler.hasMessages(
- OneHandedDisplayAreaOrganizer.MSG_RESET_IMMEDIATE)).isEqualTo(false);
+ verify(mSpyUpdateHandler, never()).sendMessage(any());
+ }
+ @Test
+ public void testRotation_landscape_90_to_seascape_270() {
+ when(mMockLeash.isValid()).thenReturn(false);
// Rotate 90 -> 270
- TestableLooper.get(this).processAllMessages();
- mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_90, Surface.ROTATION_270);
+ mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_90, Surface.ROTATION_270,
+ mMockWindowContainerTransaction);
+ mTestableLooper.processAllMessages();
- assertThat(mUpdateHandler.hasMessages(
- OneHandedDisplayAreaOrganizer.MSG_RESET_IMMEDIATE)).isEqualTo(false);
+ verify(mSpyUpdateHandler, never()).sendMessage(any());
+ }
+ @Test
+ public void testRotation_seascape_270_to_seascape_270() {
+ when(mMockLeash.isValid()).thenReturn(false);
// Rotate 270 -> 270
- TestableLooper.get(this).processAllMessages();
- mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_270, Surface.ROTATION_270);
+ mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_270, Surface.ROTATION_270,
+ mMockWindowContainerTransaction);
+ mTestableLooper.processAllMessages();
- assertThat(mUpdateHandler.hasMessages(
- OneHandedDisplayAreaOrganizer.MSG_RESET_IMMEDIATE)).isEqualTo(false);
+ verify(mSpyUpdateHandler, never()).sendMessage(any());
+ }
+ @Test
+ public void testRotation_seascape_90_to_landscape_90() {
+ when(mMockLeash.isValid()).thenReturn(false);
// Rotate 270 -> 90
- TestableLooper.get(this).processAllMessages();
- mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_270, Surface.ROTATION_90);
+ mDisplayAreaOrganizer.onRotateDisplay(Surface.ROTATION_270, Surface.ROTATION_90,
+ mMockWindowContainerTransaction);
+ mTestableLooper.processAllMessages();
- assertThat(mUpdateHandler.hasMessages(
- OneHandedDisplayAreaOrganizer.MSG_RESET_IMMEDIATE)).isEqualTo(false);
+ verify(mSpyUpdateHandler, never()).sendMessage(any());
}
}
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index e76aace601be..e36e35504494 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -211,14 +211,26 @@ static jlong ComposeShader_create(JNIEnv* env, jobject o, jlong matrixPtr,
///////////////////////////////////////////////////////////////////////////////////////////////
static jlong RuntimeShader_create(JNIEnv* env, jobject, jlong shaderFactory, jlong matrixPtr,
- jbyteArray inputs, jlong colorSpaceHandle, jboolean isOpaque) {
+ jbyteArray inputs, jlongArray inputShaders, jlong colorSpaceHandle, jboolean isOpaque) {
SkRuntimeEffect* effect = reinterpret_cast<SkRuntimeEffect*>(shaderFactory);
AutoJavaByteArray arInputs(env, inputs);
+ std::vector<sk_sp<SkShader>> shaderVector;
+ if (inputShaders) {
+ jsize shaderCount = env->GetArrayLength(inputShaders);
+ shaderVector.resize(shaderCount);
+ jlong* arrayPtr = env->GetLongArrayElements(inputShaders, NULL);
+ for (int i = 0; i < shaderCount; i++) {
+ shaderVector[i] = sk_ref_sp(reinterpret_cast<SkShader*>(arrayPtr[i]));
+ }
+ env->ReleaseLongArrayElements(inputShaders, arrayPtr, 0);
+ }
+
sk_sp<SkData> fData;
fData = SkData::MakeWithCopy(arInputs.ptr(), arInputs.length());
const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- sk_sp<SkShader> shader = effect->makeShader(fData, nullptr, 0, matrix, isOpaque == JNI_TRUE);
+ sk_sp<SkShader> shader = effect->makeShader(fData, shaderVector.data(), shaderVector.size(),
+ matrix, isOpaque == JNI_TRUE);
ThrowIAE_IfNull(env, shader);
return reinterpret_cast<jlong>(shader.release());
@@ -280,7 +292,7 @@ static const JNINativeMethod gComposeShaderMethods[] = {
static const JNINativeMethod gRuntimeShaderMethods[] = {
{ "nativeGetFinalizer", "()J", (void*)RuntimeShader_getNativeFinalizer },
- { "nativeCreate", "(JJ[BJZ)J", (void*)RuntimeShader_create },
+ { "nativeCreate", "(JJ[B[JJZ)J", (void*)RuntimeShader_create },
{ "nativeCreateShaderFactory", "(Ljava/lang/String;)J",
(void*)RuntimeShader_createShaderFactory },
};
diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp
index 66aa8c203799..3baff7ea8f90 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.cpp
+++ b/libs/hwui/pipeline/skia/ShaderCache.cpp
@@ -15,7 +15,7 @@
*/
#include "ShaderCache.h"
-#include <GrContext.h>
+#include <GrDirectContext.h>
#include <log/log.h>
#include <openssl/sha.h>
#include <algorithm>
@@ -206,7 +206,7 @@ void ShaderCache::store(const SkData& key, const SkData& data) {
}
}
-void ShaderCache::onVkFrameFlushed(GrContext* context) {
+void ShaderCache::onVkFrameFlushed(GrDirectContext* context) {
{
std::lock_guard<std::mutex> lock(mMutex);
diff --git a/libs/hwui/pipeline/skia/ShaderCache.h b/libs/hwui/pipeline/skia/ShaderCache.h
index 5b8e668a56f4..4dcc9fb49802 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.h
+++ b/libs/hwui/pipeline/skia/ShaderCache.h
@@ -80,7 +80,7 @@ public:
* Pipeline cache is saved on disk only if the size of the data has changed or there was
* a new shader compiled.
*/
- void onVkFrameFlushed(GrContext* context);
+ void onVkFrameFlushed(GrDirectContext* context);
private:
// Creation and (the lack of) destruction is handled internally.
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index b57dee4897ac..85924c5e8939 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -61,7 +61,7 @@ CacheManager::CacheManager()
SkGraphics::SetFontCacheLimit(mMaxCpuFontCacheBytes);
}
-void CacheManager::reset(sk_sp<GrContext> context) {
+void CacheManager::reset(sk_sp<GrDirectContext> context) {
if (context != mGrContext) {
destroy();
}
diff --git a/libs/hwui/renderthread/CacheManager.h b/libs/hwui/renderthread/CacheManager.h
index b009cc4f48f2..0a6b8dc26cc3 100644
--- a/libs/hwui/renderthread/CacheManager.h
+++ b/libs/hwui/renderthread/CacheManager.h
@@ -18,7 +18,7 @@
#define CACHEMANAGER_H
#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
-#include <GrContext.h>
+#include <GrDirectContext.h>
#endif
#include <SkSurface.h>
#include <utils/String8.h>
@@ -58,13 +58,13 @@ private:
explicit CacheManager();
#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
- void reset(sk_sp<GrContext> grContext);
+ void reset(sk_sp<GrDirectContext> grContext);
#endif
void destroy();
const size_t mMaxSurfaceArea;
#ifdef __ANDROID__ // Layoutlib does not support hardware acceleration
- sk_sp<GrContext> mGrContext;
+ sk_sp<GrDirectContext> mGrContext;
#endif
const size_t mMaxResourceBytes;
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index a04738d6a6f0..aceb5a528fc8 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -27,7 +27,7 @@
#include <SkRect.h>
#include <utils/RefBase.h>
-class GrContext;
+class GrDirectContext;
struct ANativeWindow;
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
index 1da09b454da7..acf4931d6144 100644
--- a/libs/hwui/renderthread/VulkanSurface.cpp
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -16,6 +16,7 @@
#include "VulkanSurface.h"
+#include <GrDirectContext.h>
#include <SkSurface.h>
#include <algorithm>
@@ -117,7 +118,7 @@ static bool ConnectAndSetWindowDefaults(ANativeWindow* window) {
VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode,
SkColorType colorType, sk_sp<SkColorSpace> colorSpace,
- GrContext* grContext, const VulkanManager& vkManager,
+ GrDirectContext* grContext, const VulkanManager& vkManager,
uint32_t extraBuffers) {
// Connect and set native window to default configurations.
if (!ConnectAndSetWindowDefaults(window)) {
@@ -310,7 +311,7 @@ bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& window
}
VulkanSurface::VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo,
- GrContext* grContext)
+ GrDirectContext* grContext)
: mNativeWindow(window), mWindowInfo(windowInfo), mGrContext(grContext) {}
VulkanSurface::~VulkanSurface() {
diff --git a/libs/hwui/renderthread/VulkanSurface.h b/libs/hwui/renderthread/VulkanSurface.h
index 40a44b11c0bc..409921bdfdd7 100644
--- a/libs/hwui/renderthread/VulkanSurface.h
+++ b/libs/hwui/renderthread/VulkanSurface.h
@@ -35,7 +35,7 @@ class VulkanManager;
class VulkanSurface {
public:
static VulkanSurface* Create(ANativeWindow* window, ColorMode colorMode, SkColorType colorType,
- sk_sp<SkColorSpace> colorSpace, GrContext* grContext,
+ sk_sp<SkColorSpace> colorSpace, GrDirectContext* grContext,
const VulkanManager& vkManager, uint32_t extraBuffers);
~VulkanSurface();
@@ -101,7 +101,7 @@ private:
SkMatrix preTransform;
};
- VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo, GrContext* grContext);
+ VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo, GrDirectContext* grContext);
static bool InitializeWindowInfoStruct(ANativeWindow* window, ColorMode colorMode,
SkColorType colorType, sk_sp<SkColorSpace> colorSpace,
const VulkanManager& vkManager, uint32_t extraBuffers,
@@ -119,7 +119,7 @@ private:
sp<ANativeWindow> mNativeWindow;
WindowInfo mWindowInfo;
- GrContext* mGrContext;
+ GrDirectContext* mGrContext;
uint32_t mPresentCount = 0;
NativeBufferInfo* mCurrentBufferInfo = nullptr;
diff --git a/media/java/android/media/midi/MidiDeviceServer.java b/media/java/android/media/midi/MidiDeviceServer.java
index 51d552066bc6..d5916b9bd6ab 100644
--- a/media/java/android/media/midi/MidiDeviceServer.java
+++ b/media/java/android/media/midi/MidiDeviceServer.java
@@ -384,14 +384,14 @@ public final class MidiDeviceServer implements Closeable {
private void updateDeviceStatus() {
// clear calling identity, since we may be in a Binder call from one of our clients
- long identityToken = Binder.clearCallingIdentity();
-
- MidiDeviceStatus status = new MidiDeviceStatus(mDeviceInfo, mInputPortOpen,
- mOutputPortOpenCount);
- if (mCallback != null) {
- mCallback.onDeviceStatusChanged(this, status);
- }
+ final long identityToken = Binder.clearCallingIdentity();
try {
+ MidiDeviceStatus status = new MidiDeviceStatus(mDeviceInfo, mInputPortOpen,
+ mOutputPortOpenCount);
+ if (mCallback != null) {
+ mCallback.onDeviceStatusChanged(this, status);
+ }
+
mMidiManager.setDeviceStatus(mServer, status);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException in updateDeviceStatus");
diff --git a/media/java/android/media/permission/ClearCallingIdentityContext.java b/media/java/android/media/permission/ClearCallingIdentityContext.java
index 364a2e800afe..2d58b246a3c6 100644
--- a/media/java/android/media/permission/ClearCallingIdentityContext.java
+++ b/media/java/android/media/permission/ClearCallingIdentityContext.java
@@ -47,11 +47,13 @@ public class ClearCallingIdentityContext implements SafeCloseable {
return new ClearCallingIdentityContext();
}
+ @SuppressWarnings("AndroidFrameworkBinderIdentity")
private ClearCallingIdentityContext() {
mRestoreKey = Binder.clearCallingIdentity();
}
@Override
+ @SuppressWarnings("AndroidFrameworkBinderIdentity")
public void close() {
Binder.restoreCallingIdentity(mRestoreKey);
}
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 5fd8f7318543..1557ea632b66 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -44,11 +44,11 @@ interface ISessionManager {
void dispatchMediaKeyEvent(String packageName, boolean asSystemService, in KeyEvent keyEvent,
boolean needWakeLock);
boolean dispatchMediaKeyEventToSessionAsSystemService(String packageName,
- in MediaSession.Token sessionToken, in KeyEvent keyEvent);
+ in KeyEvent keyEvent, in MediaSession.Token sessionToken);
void dispatchVolumeKeyEvent(String packageName, String opPackageName, boolean asSystemService,
in KeyEvent keyEvent, int stream, boolean musicOnly);
void dispatchVolumeKeyEventToSessionAsSystemService(String packageName, String opPackageName,
- in MediaSession.Token sessionToken, in KeyEvent keyEvent);
+ in KeyEvent keyEvent, in MediaSession.Token sessionToken);
void dispatchAdjustVolume(String packageName, String opPackageName, int suggestedStream,
int delta, int flags);
void addSessionsListener(in IActiveSessionsListener listener, in ComponentName compName,
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 3acb9516054e..b7b9e4ba6f40 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -493,43 +493,46 @@ public final class MediaSessionManager {
}
/**
- * Send a media key event. The receiver will be selected automatically.
+ * Sends a media key event. The receiver will be selected automatically.
*
- * @param keyEvent The KeyEvent to send.
+ * @param keyEvent the key event to send
* @hide
*/
public void dispatchMediaKeyEvent(@NonNull KeyEvent keyEvent) {
- dispatchMediaKeyEvent(keyEvent, false);
+ dispatchMediaKeyEventInternal(keyEvent, /*asSystemService=*/false, /*needWakeLock=*/false);
}
/**
- * Send a media key event. The receiver will be selected automatically.
+ * Sends a media key event. The receiver will be selected automatically.
*
- * @param keyEvent The KeyEvent to send.
- * @param needWakeLock True if a wake lock should be held while sending the key.
+ * @param keyEvent the key event to send
+ * @param needWakeLock true if a wake lock should be held while sending the key
* @hide
*/
public void dispatchMediaKeyEvent(@NonNull KeyEvent keyEvent, boolean needWakeLock) {
- dispatchMediaKeyEventInternal(false, keyEvent, needWakeLock);
+ dispatchMediaKeyEventInternal(keyEvent, /*asSystemService=*/false, needWakeLock);
}
/**
- * Send a media key event as system component. The receiver will be selected automatically.
+ * Sends a media key event as system service. The receiver will be selected automatically.
* <p>
* Should be only called by the {@link com.android.internal.policy.PhoneWindow} or
* {@link android.view.FallbackEventHandler} when the foreground activity didn't consume the key
* from the hardware devices.
*
- * @param keyEvent The KeyEvent to send.
+ * @param keyEvent the key event to send
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public void dispatchMediaKeyEventAsSystemService(@NonNull KeyEvent keyEvent) {
- dispatchMediaKeyEventInternal(true, keyEvent, false);
+ dispatchMediaKeyEventInternal(keyEvent, /*asSystemService=*/true, /*needWakeLock=*/false);
}
- private void dispatchMediaKeyEventInternal(boolean asSystemService, @NonNull KeyEvent keyEvent,
+ private void dispatchMediaKeyEventInternal(KeyEvent keyEvent, boolean asSystemService,
boolean needWakeLock) {
+ if (keyEvent == null) {
+ throw new NullPointerException("keyEvent shouldn't be null");
+ }
try {
mService.dispatchMediaKeyEvent(mContext.getPackageName(), asSystemService, keyEvent,
needWakeLock);
@@ -539,31 +542,31 @@ public final class MediaSessionManager {
}
/**
- * Dispatches the media button event as system service to the session.
+ * Sends a media key event as system service to the given session.
* <p>
* Should be only called by the {@link com.android.internal.policy.PhoneWindow} when the
* foreground activity didn't consume the key from the hardware devices.
*
- * @param sessionToken session token
- * @param keyEvent media key event
+ * @param keyEvent the key event to send
+ * @param sessionToken the session token to which the key event should be dispatched
* @return {@code true} if the event was sent to the session, {@code false} otherwise
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public boolean dispatchMediaKeyEventAsSystemService(@NonNull MediaSession.Token sessionToken,
- @NonNull KeyEvent keyEvent) {
+ public boolean dispatchMediaKeyEventToSessionAsSystemService(@NonNull KeyEvent keyEvent,
+ @NonNull MediaSession.Token sessionToken) {
if (sessionToken == null) {
- throw new IllegalArgumentException("sessionToken shouldn't be null");
+ throw new NullPointerException("sessionToken shouldn't be null");
}
if (keyEvent == null) {
- throw new IllegalArgumentException("keyEvent shouldn't be null");
+ throw new NullPointerException("keyEvent shouldn't be null");
}
if (!KeyEvent.isMediaSessionKey(keyEvent.getKeyCode())) {
return false;
}
try {
- return mService.dispatchMediaKeyEventToSessionAsSystemService(mContext.getPackageName(),
- sessionToken, keyEvent);
+ return mService.dispatchMediaKeyEventToSessionAsSystemService(
+ mContext.getPackageName(), keyEvent, sessionToken);
} catch (RemoteException e) {
Log.e(TAG, "Failed to send key event.", e);
}
@@ -571,13 +574,16 @@ public final class MediaSessionManager {
}
/**
- * Send a volume key event. The receiver will be selected automatically.
+ * Sends a volume key event. The receiver will be selected automatically.
*
- * @param keyEvent The volume KeyEvent to send.
+ * @param keyEvent the volume key event to send
+ * @param streamType type of stream
+ * @param musicOnly true if key event should only be sent to music stream
* @hide
*/
- public void dispatchVolumeKeyEvent(@NonNull KeyEvent keyEvent, int stream, boolean musicOnly) {
- dispatchVolumeKeyEventInternal(false, keyEvent, stream, musicOnly);
+ public void dispatchVolumeKeyEvent(@NonNull KeyEvent keyEvent, int streamType,
+ boolean musicOnly) {
+ dispatchVolumeKeyEventInternal(keyEvent, streamType, musicOnly, /*asSystemService=*/false);
}
/**
@@ -592,17 +598,21 @@ public final class MediaSessionManager {
* Valid stream types include {@link AudioManager.PublicStreamTypes} and
* {@link AudioManager#USE_DEFAULT_STREAM_TYPE}.
*
- * @param keyEvent volume key event
+ * @param keyEvent the volume key event to send
* @param streamType type of stream
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public void dispatchVolumeKeyEventAsSystemService(@NonNull KeyEvent keyEvent, int streamType) {
- dispatchVolumeKeyEventInternal(true, keyEvent, streamType, false);
+ dispatchVolumeKeyEventInternal(keyEvent, streamType, /*musicOnly=*/false,
+ /*asSystemService=*/true);
}
- private void dispatchVolumeKeyEventInternal(boolean asSystemService, @NonNull KeyEvent keyEvent,
- int stream, boolean musicOnly) {
+ private void dispatchVolumeKeyEventInternal(@NonNull KeyEvent keyEvent, int stream,
+ boolean musicOnly, boolean asSystemService) {
+ if (keyEvent == null) {
+ throw new NullPointerException("keyEvent shouldn't be null");
+ }
try {
mService.dispatchVolumeKeyEvent(mContext.getPackageName(), mContext.getOpPackageName(),
asSystemService, keyEvent, stream, musicOnly);
@@ -617,22 +627,22 @@ public final class MediaSessionManager {
* Should be only called by the {@link com.android.internal.policy.PhoneWindow} when the
* foreground activity didn't consume the key from the hardware devices.
*
- * @param sessionToken sessionToken
- * @param keyEvent volume key event
+ * @param keyEvent the volume key event to send
+ * @param sessionToken the session token to which the key event should be dispatched
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public void dispatchVolumeKeyEventAsSystemService(@NonNull MediaSession.Token sessionToken,
- @NonNull KeyEvent keyEvent) {
+ public void dispatchVolumeKeyEventToSessionAsSystemService(@NonNull KeyEvent keyEvent,
+ @NonNull MediaSession.Token sessionToken) {
if (sessionToken == null) {
- throw new IllegalArgumentException("sessionToken shouldn't be null");
+ throw new NullPointerException("sessionToken shouldn't be null");
}
if (keyEvent == null) {
- throw new IllegalArgumentException("keyEvent shouldn't be null");
+ throw new NullPointerException("keyEvent shouldn't be null");
}
try {
mService.dispatchVolumeKeyEventToSessionAsSystemService(mContext.getPackageName(),
- mContext.getOpPackageName(), sessionToken, keyEvent);
+ mContext.getOpPackageName(), keyEvent, sessionToken);
} catch (RemoteException e) {
Log.wtf(TAG, "Error calling dispatchVolumeKeyEventAsSystemService", e);
}
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index d4278fa74600..a0aa0e09084b 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -4376,6 +4376,7 @@ package android.app {
method @Deprecated public void checkPackage(int, @NonNull String);
method @Deprecated public void finishOp(@NonNull String, int, @NonNull String);
method public void finishOp(@NonNull String, int, @NonNull String, @Nullable String);
+ method public void finishProxyOp(@NonNull String, int, @NonNull String, @Nullable String);
method public boolean isOpActive(@NonNull String, int, @NonNull String);
method @Deprecated public int noteOp(@NonNull String, int, @NonNull String);
method public int noteOp(@NonNull String, int, @Nullable String, @Nullable String, @Nullable String);
@@ -4392,6 +4393,8 @@ package android.app {
method public int startOp(@NonNull String, int, @Nullable String, @Nullable String, @Nullable String);
method @Deprecated public int startOpNoThrow(@NonNull String, int, @NonNull String);
method public int startOpNoThrow(@NonNull String, int, @NonNull String, @NonNull String, @Nullable String);
+ method public int startProxyOp(@NonNull String, int, @NonNull String, @Nullable String, @Nullable String);
+ method public int startProxyOpNoThrow(@NonNull String, int, @NonNull String, @Nullable String, @Nullable String);
method public void startWatchingActive(@NonNull String[], @NonNull java.util.concurrent.Executor, @NonNull android.app.AppOpsManager.OnOpActiveChangedListener);
method public void startWatchingMode(@NonNull String, @Nullable String, @NonNull android.app.AppOpsManager.OnOpChangedListener);
method public void startWatchingMode(@NonNull String, @Nullable String, int, @NonNull android.app.AppOpsManager.OnOpChangedListener);
@@ -6515,6 +6518,7 @@ package android.app {
method public void dropShellPermissionIdentity();
method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
method public android.os.ParcelFileDescriptor executeShellCommand(String);
+ method @NonNull public android.os.ParcelFileDescriptor[] executeShellCommandRw(@NonNull String);
method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
method public android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
@@ -9141,6 +9145,7 @@ package android.bluetooth.le {
method public boolean getIncludeTxPowerLevel();
method public android.util.SparseArray<byte[]> getManufacturerSpecificData();
method public java.util.Map<android.os.ParcelUuid,byte[]> getServiceData();
+ method @Nullable public java.util.List<android.os.ParcelUuid> getServiceSolicitationUuids();
method public java.util.List<android.os.ParcelUuid> getServiceUuids();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.le.AdvertiseData> CREATOR;
@@ -9150,6 +9155,7 @@ package android.bluetooth.le {
ctor public AdvertiseData.Builder();
method public android.bluetooth.le.AdvertiseData.Builder addManufacturerData(int, byte[]);
method public android.bluetooth.le.AdvertiseData.Builder addServiceData(android.os.ParcelUuid, byte[]);
+ method @NonNull public android.bluetooth.le.AdvertiseData.Builder addServiceSolicitationUuid(@NonNull android.os.ParcelUuid);
method public android.bluetooth.le.AdvertiseData.Builder addServiceUuid(android.os.ParcelUuid);
method public android.bluetooth.le.AdvertiseData build();
method public android.bluetooth.le.AdvertiseData.Builder setIncludeDeviceName(boolean);
@@ -10804,6 +10810,7 @@ package android.content {
field public static final String EXTRA_REFERRER = "android.intent.extra.REFERRER";
field public static final String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME";
field public static final String EXTRA_REMOTE_INTENT_TOKEN = "android.intent.extra.remote_intent_token";
+ field public static final String EXTRA_REMOVED_BY_SYSTEM = "android.intent.extra.REMOVED_BY_SYSTEM";
field public static final String EXTRA_REPLACEMENT_EXTRAS = "android.intent.extra.REPLACEMENT_EXTRAS";
field public static final String EXTRA_REPLACING = "android.intent.extra.REPLACING";
field public static final String EXTRA_RESTRICTIONS_BUNDLE = "android.intent.extra.restrictions_bundle";
@@ -49010,6 +49017,7 @@ package android.text.style {
field @NonNull public static final android.os.Parcelable.Creator<android.text.style.SuggestionSpan> CREATOR;
field public static final int FLAG_AUTO_CORRECTION = 4; // 0x4
field public static final int FLAG_EASY_CORRECT = 1; // 0x1
+ field public static final int FLAG_GRAMMAR_ERROR = 8; // 0x8
field public static final int FLAG_MISSPELLED = 2; // 0x2
field public static final int SUGGESTIONS_MAX_SIZE = 5; // 0x5
field @Deprecated public static final String SUGGESTION_SPAN_PICKED_AFTER = "after";
@@ -56377,6 +56385,7 @@ package android.view.textservice {
field @NonNull public static final android.os.Parcelable.Creator<android.view.textservice.SuggestionsInfo> CREATOR;
field public static final int RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = 4; // 0x4
field public static final int RESULT_ATTR_IN_THE_DICTIONARY = 1; // 0x1
+ field public static final int RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR = 8; // 0x8
field public static final int RESULT_ATTR_LOOKS_LIKE_TYPO = 2; // 0x2
}
diff --git a/non-updatable-api/module-lib-current.txt b/non-updatable-api/module-lib-current.txt
index 003a36316c9b..6e3cec6a4f1f 100644
--- a/non-updatable-api/module-lib-current.txt
+++ b/non-updatable-api/module-lib-current.txt
@@ -72,9 +72,9 @@ package android.media.session {
public final class MediaSessionManager {
method public void addOnActiveSessionsChangedListener(@NonNull android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, @Nullable android.content.ComponentName, int, @Nullable android.os.Handler);
method public void dispatchMediaKeyEventAsSystemService(@NonNull android.view.KeyEvent);
- method public boolean dispatchMediaKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
+ method public boolean dispatchMediaKeyEventToSessionAsSystemService(@NonNull android.view.KeyEvent, @NonNull android.media.session.MediaSession.Token);
method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.view.KeyEvent, int);
- method public void dispatchVolumeKeyEventAsSystemService(@NonNull android.media.session.MediaSession.Token, @NonNull android.view.KeyEvent);
+ method public void dispatchVolumeKeyEventToSessionAsSystemService(@NonNull android.view.KeyEvent, @NonNull android.media.session.MediaSession.Token);
field public static final int RESULT_MEDIA_KEY_HANDLED = 1; // 0x1
field public static final int RESULT_MEDIA_KEY_NOT_HANDLED = 0; // 0x0
}
diff --git a/packages/CarSystemUI/res/layout/sysui_overlay_window.xml b/packages/CarSystemUI/res/layout/sysui_overlay_window.xml
index e7295aa6383d..2c9788955bfa 100644
--- a/packages/CarSystemUI/res/layout/sysui_overlay_window.xml
+++ b/packages/CarSystemUI/res/layout/sysui_overlay_window.xml
@@ -25,8 +25,7 @@
<ViewStub android:id="@+id/notification_panel_stub"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout="@layout/notification_panel_container"
- android:layout_marginBottom="@dimen/car_bottom_navigation_bar_height"/>
+ android:layout="@layout/notification_panel_container"/>
<ViewStub android:id="@+id/keyguard_stub"
android:layout_width="match_parent"
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
index b647f13cbe1f..4b660692cd8f 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java
@@ -32,6 +32,7 @@ import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.WindowInsets;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
@@ -82,7 +83,6 @@ public class NotificationPanelViewController extends OverlayPanelViewController
private final StatusBarStateController mStatusBarStateController;
private final boolean mEnableHeadsUpNotificationWhenNotificationShadeOpen;
private final NotificationVisibilityLogger mNotificationVisibilityLogger;
- private final int mNavBarHeight;
private float mInitialBackgroundAlpha;
private float mBackgroundAlphaDiff;
@@ -97,6 +97,7 @@ public class NotificationPanelViewController extends OverlayPanelViewController
private boolean mNotificationListAtEndAtTimeOfTouch;
private boolean mIsSwipingVerticallyToClose;
private boolean mIsNotificationCardSwiping;
+ private boolean mImeVisible = false;
private OnUnseenCountUpdateListener mUnseenCountUpdateListener;
@@ -139,8 +140,6 @@ public class NotificationPanelViewController extends OverlayPanelViewController
mStatusBarStateController = statusBarStateController;
mNotificationVisibilityLogger = notificationVisibilityLogger;
- mNavBarHeight = mResources.getDimensionPixelSize(R.dimen.car_bottom_navigation_bar_height);
-
mCommandQueue.addCallback(this);
// Notification background setup.
@@ -189,19 +188,7 @@ public class NotificationPanelViewController extends OverlayPanelViewController
if (mContext.getDisplayId() != displayId) {
return;
}
- boolean isKeyboardVisible = (vis & InputMethodService.IME_VISIBLE) != 0;
- int bottomMargin = isKeyboardVisible ? 0 : mNavBarHeight;
- ViewGroup container = (ViewGroup) getLayout();
- if (container == null) {
- // Notification panel hasn't been inflated before. We shouldn't try to update the layout
- // params.
- return;
- }
-
- ViewGroup.MarginLayoutParams params =
- (ViewGroup.MarginLayoutParams) container.getLayoutParams();
- params.setMargins(params.leftMargin, params.topMargin, params.rightMargin, bottomMargin);
- container.setLayoutParams(params);
+ mImeVisible = (vis & InputMethodService.IME_VISIBLE) != 0;
}
// OverlayViewController
@@ -229,7 +216,7 @@ public class NotificationPanelViewController extends OverlayPanelViewController
@Override
protected int getInsetTypesToFit() {
- return 0;
+ return WindowInsets.Type.navigationBars();
}
@Override
@@ -237,6 +224,12 @@ public class NotificationPanelViewController extends OverlayPanelViewController
return mEnableHeadsUpNotificationWhenNotificationShadeOpen;
}
+ @Override
+ protected boolean shouldUseStableInsets() {
+ // When IME is visible, then the inset from the nav bar should not be applied.
+ return !mImeVisible;
+ }
+
/** Reinflates the view. */
public void reinflate() {
ViewGroup container = (ViewGroup) getLayout();
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java
index 8adc1adcc41c..6c3a6327d90c 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java
@@ -168,6 +168,19 @@ public class OverlayViewController {
}
/**
+ * Returns {@code true} if the window should use stable insets. Using stable insets means that
+ * even when system bars are temporarily not visible, inset from the system bars will still be
+ * applied.
+ *
+ * NOTE: When system bars are hidden in transient mode, insets from them will not be applied
+ * even when the system bars become visible. Setting the return value to {@true} here can
+ * prevent the OverlayView from overlapping with the system bars when that happens.
+ */
+ protected boolean shouldUseStableInsets() {
+ return false;
+ }
+
+ /**
* Returns the insets types to fit to the sysui overlay window when this
* {@link OverlayViewController} is in the foreground.
*/
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java
index c13e486f1c0e..0da23605a2cf 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java
@@ -108,6 +108,7 @@ public class OverlayViewGlobalStateController {
if (mZOrderVisibleSortedMap.isEmpty()) {
setWindowVisible(true);
}
+
if (!(viewController instanceof OverlayPanelViewController)) {
inflateView(viewController);
}
@@ -117,6 +118,7 @@ public class OverlayViewGlobalStateController {
}
updateInternalsWhenShowingView(viewController);
+ refreshUseStableInsets();
refreshInsetTypesToFit();
refreshWindowFocus();
refreshNavigationBarVisibility();
@@ -190,6 +192,7 @@ public class OverlayViewGlobalStateController {
mZOrderVisibleSortedMap.remove(mZOrderMap.get(viewController));
refreshHighestZOrderWhenHidingView(viewController);
+ refreshUseStableInsets();
refreshInsetTypesToFit();
refreshWindowFocus();
refreshNavigationBarVisibility();
@@ -247,6 +250,11 @@ public class OverlayViewGlobalStateController {
setWindowFocusable(mHighestZOrder == null ? false : mHighestZOrder.shouldFocusWindow());
}
+ private void refreshUseStableInsets() {
+ mSystemUIOverlayWindowController.setUsingStableInsets(
+ mHighestZOrder == null ? false : mHighestZOrder.shouldUseStableInsets());
+ }
+
private void refreshInsetTypesToFit() {
if (mZOrderVisibleSortedMap.isEmpty()) {
setFitInsetsTypes(statusBars());
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/SystemUIOverlayWindowController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/SystemUIOverlayWindowController.java
index 887329359b05..b22de84eb038 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/SystemUIOverlayWindowController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/SystemUIOverlayWindowController.java
@@ -53,6 +53,7 @@ public class SystemUIOverlayWindowController implements
private boolean mIsAttached = false;
private boolean mVisible = false;
private boolean mFocusable = false;
+ private boolean mUsingStableInsets = false;
@Inject
public SystemUIOverlayWindowController(
@@ -115,6 +116,7 @@ public class SystemUIOverlayWindowController implements
/** Sets the types of insets to fit. Note: This should be rarely used. */
public void setFitInsetsTypes(@WindowInsets.Type.InsetsType int types) {
mLpChanged.setFitInsetsTypes(types);
+ mLpChanged.setFitInsetsIgnoringVisibility(mUsingStableInsets);
updateWindow();
}
@@ -159,6 +161,10 @@ public class SystemUIOverlayWindowController implements
return mFocusable;
}
+ protected void setUsingStableInsets(boolean useStableInsets) {
+ mUsingStableInsets = useStableInsets;
+ }
+
private void updateWindow() {
if (mLp != null && mLp.copyFrom(mLpChanged) != 0) {
if (isAttached()) {
diff --git a/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml b/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml
new file mode 100644
index 000000000000..f66ff007fb90
--- /dev/null
+++ b/packages/SettingsLib/res/layout/edit_user_info_dialog_content.xml
@@ -0,0 +1,51 @@
+<!--
+ Copyright (C) 2013 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:baselineAligned="false"
+ android:orientation="horizontal"
+ android:padding="16dp">
+
+ <ImageView
+ android:id="@+id/user_photo"
+ android:layout_width="56dp"
+ android:layout_height="56dp"
+ android:layout_gravity="bottom"
+ android:contentDescription="@string/user_image_photo_selector"
+ android:background="@*android:drawable/spinner_background_holo_dark"
+ android:scaleType="fitCenter"/>
+
+ <EditText
+ android:id="@+id/user_name"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:layout_weight="1"
+ android:minWidth="200dp"
+ android:layout_marginStart="6dp"
+ android:minHeight="@dimen/min_tap_target_size"
+ android:ellipsize="end"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textAlignment="viewStart"
+ android:inputType="text|textCapWords"
+ android:selectAllOnFocus="true"
+ android:hint="@string/user_nickname"
+ android:maxLength="100"/>
+
+</LinearLayout>
diff --git a/packages/SettingsLib/res/layout/restricted_popup_menu_item.xml b/packages/SettingsLib/res/layout/restricted_popup_menu_item.xml
new file mode 100644
index 000000000000..923d022aea68
--- /dev/null
+++ b/packages/SettingsLib/res/layout/restricted_popup_menu_item.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp">
+
+ <TextView
+ android:id="@+id/text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceListItemSmall"
+ android:textColor="?android:attr/textColorAlertDialogListItem" />
+
+ <ImageView
+ android:id="@+id/restricted_icon"
+ android:layout_width="@*android:dimen/config_restrictedIconSize"
+ android:layout_height="@*android:dimen/config_restrictedIconSize"
+ android:layout_alignParentRight="true"
+ android:scaleType="centerInside"
+ android:src="@*android:drawable/ic_info"
+ android:tint="?android:attr/colorAccent"
+ android:visibility="gone" />
+
+</RelativeLayout>
diff --git a/packages/SettingsLib/res/layout/user_creation_progress_dialog.xml b/packages/SettingsLib/res/layout/user_creation_progress_dialog.xml
new file mode 100644
index 000000000000..fe09aaca0b1f
--- /dev/null
+++ b/packages/SettingsLib/res/layout/user_creation_progress_dialog.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/message"
+ style="?android:attr/textAppearanceListItem"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:paddingStart="?android:attr/dialogPreferredPadding"
+ android:paddingEnd="?android:attr/dialogPreferredPadding"
+ android:paddingTop="24dp"
+ android:paddingBottom="24dp" />
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index e552d78e1a45..ef4b97f7743f 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -97,4 +97,8 @@
<!-- Size of advanced icon -->
<dimen name="advanced_icon_size">18dp</dimen>
+
+ <!-- Minimum width for the popup for updating a user's photo. -->
+ <dimen name="update_user_photo_popup_min_width">300dp</dimen>
+
</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 03161d051342..6a4c8c301cbe 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1354,6 +1354,11 @@
<string name="user_set_lock_button">Set lock</string>
<!-- Label for switching to other user in the user switcher [CHAR LIMIT=35] -->
<string name="user_switch_to_user">Switch to <xliff:g id="user_name" example="John Doe">%s</xliff:g></string>
+ <!-- Dialog message when creating a new user [CHAR LIMIT=40] -->
+ <string name="creating_new_user_dialog_message">Creating new user…</string>
+
+ <!-- Title for the preference to enter the nickname of the user to display in the user switcher [CHAR LIMIT=25]-->
+ <string name="user_nickname">Nickname</string>
<!-- Label for adding a new guest in the user switcher [CHAR LIMIT=35] -->
<string name="guest_new_guest">Add guest</string>
@@ -1362,6 +1367,13 @@
<!-- Name for the guest user [CHAR LIMIT=35] -->
<string name="guest_nickname">Guest</string>
+ <!-- An option in a photo selection dialog to take a new photo [CHAR LIMIT=50] -->
+ <string name="user_image_take_photo">Take a photo</string>
+ <!-- An option in a photo selection dialog to choose a pre-existing image [CHAR LIMIT=50] -->
+ <string name="user_image_choose_photo">Choose an image</string>
+ <!-- Accessibility message for the photo selector which is a button/popup with the current photo [CHAR LIMIT=50] -->
+ <string name="user_image_photo_selector">Select photo</string>
+
<!-- List entry in developer settings to choose default device/system behavior for the app freezer [CHAR LIMIT=30]-->
<string name="cached_apps_freezer_device_default">Device default</string>
<!-- List entry in developer settings to disable the app freezer in developer settings [CHAR LIMIT=30]-->
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java
index 28e993da7dc4..fc16eb6b4277 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaOutputSliceConstants.java
@@ -92,4 +92,10 @@ public class MediaOutputSliceConstants {
* SystemUi package name.
*/
public static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui";
+
+ /**
+ * An intent action to close settings panel.
+ */
+ public static final String ACTION_CLOSE_PANEL =
+ "com.android.settings.panel.action.CLOSE_PANEL";
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/ActivityStarter.java b/packages/SettingsLib/src/com/android/settingslib/users/ActivityStarter.java
new file mode 100644
index 000000000000..081b5075ebbe
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/users/ActivityStarter.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.users;
+
+import android.content.Intent;
+
+/**
+ * An interface to start activities for result. This is used as a callback from controllers where
+ * activity starting isn't possible but we want to keep the intent building logic there.
+ */
+public interface ActivityStarter {
+
+ /**
+ * Launch an activity for which you would like a result when it finished.
+ */
+ void startActivityForResult(Intent intent, int requestCode);
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/EditUserInfoController.java b/packages/SettingsLib/src/com/android/settingslib/users/EditUserInfoController.java
new file mode 100644
index 000000000000..58599532d9cb
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/users/EditUserInfoController.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.users;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.ImageView;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.internal.util.UserIcons;
+import com.android.settingslib.R;
+import com.android.settingslib.drawable.CircleFramedDrawable;
+
+import java.io.File;
+import java.util.function.BiConsumer;
+
+/**
+ * This class encapsulates a Dialog for editing the user nickname and photo.
+ */
+public class EditUserInfoController {
+
+ private static final String KEY_AWAITING_RESULT = "awaiting_result";
+ private static final String KEY_SAVED_PHOTO = "pending_photo";
+
+ private Dialog mEditUserInfoDialog;
+ private Bitmap mSavedPhoto;
+ private EditUserPhotoController mEditUserPhotoController;
+ private boolean mWaitingForActivityResult = false;
+ private final String mFileAuthority;
+
+ public EditUserInfoController(String fileAuthority) {
+ mFileAuthority = fileAuthority;
+ }
+
+ private void clear() {
+ if (mEditUserPhotoController != null) {
+ mEditUserPhotoController.removeNewUserPhotoBitmapFile();
+ }
+ mEditUserInfoDialog = null;
+ mSavedPhoto = null;
+ }
+
+ /**
+ * This should be called when the container activity/fragment got re-initialized from a
+ * previously saved state.
+ */
+ public void onRestoreInstanceState(Bundle icicle) {
+ String pendingPhoto = icicle.getString(KEY_SAVED_PHOTO);
+ if (pendingPhoto != null) {
+ mSavedPhoto = EditUserPhotoController.loadNewUserPhotoBitmap(new File(pendingPhoto));
+ }
+ mWaitingForActivityResult = icicle.getBoolean(KEY_AWAITING_RESULT, false);
+ }
+
+ /**
+ * Should be called from the container activity/fragment when it's onSaveInstanceState is
+ * called.
+ */
+ public void onSaveInstanceState(Bundle outState) {
+ if (mEditUserInfoDialog != null && mEditUserPhotoController != null) {
+ // Bitmap cannot be stored into bundle because it may exceed parcel limit
+ // Store it in a temporary file instead
+ File file = mEditUserPhotoController.saveNewUserPhotoBitmap();
+ if (file != null) {
+ outState.putString(KEY_SAVED_PHOTO, file.getPath());
+ }
+ }
+ outState.putBoolean(KEY_AWAITING_RESULT, mWaitingForActivityResult);
+ }
+
+ /**
+ * Should be called from the container activity/fragment when an activity has started for
+ * take/choose/crop photo actions.
+ */
+ public void startingActivityForResult() {
+ mWaitingForActivityResult = true;
+ }
+
+ /**
+ * Should be called from the container activity/fragment after it receives a result from
+ * take/choose/crop photo activity.
+ */
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ mWaitingForActivityResult = false;
+
+ if (mEditUserPhotoController != null && mEditUserInfoDialog != null) {
+ mEditUserPhotoController.onActivityResult(requestCode, resultCode, data);
+ }
+ }
+
+ /**
+ * Creates a user edit dialog with option to change the user's name and photo.
+ *
+ * @param activityStarter - ActivityStarter is called with appropriate intents and request
+ * codes to take photo/choose photo/crop photo.
+ */
+ public Dialog createDialog(Activity activity, ActivityStarter activityStarter,
+ @Nullable Drawable oldUserIcon, String defaultUserName, String title,
+ BiConsumer<String, Drawable> successCallback, Runnable cancelCallback) {
+ LayoutInflater inflater = LayoutInflater.from(activity);
+ View content = inflater.inflate(R.layout.edit_user_info_dialog_content, null);
+
+ EditText userNameView = content.findViewById(R.id.user_name);
+ userNameView.setText(defaultUserName);
+
+ ImageView userPhotoView = content.findViewById(R.id.user_photo);
+
+ // if oldUserIcon param is null then we use a default gray user icon
+ Drawable defaultUserIcon = oldUserIcon != null ? oldUserIcon : UserIcons.getDefaultUserIcon(
+ activity.getResources(), UserHandle.USER_NULL, false);
+ // in case a new photo was selected and the activity got recreated we have to load the image
+ Drawable userIcon = getUserIcon(activity, defaultUserIcon);
+ userPhotoView.setImageDrawable(userIcon);
+
+ if (canChangePhoto(activity)) {
+ mEditUserPhotoController = createEditUserPhotoController(activity, activityStarter,
+ userPhotoView);
+ } else {
+ // some users can't change their photos so we need to remove suggestive
+ // background from the photoView
+ userPhotoView.setBackground(null);
+ }
+
+ mEditUserInfoDialog = buildDialog(activity, content, userNameView, oldUserIcon,
+ defaultUserName, title, successCallback, cancelCallback);
+
+ // Make sure the IME is up.
+ mEditUserInfoDialog.getWindow()
+ .setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+
+ return mEditUserInfoDialog;
+ }
+
+ private Drawable getUserIcon(Activity activity, Drawable defaultUserIcon) {
+ if (mSavedPhoto != null) {
+ return CircleFramedDrawable.getInstance(activity, mSavedPhoto);
+ }
+ return defaultUserIcon;
+ }
+
+ private Dialog buildDialog(Activity activity, View content, EditText userNameView,
+ @Nullable Drawable oldUserIcon, String defaultUserName, String title,
+ BiConsumer<String, Drawable> successCallback, Runnable cancelCallback) {
+ return new AlertDialog.Builder(activity)
+ .setTitle(title)
+ .setView(content)
+ .setCancelable(true)
+ .setPositiveButton(android.R.string.ok, (dialog, which) -> {
+ Drawable newUserIcon = mEditUserPhotoController != null
+ ? mEditUserPhotoController.getNewUserPhotoDrawable()
+ : null;
+ Drawable userIcon = newUserIcon != null
+ ? newUserIcon
+ : oldUserIcon;
+
+ String newName = userNameView.getText().toString().trim();
+ String userName = !newName.isEmpty() ? newName : defaultUserName;
+
+ clear();
+ if (successCallback != null) {
+ successCallback.accept(userName, userIcon);
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, (dialog, which) -> {
+ clear();
+ if (cancelCallback != null) {
+ cancelCallback.run();
+ }
+ })
+ .setOnCancelListener(dialog -> {
+ clear();
+ if (cancelCallback != null) {
+ cancelCallback.run();
+ }
+ })
+ .create();
+ }
+
+ @VisibleForTesting
+ boolean canChangePhoto(Context context) {
+ return (PhotoCapabilityUtils.canCropPhoto(context)
+ && PhotoCapabilityUtils.canChoosePhoto(context))
+ || PhotoCapabilityUtils.canTakePhoto(context);
+ }
+
+ @VisibleForTesting
+ EditUserPhotoController createEditUserPhotoController(Activity activity,
+ ActivityStarter activityStarter, ImageView userPhotoView) {
+ return new EditUserPhotoController(activity, activityStarter, userPhotoView,
+ mSavedPhoto, mWaitingForActivityResult, mFileAuthority);
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java b/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java
new file mode 100644
index 000000000000..ecd40667843e
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java
@@ -0,0 +1,509 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.users;
+
+import android.app.Activity;
+import android.content.ClipData;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+import android.media.ExifInterface;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.StrictMode;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.ContactsContract.DisplayPhoto;
+import android.provider.MediaStore;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.ListPopupWindow;
+import android.widget.TextView;
+
+import androidx.core.content.FileProvider;
+
+import com.android.settingslib.R;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedLockUtilsInternal;
+import com.android.settingslib.drawable.CircleFramedDrawable;
+
+import libcore.io.Streams;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class contains logic for starting activities to take/choose/crop photo, reads and transforms
+ * the result image.
+ */
+public class EditUserPhotoController {
+ private static final String TAG = "EditUserPhotoController";
+
+ // It seems that this class generates custom request codes and they may
+ // collide with ours, these values are very unlikely to have a conflict.
+ private static final int REQUEST_CODE_CHOOSE_PHOTO = 1001;
+ private static final int REQUEST_CODE_TAKE_PHOTO = 1002;
+ private static final int REQUEST_CODE_CROP_PHOTO = 1003;
+ // in rare cases we get a null Cursor when querying for DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI
+ // so we need a default photo size
+ private static final int DEFAULT_PHOTO_SIZE = 500;
+
+ private static final String IMAGES_DIR = "multi_user";
+ private static final String CROP_PICTURE_FILE_NAME = "CropEditUserPhoto.jpg";
+ private static final String TAKE_PICTURE_FILE_NAME = "TakeEditUserPhoto.jpg";
+ private static final String NEW_USER_PHOTO_FILE_NAME = "NewUserPhoto.png";
+
+ private final int mPhotoSize;
+
+ private final Activity mActivity;
+ private final ActivityStarter mActivityStarter;
+ private final ImageView mImageView;
+ private final String mFileAuthority;
+
+ private final File mImagesDir;
+ private final Uri mCropPictureUri;
+ private final Uri mTakePictureUri;
+
+ private Bitmap mNewUserPhotoBitmap;
+ private Drawable mNewUserPhotoDrawable;
+
+ public EditUserPhotoController(Activity activity, ActivityStarter activityStarter,
+ ImageView view, Bitmap bitmap, boolean waiting, String fileAuthority) {
+ mActivity = activity;
+ mActivityStarter = activityStarter;
+ mImageView = view;
+ mFileAuthority = fileAuthority;
+
+ mImagesDir = new File(activity.getCacheDir(), IMAGES_DIR);
+ mImagesDir.mkdir();
+ mCropPictureUri = createTempImageUri(activity, CROP_PICTURE_FILE_NAME, !waiting);
+ mTakePictureUri = createTempImageUri(activity, TAKE_PICTURE_FILE_NAME, !waiting);
+ mPhotoSize = getPhotoSize(activity);
+ mImageView.setOnClickListener(v -> showUpdatePhotoPopup());
+ mNewUserPhotoBitmap = bitmap;
+ }
+
+ /**
+ * Handles activity result from containing activity/fragment after a take/choose/crop photo
+ * action result is received.
+ */
+ public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (resultCode != Activity.RESULT_OK) {
+ return false;
+ }
+ final Uri pictureUri = data != null && data.getData() != null
+ ? data.getData() : mTakePictureUri;
+ switch (requestCode) {
+ case REQUEST_CODE_CROP_PHOTO:
+ onPhotoCropped(pictureUri);
+ return true;
+ case REQUEST_CODE_TAKE_PHOTO:
+ case REQUEST_CODE_CHOOSE_PHOTO:
+ if (mTakePictureUri.equals(pictureUri)) {
+ if (PhotoCapabilityUtils.canCropPhoto(mActivity)) {
+ cropPhoto();
+ } else {
+ onPhotoNotCropped(pictureUri);
+ }
+ } else {
+ copyAndCropPhoto(pictureUri);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public Drawable getNewUserPhotoDrawable() {
+ return mNewUserPhotoDrawable;
+ }
+
+ private void showUpdatePhotoPopup() {
+ final Context context = mImageView.getContext();
+ final boolean canTakePhoto = PhotoCapabilityUtils.canTakePhoto(context);
+ final boolean canChoosePhoto = PhotoCapabilityUtils.canChoosePhoto(context);
+
+ if (!canTakePhoto && !canChoosePhoto) {
+ return;
+ }
+
+ final List<EditUserPhotoController.RestrictedMenuItem> items = new ArrayList<>();
+
+ if (canTakePhoto) {
+ final String title = context.getString(R.string.user_image_take_photo);
+ items.add(new RestrictedMenuItem(context, title, UserManager.DISALLOW_SET_USER_ICON,
+ this::takePhoto));
+ }
+
+ if (canChoosePhoto) {
+ final String title = context.getString(R.string.user_image_choose_photo);
+ items.add(new RestrictedMenuItem(context, title, UserManager.DISALLOW_SET_USER_ICON,
+ this::choosePhoto));
+ }
+
+ final ListPopupWindow listPopupWindow = new ListPopupWindow(context);
+
+ listPopupWindow.setAnchorView(mImageView);
+ listPopupWindow.setModal(true);
+ listPopupWindow.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NOT_NEEDED);
+ listPopupWindow.setAdapter(new RestrictedPopupMenuAdapter(context, items));
+
+ final int width = Math.max(mImageView.getWidth(), context.getResources()
+ .getDimensionPixelSize(R.dimen.update_user_photo_popup_min_width));
+ listPopupWindow.setWidth(width);
+ listPopupWindow.setDropDownGravity(Gravity.START);
+
+ listPopupWindow.setOnItemClickListener((parent, view, position, id) -> {
+ listPopupWindow.dismiss();
+ final RestrictedMenuItem item =
+ (RestrictedMenuItem) parent.getAdapter().getItem(position);
+ item.doAction();
+ });
+
+ listPopupWindow.show();
+ }
+
+ private void takePhoto() {
+ Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE_SECURE);
+ appendOutputExtra(intent, mTakePictureUri);
+ mActivityStarter.startActivityForResult(intent, REQUEST_CODE_TAKE_PHOTO);
+ }
+
+ private void choosePhoto() {
+ Intent intent = new Intent(Intent.ACTION_GET_CONTENT, null);
+ intent.setType("image/*");
+ appendOutputExtra(intent, mTakePictureUri);
+ mActivityStarter.startActivityForResult(intent, REQUEST_CODE_CHOOSE_PHOTO);
+ }
+
+ private void copyAndCropPhoto(final Uri pictureUri) {
+ // TODO: Replace AsyncTask
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ final ContentResolver cr = mActivity.getContentResolver();
+ try (InputStream in = cr.openInputStream(pictureUri);
+ OutputStream out = cr.openOutputStream(mTakePictureUri)) {
+ Streams.copy(in, out);
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to copy photo", e);
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ if (!mActivity.isFinishing() && !mActivity.isDestroyed()) {
+ cropPhoto();
+ }
+ }
+ }.execute();
+ }
+
+ private void cropPhoto() {
+ // TODO: Use a public intent, when there is one.
+ Intent intent = new Intent("com.android.camera.action.CROP");
+ intent.setDataAndType(mTakePictureUri, "image/*");
+ appendOutputExtra(intent, mCropPictureUri);
+ appendCropExtras(intent);
+ if (intent.resolveActivity(mActivity.getPackageManager()) != null) {
+ try {
+ StrictMode.disableDeathOnFileUriExposure();
+ mActivityStarter.startActivityForResult(intent, REQUEST_CODE_CROP_PHOTO);
+ } finally {
+ StrictMode.enableDeathOnFileUriExposure();
+ }
+ } else {
+ onPhotoNotCropped(mTakePictureUri);
+ }
+ }
+
+ private void appendOutputExtra(Intent intent, Uri pictureUri) {
+ intent.putExtra(MediaStore.EXTRA_OUTPUT, pictureUri);
+ intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ | Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ intent.setClipData(ClipData.newRawUri(MediaStore.EXTRA_OUTPUT, pictureUri));
+ }
+
+ private void appendCropExtras(Intent intent) {
+ intent.putExtra("crop", "true");
+ intent.putExtra("scale", true);
+ intent.putExtra("scaleUpIfNeeded", true);
+ intent.putExtra("aspectX", 1);
+ intent.putExtra("aspectY", 1);
+ intent.putExtra("outputX", mPhotoSize);
+ intent.putExtra("outputY", mPhotoSize);
+ }
+
+ private void onPhotoCropped(final Uri data) {
+ // TODO: Replace AsyncTask to avoid possible memory leaks and handle configuration change
+ new AsyncTask<Void, Void, Bitmap>() {
+ @Override
+ protected Bitmap doInBackground(Void... params) {
+ InputStream imageStream = null;
+ try {
+ imageStream = mActivity.getContentResolver()
+ .openInputStream(data);
+ return BitmapFactory.decodeStream(imageStream);
+ } catch (FileNotFoundException fe) {
+ Log.w(TAG, "Cannot find image file", fe);
+ return null;
+ } finally {
+ if (imageStream != null) {
+ try {
+ imageStream.close();
+ } catch (IOException ioe) {
+ Log.w(TAG, "Cannot close image stream", ioe);
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap bitmap) {
+ onPhotoProcessed(bitmap);
+
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+ }
+
+ private void onPhotoNotCropped(final Uri data) {
+ // TODO: Replace AsyncTask to avoid possible memory leaks and handle configuration change
+ new AsyncTask<Void, Void, Bitmap>() {
+ @Override
+ protected Bitmap doInBackground(Void... params) {
+ // Scale and crop to a square aspect ratio
+ Bitmap croppedImage = Bitmap.createBitmap(mPhotoSize, mPhotoSize,
+ Config.ARGB_8888);
+ Canvas canvas = new Canvas(croppedImage);
+ Bitmap fullImage;
+ try {
+ InputStream imageStream = mActivity.getContentResolver()
+ .openInputStream(data);
+ fullImage = BitmapFactory.decodeStream(imageStream);
+ } catch (FileNotFoundException fe) {
+ return null;
+ }
+ if (fullImage != null) {
+ int rotation = getRotation(mActivity, data);
+ final int squareSize = Math.min(fullImage.getWidth(),
+ fullImage.getHeight());
+ final int left = (fullImage.getWidth() - squareSize) / 2;
+ final int top = (fullImage.getHeight() - squareSize) / 2;
+
+ Matrix matrix = new Matrix();
+ RectF rectSource = new RectF(left, top,
+ left + squareSize, top + squareSize);
+ RectF rectDest = new RectF(0, 0, mPhotoSize, mPhotoSize);
+ matrix.setRectToRect(rectSource, rectDest, Matrix.ScaleToFit.CENTER);
+ matrix.postRotate(rotation, mPhotoSize / 2f, mPhotoSize / 2f);
+ canvas.drawBitmap(fullImage, matrix, new Paint());
+ return croppedImage;
+ } else {
+ // Bah! Got nothin.
+ return null;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Bitmap bitmap) {
+ onPhotoProcessed(bitmap);
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+ }
+
+ /**
+ * Reads the image's exif data and determines the rotation degree needed to display the image
+ * in portrait mode.
+ */
+ private int getRotation(Context context, Uri selectedImage) {
+ int rotation = -1;
+ try {
+ InputStream imageStream = context.getContentResolver().openInputStream(selectedImage);
+ ExifInterface exif = new ExifInterface(imageStream);
+ rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);
+ } catch (IOException exception) {
+ Log.e(TAG, "Error while getting rotation", exception);
+ }
+
+ switch (rotation) {
+ case ExifInterface.ORIENTATION_ROTATE_90:
+ return 90;
+ case ExifInterface.ORIENTATION_ROTATE_180:
+ return 180;
+ case ExifInterface.ORIENTATION_ROTATE_270:
+ return 270;
+ default:
+ return 0;
+ }
+ }
+
+ private void onPhotoProcessed(Bitmap bitmap) {
+ if (bitmap != null) {
+ mNewUserPhotoBitmap = bitmap;
+ mNewUserPhotoDrawable = CircleFramedDrawable
+ .getInstance(mImageView.getContext(), mNewUserPhotoBitmap);
+ mImageView.setImageDrawable(mNewUserPhotoDrawable);
+ }
+ new File(mImagesDir, TAKE_PICTURE_FILE_NAME).delete();
+ new File(mImagesDir, CROP_PICTURE_FILE_NAME).delete();
+ }
+
+ private static int getPhotoSize(Context context) {
+ try (Cursor cursor = context.getContentResolver().query(
+ DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI,
+ new String[]{DisplayPhoto.DISPLAY_MAX_DIM}, null, null, null)) {
+ if (cursor != null) {
+ cursor.moveToFirst();
+ return cursor.getInt(0);
+ } else {
+ return DEFAULT_PHOTO_SIZE;
+ }
+ }
+ }
+
+ private Uri createTempImageUri(Context context, String fileName, boolean purge) {
+ final File fullPath = new File(mImagesDir, fileName);
+ if (purge) {
+ fullPath.delete();
+ }
+ return FileProvider.getUriForFile(context, mFileAuthority, fullPath);
+ }
+
+ File saveNewUserPhotoBitmap() {
+ if (mNewUserPhotoBitmap == null) {
+ return null;
+ }
+ try {
+ File file = new File(mImagesDir, NEW_USER_PHOTO_FILE_NAME);
+ OutputStream os = new FileOutputStream(file);
+ mNewUserPhotoBitmap.compress(Bitmap.CompressFormat.PNG, 100, os);
+ os.flush();
+ os.close();
+ return file;
+ } catch (IOException e) {
+ Log.e(TAG, "Cannot create temp file", e);
+ }
+ return null;
+ }
+
+ static Bitmap loadNewUserPhotoBitmap(File file) {
+ return BitmapFactory.decodeFile(file.getAbsolutePath());
+ }
+
+ void removeNewUserPhotoBitmapFile() {
+ new File(mImagesDir, NEW_USER_PHOTO_FILE_NAME).delete();
+ }
+
+ private static final class RestrictedMenuItem {
+ private final Context mContext;
+ private final String mTitle;
+ private final Runnable mAction;
+ private final RestrictedLockUtils.EnforcedAdmin mAdmin;
+ // Restriction may be set by system or something else via UserManager.setUserRestriction().
+ private final boolean mIsRestrictedByBase;
+
+ /**
+ * The menu item, used for popup menu. Any element of such a menu can be disabled by admin.
+ *
+ * @param context A context.
+ * @param title The title of the menu item.
+ * @param restriction The restriction, that if is set, blocks the menu item.
+ * @param action The action on menu item click.
+ */
+ RestrictedMenuItem(Context context, String title, String restriction,
+ Runnable action) {
+ mContext = context;
+ mTitle = title;
+ mAction = action;
+
+ final int myUserId = UserHandle.myUserId();
+ mAdmin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced(context,
+ restriction, myUserId);
+ mIsRestrictedByBase = RestrictedLockUtilsInternal.hasBaseUserRestriction(mContext,
+ restriction, myUserId);
+ }
+
+ @Override
+ public String toString() {
+ return mTitle;
+ }
+
+ void doAction() {
+ if (isRestrictedByBase()) {
+ return;
+ }
+
+ if (isRestrictedByAdmin()) {
+ RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, mAdmin);
+ return;
+ }
+
+ mAction.run();
+ }
+
+ boolean isRestrictedByAdmin() {
+ return mAdmin != null;
+ }
+
+ boolean isRestrictedByBase() {
+ return mIsRestrictedByBase;
+ }
+ }
+
+ /**
+ * Provide this adapter to ListPopupWindow.setAdapter() to have a popup window menu, where
+ * any element can be restricted by admin (profile owner or device owner).
+ */
+ private static final class RestrictedPopupMenuAdapter extends ArrayAdapter<RestrictedMenuItem> {
+ RestrictedPopupMenuAdapter(Context context, List<RestrictedMenuItem> items) {
+ super(context, R.layout.restricted_popup_menu_item, R.id.text, items);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ final View view = super.getView(position, convertView, parent);
+ final RestrictedMenuItem item = getItem(position);
+ final TextView text = (TextView) view.findViewById(R.id.text);
+ final ImageView image = (ImageView) view.findViewById(R.id.restricted_icon);
+
+ text.setEnabled(!item.isRestrictedByAdmin() && !item.isRestrictedByBase());
+ image.setVisibility(item.isRestrictedByAdmin() && !item.isRestrictedByBase()
+ ? ImageView.VISIBLE : ImageView.GONE);
+
+ return view;
+ }
+ }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/PhotoCapabilityUtils.java b/packages/SettingsLib/src/com/android/settingslib/users/PhotoCapabilityUtils.java
new file mode 100644
index 000000000000..165c2808f16d
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/users/PhotoCapabilityUtils.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.users;
+
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.provider.MediaStore;
+
+/**
+ * Utility class that contains helper methods to determine if the current user has permission and
+ * the device is in a proper state to start an activity for a given action.
+ */
+public class PhotoCapabilityUtils {
+
+ /**
+ * Check if the current user can perform any activity for
+ * android.media.action.IMAGE_CAPTURE action.
+ */
+ public static boolean canTakePhoto(Context context) {
+ return context.getPackageManager().queryIntentActivities(
+ new Intent(MediaStore.ACTION_IMAGE_CAPTURE),
+ PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
+ }
+
+ /**
+ * Check if the current user can perform any activity for
+ * android.intent.action.GET_CONTENT action for images.
+ * Returns false if the device is currently locked and
+ * requires a PIN, pattern or password to unlock.
+ */
+ public static boolean canChoosePhoto(Context context) {
+ Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
+ intent.setType("image/*");
+ boolean canPerformActivityForGetImage =
+ context.getPackageManager().queryIntentActivities(intent, 0).size() > 0;
+ // on locked device we can't access the images
+ return canPerformActivityForGetImage && !isDeviceLocked(context);
+ }
+
+ /**
+ * Check if the current user can perform any activity for
+ * com.android.camera.action.CROP action for images.
+ * Returns false if the device is currently locked and
+ * requires a PIN, pattern or password to unlock.
+ */
+ public static boolean canCropPhoto(Context context) {
+ Intent intent = new Intent("com.android.camera.action.CROP");
+ intent.setType("image/*");
+ boolean canPerformActivityForCropping =
+ context.getPackageManager().queryIntentActivities(intent, 0).size() > 0;
+ // on locked device we can't start a cropping activity
+ return canPerformActivityForCropping && !isDeviceLocked(context);
+ }
+
+ private static boolean isDeviceLocked(Context context) {
+ KeyguardManager keyguardManager = context.getSystemService(KeyguardManager.class);
+ return keyguardManager == null || keyguardManager.isDeviceLocked();
+ }
+
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/UserCreatingDialog.java b/packages/SettingsLib/src/com/android/settingslib/users/UserCreatingDialog.java
new file mode 100644
index 000000000000..075635c87b1b
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/users/UserCreatingDialog.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.users;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+import com.android.settingslib.R;
+
+/**
+ * Dialog to show when a user creation is in progress.
+ */
+public class UserCreatingDialog extends AlertDialog {
+
+ public UserCreatingDialog(Context context) {
+ // hardcoding theme to be consistent with UserSwitchingDialog's theme
+ // todo replace both to adapt to the device's theme
+ super(context, com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog_Alert);
+
+ inflateContent();
+ getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
+
+ WindowManager.LayoutParams attrs = getWindow().getAttributes();
+ attrs.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR
+ | WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
+ getWindow().setAttributes(attrs);
+ }
+
+ private void inflateContent() {
+ // using the same design as UserSwitchingDialog
+ setCancelable(false);
+ View view = LayoutInflater.from(getContext())
+ .inflate(R.layout.user_creation_progress_dialog, null);
+ String message = getContext().getString(R.string.creating_new_user_dialog_message);
+ view.setAccessibilityPaneTitle(message);
+ ((TextView) view.findViewById(R.id.message)).setText(message);
+ setView(view);
+ }
+
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java
new file mode 100644
index 000000000000..d6c8816ecc58
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.users;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.widget.EditText;
+import android.widget.ImageView;
+
+import androidx.fragment.app.FragmentActivity;
+
+import com.android.settingslib.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.android.controller.ActivityController;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowDialog;
+
+import java.util.function.BiConsumer;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@RunWith(RobolectricTestRunner.class)
+public class EditUserInfoControllerTest {
+ private static final int MAX_USER_NAME_LENGTH = 100;
+
+ @Mock
+ private Drawable mCurrentIcon;
+ @Mock
+ private ActivityStarter mActivityStarter;
+
+ private boolean mCanChangePhoto;
+ private Activity mActivity;
+ private TestEditUserInfoController mController;
+
+ public class TestEditUserInfoController extends EditUserInfoController {
+ private EditUserPhotoController mPhotoController;
+
+ TestEditUserInfoController() {
+ super("file_authority");
+ }
+
+ private EditUserPhotoController getPhotoController() {
+ return mPhotoController;
+ }
+
+ @Override
+ EditUserPhotoController createEditUserPhotoController(Activity activity,
+ ActivityStarter activityStarter, ImageView userPhotoView) {
+ mPhotoController = mock(EditUserPhotoController.class, Answers.RETURNS_DEEP_STUBS);
+ return mPhotoController;
+ }
+
+ @Override
+ boolean canChangePhoto(Context context) {
+ return mCanChangePhoto;
+ }
+ }
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mActivity = spy(ActivityController.of(new FragmentActivity()).get());
+ mActivity.setTheme(R.style.Theme_AppCompat_DayNight);
+ mController = new TestEditUserInfoController();
+ mCanChangePhoto = true;
+ }
+
+ @Test
+ public void photoControllerOnActivityResult_whenWaiting_isCalled() {
+ mController.createDialog(mActivity, mActivityStarter, mCurrentIcon, "test user",
+ "title", null, null);
+ mController.startingActivityForResult();
+ Intent resultData = new Intent();
+ mController.onActivityResult(0, 0, resultData);
+ EditUserPhotoController photoController = mController.getPhotoController();
+
+ assertThat(photoController).isNotNull();
+ verify(photoController).onActivityResult(0, 0, resultData);
+ }
+
+ @Test
+ @Config(shadows = ShadowDialog.class)
+ public void userNameView_inputLongName_shouldBeConstrained() {
+ // generate a string of 200 'A's
+ final String longName = Stream.generate(
+ () -> String.valueOf('A')).limit(200).collect(Collectors.joining());
+
+ final AlertDialog dialog = (AlertDialog) mController.createDialog(mActivity,
+ mActivityStarter, mCurrentIcon,
+ "test user", "title", null,
+ null);
+ dialog.show();
+ final EditText userNameEditText = dialog.findViewById(R.id.user_name);
+ userNameEditText.setText(longName);
+
+ assertThat(userNameEditText.getText().length()).isEqualTo(MAX_USER_NAME_LENGTH);
+ }
+
+ @Test
+ public void cancelCallback_isCalled_whenCancelled() {
+ BiConsumer<String, Drawable> successCallback = mock(BiConsumer.class);
+ Runnable cancelCallback = mock(Runnable.class);
+
+ AlertDialog dialog = (AlertDialog) mController.createDialog(
+ mActivity, mActivityStarter, mCurrentIcon, "test",
+ "title", successCallback, cancelCallback);
+ dialog.show();
+ dialog.cancel();
+
+ verifyZeroInteractions(successCallback);
+ verify(cancelCallback, times(1))
+ .run();
+ }
+
+ @Test
+ public void cancelCallback_isCalled_whenNegativeClicked() {
+ BiConsumer<String, Drawable> successCallback = mock(BiConsumer.class);
+ Runnable cancelCallback = mock(Runnable.class);
+
+ AlertDialog dialog = (AlertDialog) mController.createDialog(
+ mActivity, mActivityStarter, mCurrentIcon, "test",
+ "title", successCallback, cancelCallback);
+ dialog.show();
+ dialog.getButton(Dialog.BUTTON_NEGATIVE).performClick();
+
+ verifyZeroInteractions(successCallback);
+ verify(cancelCallback, times(1))
+ .run();
+ }
+
+ @Test
+ public void successCallback_isCalled_whenNothingChanged() {
+ BiConsumer<String, Drawable> successCallback = mock(BiConsumer.class);
+ Runnable cancelCallback = mock(Runnable.class);
+
+ Drawable oldUserIcon = mCurrentIcon;
+ AlertDialog dialog = (AlertDialog) mController.createDialog(
+ mActivity, mActivityStarter, oldUserIcon, "test",
+ "title", successCallback, cancelCallback);
+ // No change to the photo.
+ when(mController.getPhotoController().getNewUserPhotoDrawable()).thenReturn(null);
+ dialog.show();
+ dialog.getButton(Dialog.BUTTON_POSITIVE).performClick();
+
+ verify(successCallback, times(1))
+ .accept("test", oldUserIcon);
+ verifyZeroInteractions(cancelCallback);
+ }
+
+ @Test
+ public void successCallback_calledWithNullIcon_whenOldIconIsNullAndNothingChanged() {
+ BiConsumer<String, Drawable> successCallback = mock(BiConsumer.class);
+ Runnable cancelCallback = mock(Runnable.class);
+
+ AlertDialog dialog = (AlertDialog) mController.createDialog(
+ mActivity, mActivityStarter, null, "test",
+ "title", successCallback, cancelCallback);
+ // No change to the photo.
+ when(mController.getPhotoController().getNewUserPhotoDrawable()).thenReturn(null);
+ dialog.show();
+ dialog.getButton(Dialog.BUTTON_POSITIVE).performClick();
+
+ verify(successCallback, times(1))
+ .accept("test", null);
+ verifyZeroInteractions(cancelCallback);
+ }
+
+ @Test
+ public void successCallback_isCalled_whenLabelChanges() {
+ BiConsumer<String, Drawable> successCallback = mock(BiConsumer.class);
+ Runnable cancelCallback = mock(Runnable.class);
+
+ AlertDialog dialog = (AlertDialog) mController.createDialog(
+ mActivity, mActivityStarter, mCurrentIcon, "test",
+ "title", successCallback, cancelCallback);
+ // No change to the photo.
+ when(mController.getPhotoController().getNewUserPhotoDrawable()).thenReturn(null);
+ dialog.show();
+ String expectedNewName = "new test user";
+ EditText editText = (EditText) dialog.findViewById(R.id.user_name);
+ editText.setText(expectedNewName);
+ dialog.getButton(Dialog.BUTTON_POSITIVE).performClick();
+
+ verify(successCallback, times(1))
+ .accept(expectedNewName, mCurrentIcon);
+ verifyZeroInteractions(cancelCallback);
+ }
+
+ @Test
+ public void successCallback_isCalled_whenPhotoChanges() {
+ BiConsumer<String, Drawable> successCallback = mock(BiConsumer.class);
+ Runnable cancelCallback = mock(Runnable.class);
+
+ AlertDialog dialog = (AlertDialog) mController.createDialog(
+ mActivity, mActivityStarter, mCurrentIcon, "test",
+ "title", successCallback, cancelCallback);
+ // A different drawable.
+ Drawable newPhoto = mock(Drawable.class);
+ when(mController.getPhotoController().getNewUserPhotoDrawable()).thenReturn(newPhoto);
+ dialog.show();
+ dialog.getButton(Dialog.BUTTON_POSITIVE).performClick();
+
+ verify(successCallback, times(1))
+ .accept("test", newPhoto);
+ verifyZeroInteractions(cancelCallback);
+ }
+
+ @Test
+ public void successCallback_isCalledWithChangedPhoto_whenOldIconIsNullAndPhotoChanges() {
+ BiConsumer<String, Drawable> successCallback = mock(BiConsumer.class);
+ Runnable cancelCallback = mock(Runnable.class);
+
+ AlertDialog dialog = (AlertDialog) mController.createDialog(
+ mActivity, mActivityStarter, null, "test",
+ "title", successCallback, cancelCallback);
+ // A different drawable.
+ Drawable newPhoto = mock(Drawable.class);
+ when(mController.getPhotoController().getNewUserPhotoDrawable()).thenReturn(newPhoto);
+ dialog.show();
+ dialog.getButton(Dialog.BUTTON_POSITIVE).performClick();
+
+ verify(successCallback, times(1))
+ .accept("test", newPhoto);
+ verifyZeroInteractions(cancelCallback);
+ }
+
+ @Test
+ public void createDialog_canNotChangePhoto_nullPhotoController() {
+ mCanChangePhoto = false;
+
+ mController.createDialog(mActivity, mActivityStarter, mCurrentIcon,
+ "test", "title", null, null);
+
+ assertThat(mController.mPhotoController).isNull();
+ }
+}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index a19761ad2669..c1bdb56b9da7 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -60,6 +60,7 @@ public class SecureSettings {
Settings.Secure.ACCESSIBILITY_CAPTIONING_TYPEFACE,
Settings.Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE,
Settings.Secure.ACCESSIBILITY_CAPTIONING_WINDOW_COLOR,
+ Settings.Secure.FORCE_BOLD_TEXT,
Settings.Secure.REDUCE_BRIGHT_COLORS_LEVEL,
Settings.Secure.REDUCE_BRIGHT_COLORS_PERSIST_ACROSS_REBOOTS,
Settings.Secure.TTS_DEFAULT_RATE,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 27c2564e1273..388bf283625c 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -102,6 +102,7 @@ public class SecureSettingsValidators {
Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE,
new InclusiveFloatRangeValidator(0.5f, 2.0f));
VALIDATORS.put(Secure.ACCESSIBILITY_CAPTIONING_WINDOW_COLOR, ANY_INTEGER_VALIDATOR);
+ VALIDATORS.put(Secure.FORCE_BOLD_TEXT, new DiscreteValueValidator(new String[] {"1", "2"}));
VALIDATORS.put(Secure.REDUCE_BRIGHT_COLORS_LEVEL, PERCENTAGE_INTEGER_VALIDATOR);
VALIDATORS.put(Secure.REDUCE_BRIGHT_COLORS_PERSIST_ACROSS_REBOOTS, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.TTS_DEFAULT_RATE, NON_NEGATIVE_INTEGER_VALIDATOR);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index a9843dc49fff..69be14413583 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -440,6 +440,7 @@ public class SettingsBackupTest {
Settings.Global.SHOW_NEW_APP_INSTALLED_NOTIFICATION_ENABLED,
Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS,
Settings.Global.SHOW_PEOPLE_SPACE,
+ Settings.Global.SHOW_NEW_LOCKSCREEN,
Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG,
Settings.Global.SHOW_TEMPERATURE_WARNING,
Settings.Global.SHOW_USB_TEMPERATURE_ALARM,
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 505ef7a58843..bf9b809e5684 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -572,6 +572,13 @@
</intent-filter>
</activity>
+ <!-- People Space UI Screen -->
+ <activity
+ android:name=".people.PeopleSpaceActivity"
+ android:exported="true"
+ android:theme="@android:style/Theme.Material.NoActionBar">
+ </activity>
+
<!-- a gallery of delicious treats -->
<service
android:name=".DessertCaseDream"
@@ -606,6 +613,14 @@
</intent-filter>
</activity>
+ <activity
+ android:name=".user.CreateUserActivity"
+ android:excludeFromRecents="true"
+ android:exported="false"
+ android:finishOnCloseSystemDialogs="true"
+ android:launchMode="singleInstance"
+ android:theme="@style/Theme.CreateUser" />
+
<activity android:name=".Somnambulator"
android:label="@string/start_dreams"
android:icon="@mipmap/ic_launcher_dreams"
diff --git a/packages/SystemUI/docs/plugin_hooks.md b/packages/SystemUI/docs/plugin_hooks.md
index 9fe2e181971a..cde5094f652e 100644
--- a/packages/SystemUI/docs/plugin_hooks.md
+++ b/packages/SystemUI/docs/plugin_hooks.md
@@ -1,33 +1,34 @@
# Plugin hooks
### Action: com.android.systemui.action.PLUGIN_OVERLAY
-Expected interface: [OverlayPlugin](/packages/SystemUI/plugin/src/com/android/systemui/plugins/OverlayPlugin.java)
+Expected interface: [OverlayPlugin](/frameworks/base/packages/SystemUI/plugin/src/com/android
+/systemui/plugins/OverlayPlugin.java)
Use: Allows plugin access to the status bar and nav bar window for whatever nefarious purposes you can imagine.
### Action: com.android.systemui.action.PLUGIN_QS
-Expected interface: [QS](/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java)
+Expected interface: [QS](/frameworks/base/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QS.java)
Use: Allows the entire QS panel to be replaced with something else that is optionally expandable.
Notes: To not mess up the notification panel interaction, much of the QSContainer interface needs to actually be implemented.
### Action: com.android.systemui.action.PLUGIN_QS_FACTORY
-Expected interface: [QSFactory](/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSFactory.java)
+Expected interface: [QSFactory](/frameworks/base/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSFactory.java)
Use: Controls the creation of QS Tiles and their views, can used to add or change system QS tiles, can also be used to change the layout/interaction of the tile views.
### Action: com.android.systemui.action.PLUGIN_NAV_BUTTON
-Expected interface: [NavBarButtonProvider](/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavBarButtonProvider.java)
+Expected interface: [NavBarButtonProvider](/frameworks/base/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavBarButtonProvider.java)
Use: Allows a plugin to create a new nav bar button, or override an existing one with a view of its own.
### Action: com.android.systemui.action.PLUGIN_NAV_GESTURE
-Expected interface: [NavGesture](/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java)
+Expected interface: [NavGesture](/frameworks/base/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java)
Use: Allows touch events from the nav bar to be intercepted and used for other gestures.
### Action: com.android.systemui.action.PLUGIN_LOCKSCREEN_RIGHT_BUTTON
-Expected interface: [IntentButtonProvider](/packages/SystemUI/plugin/src/com/android/systemui/plugins/IntentButtonProvider.java)
+Expected interface: [IntentButtonProvider](/frameworks/base/packages/SystemUI/plugin/src/com/android/systemui/plugins/IntentButtonProvider.java)
Use: Allows a plugin to specify the icon for the bottom right lock screen button, and the intent that gets launched when it is activated.
@@ -37,28 +38,33 @@ Expected interface: [IntentButtonProvider](/packages/SystemUI/plugin/src/com/and
Use: Allows a plugin to specify the icon for the bottom left lock screen button, and the intent that gets launched when it is activated.
### Action: com.android.systemui.action.PLUGIN_GLOBAL_ACTIONS
-Expected interface: [GlobalActions](/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActions.java)
+Expected interface: [GlobalActions](/frameworks/base/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActions.java)
Use: Allows the long-press power menu to be completely replaced.
### Action: com.android.systemui.action.PLUGIN_VOLUME
-Expected interface: [VolumeDialog](/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialog.java)
+Expected interface: [VolumeDialog](/frameworks/base/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialog.java)
Use: Allows replacement of the volume dialog.
### Action: com.android.systemui.action.PLUGIN_NOTIFICATION_SWIPE_ACTION
-Expected interface: [NotificationSwipeActionHelper](/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java)
+Expected interface: [NotificationSwipeActionHelper](/frameworks/base/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/NotificationSwipeActionHelper.java)
Use: Control over swipes/input for notification views, can be used to control what happens when you swipe/long-press
### Action: com.android.systemui.action.PLUGIN_CLOCK
-Expected interface: [ClockPlugin](/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java)
+Expected interface: [ClockPlugin](/frameworks/base/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java)
Use: Allows replacement of the keyguard main clock.
+### Action: com.android.systemui.action.PLUGIN_TOAST
+Expected interface: [ToastPlugin](/frameworks/base/packages/SystemUI/plugin/src/com/android/systemui/plugins/ToastPlugin.java)
+
+Use: Allows replacement of uncustomized toasts created via Toast.makeText().
+
# Global plugin dependencies
These classes can be accessed by any plugin using PluginDependency as long as they @Requires them.
-[VolumeDialogController](/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java) - Mostly just API for the volume plugin
+[VolumeDialogController](/frameworks/base/packages/SystemUI/plugin/src/com/android/systemui/plugins/VolumeDialogController.java) - Mostly just API for the volume plugin
-[ActivityStarter](/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java) - Allows starting of intents while co-operating with keyguard unlocks.
+[ActivityStarter](/frameworks/base/packages/SystemUI/plugin/src/com/android/systemui/plugins/ActivityStarter.java) - Allows starting of intents while co-operating with keyguard unlocks.
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ToastPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ToastPlugin.java
new file mode 100644
index 000000000000..0831e0ef7795
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ToastPlugin.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.plugins;
+
+import android.animation.Animator;
+import android.annotation.NonNull;
+import android.view.View;
+
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+
+/**
+ * Customize toasts displayed by SystemUI (via Toast#makeText)
+ */
+@ProvidesInterface(action = ToastPlugin.ACTION, version = ToastPlugin.VERSION)
+public interface ToastPlugin extends Plugin {
+
+ String ACTION = "com.android.systemui.action.PLUGIN_TOAST";
+ int VERSION = 1;
+
+ /**
+ * Creates a CustomPluginToast.
+ */
+ @NonNull Toast createToast(CharSequence text, String packageName, int userId);
+
+ /**
+ * Custom Toast with the ability to change toast positioning, styling and animations.
+ */
+ interface Toast {
+ /**
+ * Retrieve the Toast view's gravity.
+ * If no changes, returns null.
+ */
+ default Integer getGravity() {
+ return null;
+ }
+
+ /**
+ * Retrieve the Toast view's X-offset.
+ * If no changes, returns null.
+ */
+ default Integer getXOffset() {
+ return null;
+ }
+
+ /**
+ * Retrieve the Toast view's Y-offset.
+ * If no changes, returns null.
+ */
+ default Integer getYOffset() {
+ return null;
+ }
+
+ /**
+ * Retrieve the Toast view's horizontal margin.
+ * If no changes, returns null.
+ */
+ default Integer getHorizontalMargin() {
+ return null;
+ }
+
+ /**
+ * Retrieve the Toast view's vertical margin.
+ * If no changes, returns null.
+ */
+ default Integer getVerticalMargin() {
+ return null;
+ }
+
+ /**
+ * Retrieve the Toast view to show.
+ * If no changes, returns null.
+ */
+ default View getView() {
+ return null;
+ }
+
+ /**
+ * Retrieve the Toast's animate in.
+ * If no changes, returns null.
+ */
+ default Animator getInAnimation() {
+ return null;
+ }
+
+ /**
+ * Retrieve the Toast's animate out.
+ * If no changes, returns null.
+ */
+ default Animator getOutAnimation() {
+ return null;
+ }
+ }
+}
diff --git a/packages/SystemUI/res/drawable/people_space_tile_view_card.xml b/packages/SystemUI/res/drawable/people_space_tile_view_card.xml
new file mode 100644
index 000000000000..6b81703bd343
--- /dev/null
+++ b/packages/SystemUI/res/drawable/people_space_tile_view_card.xml
@@ -0,0 +1,28 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="@android:color/white" />
+ <padding
+ android:left="1dp"
+ android:top="1dp"
+ android:right="1dp"
+ android:bottom="1dp" />
+ <corners
+ android:bottomRightRadius="7dp"
+ android:bottomLeftRadius="7dp"
+ android:topRightRadius="7dp"
+ android:topLeftRadius="7dp" />
+</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/activity_create_new_user.xml b/packages/SystemUI/res/layout/activity_create_new_user.xml
new file mode 100644
index 000000000000..ba434e6d4ac6
--- /dev/null
+++ b/packages/SystemUI/res/layout/activity_create_new_user.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/transparent"
+ android:orientation="vertical">
+
+</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/people_space_activity.xml b/packages/SystemUI/res/layout/people_space_activity.xml
new file mode 100644
index 000000000000..67ecdaa5d7b6
--- /dev/null
+++ b/packages/SystemUI/res/layout/people_space_activity.xml
@@ -0,0 +1,45 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<androidx.core.widget.NestedScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/scroll"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/holo_blue_light">
+
+ <LinearLayout
+ android:id="@+id/people_space_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:orientation="vertical"
+ android:padding="16dp"
+ android:clipChildren="false"
+ android:clipToPadding="false">
+
+ <ImageView
+ android:id="@+id/people_space_cloud"
+ android:layout_width="67dp"
+ android:layout_height="67dp"
+ android:layout_gravity="center_horizontal"
+ android:scaleType="fitCenter"
+ android:focusable="false"
+ android:paddingBottom="16dp"
+ android:tint="?android:attr/colorControlNormal"
+ android:src="@drawable/cloud" />
+
+ </LinearLayout>
+</androidx.core.widget.NestedScrollView> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/people_space_tile_view.xml b/packages/SystemUI/res/layout/people_space_tile_view.xml
new file mode 100644
index 000000000000..80bb07070b31
--- /dev/null
+++ b/packages/SystemUI/res/layout/people_space_tile_view.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/tile_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:background="@drawable/people_space_tile_view_card"
+ android:orientation="vertical"
+ android:padding="16dp"
+ android:layout_marginBottom="24dp"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:elevation="4dp"
+ android:gravity="start">
+
+ <ImageView
+ android:id="@+id/tile_view_package_icon"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_gravity="end" />
+
+ <ImageView
+ android:id="@+id/tile_view_person_icon"
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_gravity="start" />
+
+ <TextView
+ android:id="@+id/tile_view_name"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+ android:paddingVertical="4dp"
+ android:textSize="22sp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="start" />
+
+ <TextView
+ android:id="@+id/tile_view_status"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
+ android:paddingVertical="4dp"
+ android:textSize="16sp"
+ android:textColor="?android:attr/textColorSecondary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:layout_gravity="start" />
+ </LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 2427d36076c5..6bada51aae20 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2678,6 +2678,14 @@
<string name="accessibility_control_move_left">Move left</string>
<!-- Action in accessibility menu to move the magnification window right. [CHAR LIMIT=30] -->
<string name="accessibility_control_move_right">Move right</string>
+ <!-- Content description for magnification mode switch. [CHAR LIMIT=NONE] -->
+ <string name="magnification_mode_switch_description">Magnification switch</string>
+ <!-- A11y state description for magnification mode switch that device is in full-screen mode. [CHAR LIMIT=NONE] -->
+ <string name="magnification_mode_switch_state_full_screen">Magnify entire screen</string>
+ <!-- A11y state description for magnification mode switch that device is in window mode. [CHAR LIMIT=NONE] -->
+ <string name="magnification_mode_switch_state_window">Magnify part of screen</string>
+ <!-- Click action label for magnification switch. [CHAR LIMIT=NONE] -->
+ <string name="magnification_mode_switch_click_label">Switch</string>
<!-- Device Controls strings -->
<!-- Device Controls empty state, title [CHAR LIMIT=30] -->
@@ -2834,4 +2842,10 @@
<string name="build_number_clip_data_label">Build number</string>
<!-- Text to display when copying the build number off QS [CHAR LIMIT=NONE]-->
<string name="build_number_copy_toast">Build number copied to clipboard.</string>
+
+ <!-- Status for last interaction [CHAR LIMIT=120] -->
+ <string name="last_interaction_status" translatable="false">You last chatted <xliff:g id="duration" example="5 hours">%1$s</xliff:g> ago</string>
+ <!-- Status for conversation without interaction data [CHAR LIMIT=120] -->
+ <string name="basic_status" translatable="false">Open conversation</string>
+
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 2b0a963bff18..283918912c76 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -637,6 +637,13 @@
<item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item>
</style>
+ <style name="Theme.CreateUser" parent="@style/Theme.SystemUI">
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowBackground">#33000000</item>
+ <item name="android:windowActionBar">false</item>
+ <item name="android:windowNoTitle">true</item>
+ </style>
+
<style name="TextAppearance.Control">
<item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
</style>
diff --git a/packages/SystemUI/res/xml/fileprovider.xml b/packages/SystemUI/res/xml/fileprovider.xml
index fa6468fefe04..b67378e638e1 100644
--- a/packages/SystemUI/res/xml/fileprovider.xml
+++ b/packages/SystemUI/res/xml/fileprovider.xml
@@ -18,4 +18,5 @@
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="leak" path="leak/"/>
<external-path name="screenrecord" path="."/>
+ <cache-path name="multi_user" path="multi_user/" />
</paths> \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
index 68e404e36bba..1af38970ea4c 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
@@ -16,11 +16,14 @@
package com.android.systemui.accessibility;
+import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
+
import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.PixelFormat;
import android.graphics.PointF;
+import android.os.Bundle;
import android.provider.Settings;
import android.util.MathUtils;
import android.view.Gravity;
@@ -28,6 +31,8 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.widget.ImageView;
import com.android.internal.annotations.VisibleForTesting;
@@ -71,6 +76,29 @@ class MagnificationModeSwitch {
applyResourcesValues();
mImageView.setImageResource(getIconResId(mMagnificationMode));
mImageView.setOnTouchListener(this::onTouch);
+ mImageView.setAccessibilityDelegate(new View.AccessibilityDelegate() {
+ @Override
+ public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ info.setStateDescription(formatStateDescription());
+ info.setContentDescription(mContext.getResources().getString(
+ R.string.magnification_mode_switch_description));
+ final AccessibilityAction clickAction = new AccessibilityAction(
+ AccessibilityAction.ACTION_CLICK.getId(), mContext.getResources().getString(
+ R.string.magnification_mode_switch_click_label));
+ info.addAction(clickAction);
+ info.setClickable(true);
+ }
+
+ @Override
+ public boolean performAccessibilityAction(View host, int action, Bundle args) {
+ if (action == AccessibilityAction.ACTION_CLICK.getId()) {
+ handleSingleTap();
+ return true;
+ }
+ return super.performAccessibilityAction(host, action, args);
+ }
+ });
mAnimationTask = () -> {
mImageView.animate()
@@ -81,6 +109,13 @@ class MagnificationModeSwitch {
};
}
+ private CharSequence formatStateDescription() {
+ final int stringId = mMagnificationMode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW
+ ? R.string.magnification_mode_switch_state_window
+ : R.string.magnification_mode_switch_state_full_screen;
+ return mContext.getResources().getString(stringId);
+ }
+
private void applyResourcesValues() {
final int padding = mContext.getResources().getDimensionPixelSize(
R.dimen.magnification_switch_button_padding);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
index 28bcf3a35117..ba88a599b785 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultActivityBinder.java
@@ -26,6 +26,7 @@ import com.android.systemui.settings.BrightnessDialog;
import com.android.systemui.tuner.TunerActivity;
import com.android.systemui.usb.UsbDebuggingActivity;
import com.android.systemui.usb.UsbDebuggingSecondaryUserActivity;
+import com.android.systemui.user.CreateUserActivity;
import dagger.Binds;
import dagger.Module;
@@ -85,4 +86,10 @@ public abstract class DefaultActivityBinder {
@ClassKey(UsbDebuggingSecondaryUserActivity.class)
public abstract Activity bindUsbDebuggingSecondaryUserActivity(
UsbDebuggingSecondaryUserActivity activity);
+
+ /** Inject into CreateUserActivity. */
+ @Binds
+ @IntoMap
+ @ClassKey(CreateUserActivity.class)
+ public abstract Activity bindCreateUserActivity(CreateUserActivity activity);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 8f4e738e5a5f..63d9a831b33f 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -41,8 +41,10 @@ import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfC
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.statusbar.policy.dagger.SmartRepliesInflationModule;
import com.android.systemui.statusbar.policy.dagger.StatusBarPolicyModule;
import com.android.systemui.tuner.dagger.TunerModule;
+import com.android.systemui.user.UserModule;
import com.android.systemui.util.concurrency.SysUIConcurrencyModule;
import com.android.systemui.util.dagger.UtilModule;
import com.android.systemui.util.sensors.SensorModule;
@@ -73,19 +75,23 @@ import dagger.Provides;
SensorModule.class,
SettingsModule.class,
SettingsUtilModule.class,
+ SmartRepliesInflationModule.class,
StatusBarPolicyModule.class,
SysUIConcurrencyModule.class,
TunerModule.class,
+ UserModule.class,
UtilModule.class,
VolumeModule.class
},
- subcomponents = {StatusBarComponent.class,
- NotificationRowComponent.class,
- DozeComponent.class,
- ExpandableNotificationRowComponent.class,
- KeyguardBouncerComponent.class,
- NotificationShelfComponent.class,
- FragmentService.FragmentCreator.class})
+ subcomponents = {
+ StatusBarComponent.class,
+ NotificationRowComponent.class,
+ DozeComponent.class,
+ ExpandableNotificationRowComponent.class,
+ KeyguardBouncerComponent.class,
+ NotificationShelfComponent.class,
+ FragmentService.FragmentCreator.class
+ })
public abstract class SystemUIModule {
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 6db408659c96..e3ee2a10821b 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -108,6 +108,18 @@ public class LogModule {
return buffer;
}
+ /** Provides a logging buffer for all logs related to Toasts shown by SystemUI. */
+ @Provides
+ @SysUISingleton
+ @ToastLog
+ public static LogBuffer provideToastLogBuffer(
+ LogcatEchoTracker bufferFilter,
+ DumpManager dumpManager) {
+ LogBuffer buffer = new LogBuffer("ToastLog", 50, 10, bufferFilter);
+ buffer.attach(dumpManager);
+ return buffer;
+ }
+
/** Allows logging buffers to be tweaked via adb on debug builds but not on prod builds. */
@Provides
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/ToastLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/ToastLog.java
new file mode 100644
index 000000000000..8671dbfdf1fe
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/ToastLog.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.log.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.android.systemui.log.LogBuffer;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+/** A {@link LogBuffer} for ToastLog-related messages. */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface ToastLog {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 1538e9ea61e1..fc9c3d9d8f0a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -605,6 +605,11 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa
return;
}
mLogGesture = false;
+ String logPackageName = "";
+ // Due to privacy, only top 100 most used apps by all users can be logged.
+ if (mUseMLModel && mVocab.containsKey(mPackageName) && mVocab.get(mPackageName) < 100) {
+ logPackageName = mPackageName;
+ }
SysUiStatsLog.write(SysUiStatsLog.BACK_GESTURE_REPORTED_REPORTED, backType,
(int) mDownPoint.y, mIsOnLeftEdge
? SysUiStatsLog.BACK_GESTURE__X_LOCATION__LEFT
@@ -613,7 +618,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa
(int) mEndPoint.x, (int) mEndPoint.y,
mEdgeWidthLeft + mLeftInset,
mDisplaySize.x - (mEdgeWidthRight + mRightInset),
- mUseMLModel ? mMLResults : -2);
+ mUseMLModel ? mMLResults : -2, logPackageName);
}
private void onMotionEvent(MotionEvent ev) {
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
new file mode 100644
index 000000000000..eeb93bb7d766
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.people;
+
+import android.app.Activity;
+import android.app.INotificationManager;
+import android.app.people.IPeopleManager;
+import android.content.Context;
+import android.content.pm.LauncherApps;
+import android.content.pm.PackageManager;
+import android.content.pm.ShortcutInfo;
+import android.icu.text.MeasureFormat;
+import android.icu.util.Measure;
+import android.icu.util.MeasureUnit;
+import android.os.Bundle;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.service.notification.ConversationChannelWrapper;
+import android.util.Log;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+
+import java.time.Duration;
+import java.util.List;
+import java.util.Locale;
+import java.util.stream.Collectors;
+
+/**
+ * Shows the user their tiles for their priority People (go/live-status).
+ */
+public class PeopleSpaceActivity extends Activity {
+
+ private static String sTAG = "PeopleSpaceActivity";
+
+ private ViewGroup mPeopleSpaceLayout;
+ private IPeopleManager mPeopleManager;
+ private INotificationManager mNotificationManager;
+ private PackageManager mPackageManager;
+ private LauncherApps mLauncherApps;
+ private List<ConversationChannelWrapper> mConversations;
+ private Context mContext;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.people_space_activity);
+ mPeopleSpaceLayout = findViewById(R.id.people_space_layout);
+ mContext = getApplicationContext();
+ mNotificationManager =
+ INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ mPackageManager = getPackageManager();
+ mPeopleManager = IPeopleManager.Stub.asInterface(
+ ServiceManager.getService(Context.PEOPLE_SERVICE));
+ mLauncherApps = mContext.getSystemService(LauncherApps.class);
+ setTileViewsWithPriorityConversations();
+ }
+
+ /**
+ * Retrieves all priority conversations and sets a {@link PeopleSpaceTileView}s for each
+ * priority conversation.
+ */
+ private void setTileViewsWithPriorityConversations() {
+ try {
+ List<ConversationChannelWrapper> conversations =
+ mNotificationManager.getConversations(
+ true /* priority only */).getList();
+ mConversations = conversations.stream().filter(
+ c -> shouldKeepConversation(c)).collect(Collectors.toList());
+ for (ConversationChannelWrapper conversation : mConversations) {
+ PeopleSpaceTileView tileView = new PeopleSpaceTileView(mContext,
+ mPeopleSpaceLayout,
+ conversation.getShortcutInfo().getId());
+ setTileView(tileView, conversation);
+ }
+ } catch (Exception e) {
+ Log.e(sTAG, "Couldn't retrieve conversations", e);
+ }
+ }
+
+ /** Sets {@code tileView} with the data in {@code conversation}. */
+ private void setTileView(PeopleSpaceTileView tileView,
+ ConversationChannelWrapper conversation) {
+ try {
+ ShortcutInfo shortcutInfo = conversation.getShortcutInfo();
+ int userId = UserHandle.getUserHandleForUid(
+ conversation.getUid()).getIdentifier();
+
+ String pkg = shortcutInfo.getPackage();
+ long lastInteraction = mPeopleManager.getLastInteraction(
+ pkg, userId,
+ shortcutInfo.getId());
+ String status = lastInteraction != 0l ? mContext.getString(
+ R.string.last_interaction_status,
+ getLastInteractionString(
+ lastInteraction)) : mContext.getString(R.string.basic_status);
+ tileView.setStatus(status);
+
+ tileView.setName(shortcutInfo.getLabel().toString());
+ tileView.setPackageIcon(mPackageManager.getApplicationIcon(pkg));
+ tileView.setPersonIcon(mLauncherApps.getShortcutIconDrawable(shortcutInfo, 0));
+ tileView.setOnClickListener(mLauncherApps, shortcutInfo);
+ } catch (Exception e) {
+ Log.e(sTAG, "Couldn't retrieve shortcut information", e);
+ }
+ }
+
+ /** Returns a readable representation of {@code lastInteraction}. */
+ private String getLastInteractionString(long lastInteraction) {
+ long now = System.currentTimeMillis();
+ Duration durationSinceLastInteraction = Duration.ofMillis(
+ now - lastInteraction);
+ MeasureFormat formatter = MeasureFormat.getInstance(Locale.getDefault(),
+ MeasureFormat.FormatWidth.WIDE);
+ if (durationSinceLastInteraction.toDays() >= 1) {
+ return
+ formatter
+ .formatMeasures(new Measure(durationSinceLastInteraction.toDays(),
+ MeasureUnit.DAY));
+ } else if (durationSinceLastInteraction.toHours() >= 1) {
+ return formatter.formatMeasures(new Measure(durationSinceLastInteraction.toHours(),
+ MeasureUnit.HOUR));
+ } else if (durationSinceLastInteraction.toMinutes() >= 1) {
+ return formatter.formatMeasures(new Measure(durationSinceLastInteraction.toMinutes(),
+ MeasureUnit.MINUTE));
+ } else {
+ return formatter.formatMeasures(
+ new Measure(durationSinceLastInteraction.toMillis() / 1000,
+ MeasureUnit.SECOND));
+ }
+ }
+
+ /**
+ * Returns whether the {@code conversation} should be kept for display in the People Space.
+ *
+ * <p>A valid {@code conversation} must:
+ * <ul>
+ * <li>Have a non-null {@link ShortcutInfo}
+ * <li>Have an associated label in the {@link ShortcutInfo}
+ * </ul>
+ * </li>
+ */
+ private boolean shouldKeepConversation(ConversationChannelWrapper conversation) {
+ ShortcutInfo shortcutInfo = conversation.getShortcutInfo();
+ return shortcutInfo != null && shortcutInfo.getLabel().length() != 0;
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ // Refresh tile views to sync new conversations.
+ setTileViewsWithPriorityConversations();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java
new file mode 100644
index 000000000000..d5ef190d5ff1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceTileView.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.people;
+
+import android.content.Context;
+import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutInfo;
+import android.graphics.drawable.Drawable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+
+/**
+ * PeopleSpaceTileView renders an individual person's tile with associated status.
+ */
+public class PeopleSpaceTileView extends LinearLayout {
+
+ private View mTileView;
+ private TextView mNameView;
+ private TextView mStatusView;
+ private ImageView mPackageIconView;
+ private ImageView mPersonIconView;
+
+ public PeopleSpaceTileView(Context context, ViewGroup view, String shortcutId) {
+ super(context);
+ mTileView = view.findViewWithTag(shortcutId);
+ if (mTileView == null) {
+ LayoutInflater inflater = LayoutInflater.from(context);
+ mTileView = inflater.inflate(R.layout.people_space_tile_view, view, false);
+ view.addView(mTileView, LayoutParams.MATCH_PARENT,
+ LayoutParams.MATCH_PARENT);
+ mTileView.setTag(shortcutId);
+ }
+ mNameView = mTileView.findViewById(R.id.tile_view_name);
+ mStatusView = mTileView.findViewById(R.id.tile_view_status);
+ mPackageIconView = mTileView.findViewById(R.id.tile_view_package_icon);
+ mPersonIconView = mTileView.findViewById(R.id.tile_view_person_icon);
+ }
+
+ /** Sets the name text on the tile. */
+ public void setName(String name) {
+ mNameView.setText(name);
+ }
+
+ /** Sets the status text on the tile. */
+ public void setStatus(String status) {
+ mStatusView.setText(status);
+ }
+
+ /** Sets the package drawable on the tile. */
+ public void setPackageIcon(Drawable drawable) {
+ mPackageIconView.setImageDrawable(drawable);
+ }
+
+ /** Sets the person drawable on the tile. */
+ public void setPersonIcon(Drawable drawable) {
+ mPersonIconView.setImageDrawable(drawable);
+ }
+
+ /** Sets the click listener of the tile. */
+ public void setOnClickListener(LauncherApps launcherApps, ShortcutInfo shortcutInfo) {
+ mTileView.setOnClickListener(v -> launcherApps.startShortcut(shortcutInfo, null, null));
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index 201ed9c9ebec..8ddd4c9816cd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -155,7 +155,7 @@ public class UserDetailView extends PseudoGridView {
}
view.setActivated(true);
}
- switchTo(tag);
+ onUserListItemClicked(tag);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 3b0415b31eb5..5279a20a67a7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -168,7 +168,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
if (!verifyCaller("startScreenPinning")) {
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mHandler.post(() -> {
mStatusBarOptionalLazy.ifPresent(
@@ -185,7 +185,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
if (!verifyCaller("stopScreenPinning")) {
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mHandler.post(() -> {
try {
@@ -205,7 +205,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
if (!verifyCaller("onStatusBarMotionEvent")) {
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
// TODO move this logic to message queue
mStatusBarOptionalLazy.ifPresent(statusBarLazy -> {
@@ -240,7 +240,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
if (!verifyCaller("onOverviewShown")) {
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mHandler.post(() -> {
for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
@@ -257,7 +257,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
if (!verifyCaller("getNonMinimizedSplitScreenSecondaryBounds")) {
return null;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
return mSplitScreenOptional.map(splitScreen ->
splitScreen.getDividerView().getNonMinimizedSplitScreenSecondaryBounds())
@@ -272,7 +272,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
if (!verifyCaller("setNavBarButtonAlpha")) {
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mNavBarButtonAlpha = alpha;
mHandler.post(() -> notifyNavBarButtonAlphaChanged(alpha, animate));
@@ -291,7 +291,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
if (!verifyCaller("onAssistantProgress")) {
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mHandler.post(() -> notifyAssistantProgress(progress));
} finally {
@@ -304,7 +304,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
if (!verifyCaller("onAssistantGestureCompletion")) {
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mHandler.post(() -> notifyAssistantGestureCompletion(velocity));
} finally {
@@ -317,7 +317,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
if (!verifyCaller("startAssistant")) {
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mHandler.post(() -> notifyStartAssistant(bundle));
} finally {
@@ -330,7 +330,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
if (!verifyCaller("monitorGestureInput")) {
return null;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
final InputMonitor monitor =
InputManager.getInstance().monitorGestureInput(name, displayId);
@@ -348,7 +348,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
if (!verifyCaller("notifyAccessibilityButtonClicked")) {
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
AccessibilityManager.getInstance(mContext)
.notifyAccessibilityButtonClicked(displayId);
@@ -362,7 +362,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
if (!verifyCaller("notifyAccessibilityButtonLongClicked")) {
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
final Intent intent =
new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON);
@@ -382,7 +382,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
"ByPass setShelfHeight, FEATURE_PICTURE_IN_PICTURE:" + mHasPipFeature);
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mPipOptional.ifPresent(
pip -> pip.setShelfHeight(visible, shelfHeight));
@@ -410,7 +410,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
+ mHasPipFeature);
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mPipOptional.ifPresent(
pip -> pip.setPinnedStackAnimationType(
@@ -428,7 +428,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
return;
}
mIPinnedStackAnimationListener = listener;
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mPipOptional.ifPresent(
pip -> pip.setPinnedStackAnimationListener(mPinnedStackAnimationCallback));
@@ -442,7 +442,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
if (!verifyCaller("onQuickSwitchToNewTask")) {
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mHandler.post(() -> notifyQuickSwitchToNewTask(rotation));
} finally {
@@ -455,7 +455,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
if (!verifyCaller("startOneHandedMode")) {
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mOneHandedOptional.ifPresent(oneHanded -> oneHanded.startOneHanded());
} finally {
@@ -468,7 +468,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
if (!verifyCaller("stopOneHandedMode")) {
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mOneHandedOptional.ifPresent(oneHanded -> oneHanded.stopOneHanded(
OneHandedEvents.EVENT_ONE_HANDED_TRIGGER_GESTURE_OUT));
@@ -497,7 +497,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
if (!verifyCaller("expandNotificationPanel")) {
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN);
} finally {
@@ -512,7 +512,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
if (!verifyCaller("startSwipePipToHome") || !mHasPipFeature) {
return null;
}
- long binderToken = Binder.clearCallingIdentity();
+ final long binderToken = Binder.clearCallingIdentity();
try {
return mPipOptional.map(pip ->
pip.startSwipePipToHome(componentName, activityInfo,
@@ -528,7 +528,7 @@ public class OverviewProxyService extends CurrentUserTracker implements
if (!verifyCaller("stopSwipePipToHome") || !mHasPipFeature) {
return;
}
- long binderToken = Binder.clearCallingIdentity();
+ final long binderToken = Binder.clearCallingIdentity();
try {
mPipOptional.ifPresent(pip -> pip.stopSwipePipToHome(
componentName, destinationBounds));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index 1d72557c6a89..c995e324ecfe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -81,21 +81,27 @@ public class ExpandableNotificationRowController implements NodeController {
private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
@Inject
- public ExpandableNotificationRowController(ExpandableNotificationRow view,
+ public ExpandableNotificationRowController(
+ ExpandableNotificationRow view,
NotificationListContainer listContainer,
ActivatableNotificationViewController activatableNotificationViewController,
- NotificationMediaManager mediaManager, PluginManager pluginManager,
- SystemClock clock, @AppName String appName, @NotificationKey String notificationKey,
+ NotificationMediaManager mediaManager,
+ PluginManager pluginManager,
+ SystemClock clock,
+ @AppName String appName,
+ @NotificationKey String notificationKey,
KeyguardBypassController keyguardBypassController,
GroupMembershipManager groupMembershipManager,
GroupExpansionManager groupExpansionManager,
RowContentBindStage rowContentBindStage,
- NotificationLogger notificationLogger, HeadsUpManager headsUpManager,
+ NotificationLogger notificationLogger,
+ HeadsUpManager headsUpManager,
ExpandableNotificationRow.OnExpandClickListener onExpandClickListener,
StatusBarStateController statusBarStateController,
NotificationGutsManager notificationGutsManager,
@Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
- OnUserInteractionCallback onUserInteractionCallback, FalsingManager falsingManager,
+ OnUserInteractionCallback onUserInteractionCallback,
+ FalsingManager falsingManager,
PeopleNotificationIdentifier peopleNotificationIdentifier) {
mView = view;
mListContainer = listContainer;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 9bcac1163acc..c2c4590fa6cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -42,17 +42,15 @@ import com.android.systemui.media.MediaDataManagerKt;
import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.statusbar.InflationTask;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.notification.ConversationNotificationProcessor;
import com.android.systemui.statusbar.notification.InflationException;
import com.android.systemui.statusbar.notification.MediaNotificationProcessor;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.InflatedSmartReplies;
import com.android.systemui.statusbar.policy.InflatedSmartReplies.SmartRepliesAndActions;
-import com.android.systemui.statusbar.policy.SmartReplyConstants;
+import com.android.systemui.statusbar.policy.SmartRepliesAndActionsInflater;
import com.android.systemui.util.Assert;
import java.util.HashMap;
@@ -60,8 +58,6 @@ import java.util.concurrent.Executor;
import javax.inject.Inject;
-import dagger.Lazy;
-
/**
* {@link NotificationContentInflater} binds content to a {@link ExpandableNotificationRow} by
* asynchronously building the content's {@link RemoteViews} and applying it to the row.
@@ -76,27 +72,24 @@ public class NotificationContentInflater implements NotificationRowContentBinder
private final boolean mIsMediaInQS;
private final NotificationRemoteInputManager mRemoteInputManager;
private final NotifRemoteViewCache mRemoteViewCache;
- private final Lazy<SmartReplyConstants> mSmartReplyConstants;
- private final Lazy<SmartReplyController> mSmartReplyController;
private final ConversationNotificationProcessor mConversationProcessor;
private final Executor mBgExecutor;
+ private final SmartRepliesAndActionsInflater mSmartRepliesAndActionsInflater;
@Inject
NotificationContentInflater(
NotifRemoteViewCache remoteViewCache,
NotificationRemoteInputManager remoteInputManager,
- Lazy<SmartReplyConstants> smartReplyConstants,
- Lazy<SmartReplyController> smartReplyController,
ConversationNotificationProcessor conversationProcessor,
MediaFeatureFlag mediaFeatureFlag,
- @Background Executor bgExecutor) {
+ @Background Executor bgExecutor,
+ SmartRepliesAndActionsInflater smartRepliesInflater) {
mRemoteViewCache = remoteViewCache;
mRemoteInputManager = remoteInputManager;
- mSmartReplyConstants = smartReplyConstants;
- mSmartReplyController = smartReplyController;
mConversationProcessor = conversationProcessor;
mIsMediaInQS = mediaFeatureFlag.getEnabled();
mBgExecutor = bgExecutor;
+ mSmartRepliesAndActionsInflater = smartRepliesInflater;
}
@Override
@@ -132,8 +125,6 @@ public class NotificationContentInflater implements NotificationRowContentBinder
contentToBind,
mRemoteViewCache,
entry,
- mSmartReplyConstants.get(),
- mSmartReplyController.get(),
mConversationProcessor,
row,
bindParams.isLowPriority,
@@ -141,7 +132,8 @@ public class NotificationContentInflater implements NotificationRowContentBinder
bindParams.usesIncreasedHeadsUpHeight,
callback,
mRemoteInputManager.getRemoteViewsOnClickHandler(),
- mIsMediaInQS);
+ mIsMediaInQS,
+ mSmartRepliesAndActionsInflater);
if (mInflateSynchronously) {
task.onPostExecute(task.doInBackground());
} else {
@@ -157,17 +149,19 @@ public class NotificationContentInflater implements NotificationRowContentBinder
boolean inflateSynchronously,
@InflationFlag int reInflateFlags,
Notification.Builder builder,
- Context packageContext) {
+ Context packageContext,
+ SmartRepliesAndActionsInflater smartRepliesInflater) {
InflationProgress result = createRemoteViews(reInflateFlags,
builder,
bindParams.isLowPriority,
bindParams.usesIncreasedHeight,
bindParams.usesIncreasedHeadsUpHeight,
packageContext);
+
result = inflateSmartReplyViews(result, reInflateFlags, entry,
- row.getContext(), packageContext, row.getHeadsUpManager(),
- mSmartReplyConstants.get(), mSmartReplyController.get(),
- row.getExistingSmartRepliesAndActions());
+ row.getContext(), packageContext,
+ row.getExistingSmartRepliesAndActions(),
+ smartRepliesInflater);
apply(
mBgExecutor,
@@ -268,22 +262,21 @@ public class NotificationContentInflater implements NotificationRowContentBinder
}
}
- private static InflationProgress inflateSmartReplyViews(InflationProgress result,
- @InflationFlag int reInflateFlags, NotificationEntry entry, Context context,
- Context packageContext, HeadsUpManager headsUpManager,
- SmartReplyConstants smartReplyConstants, SmartReplyController smartReplyController,
- SmartRepliesAndActions previousSmartRepliesAndActions) {
+ private static InflationProgress inflateSmartReplyViews(
+ InflationProgress result,
+ @InflationFlag int reInflateFlags,
+ NotificationEntry entry,
+ Context context,
+ Context packageContext,
+ SmartRepliesAndActions previousSmartRepliesAndActions,
+ SmartRepliesAndActionsInflater inflater) {
if ((reInflateFlags & FLAG_CONTENT_VIEW_EXPANDED) != 0 && result.newExpandedView != null) {
- result.expandedInflatedSmartReplies =
- InflatedSmartReplies.inflate(
- context, packageContext, entry, smartReplyConstants,
- smartReplyController, headsUpManager, previousSmartRepliesAndActions);
+ result.expandedInflatedSmartReplies = inflater.inflateSmartReplies(
+ context, packageContext, entry, previousSmartRepliesAndActions);
}
if ((reInflateFlags & FLAG_CONTENT_VIEW_HEADS_UP) != 0 && result.newHeadsUpView != null) {
- result.headsUpInflatedSmartReplies =
- InflatedSmartReplies.inflate(
- context, packageContext, entry, smartReplyConstants,
- smartReplyController, headsUpManager, previousSmartRepliesAndActions);
+ result.headsUpInflatedSmartReplies = inflater.inflateSmartReplies(
+ context, packageContext, entry, previousSmartRepliesAndActions);
}
return result;
}
@@ -709,8 +702,6 @@ public class NotificationContentInflater implements NotificationRowContentBinder
private final boolean mUsesIncreasedHeadsUpHeight;
private final @InflationFlag int mReInflateFlags;
private final NotifRemoteViewCache mRemoteViewCache;
- private final SmartReplyConstants mSmartReplyConstants;
- private final SmartReplyController mSmartReplyController;
private final Executor mBgExecutor;
private ExpandableNotificationRow mRow;
private Exception mError;
@@ -718,6 +709,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder
private CancellationSignal mCancellationSignal;
private final ConversationNotificationProcessor mConversationProcessor;
private final boolean mIsMediaInQS;
+ private final SmartRepliesAndActionsInflater mSmartRepliesInflater;
private AsyncInflationTask(
Executor bgExecutor,
@@ -725,8 +717,6 @@ public class NotificationContentInflater implements NotificationRowContentBinder
@InflationFlag int reInflateFlags,
NotifRemoteViewCache cache,
NotificationEntry entry,
- SmartReplyConstants smartReplyConstants,
- SmartReplyController smartReplyController,
ConversationNotificationProcessor conversationProcessor,
ExpandableNotificationRow row,
boolean isLowPriority,
@@ -734,15 +724,15 @@ public class NotificationContentInflater implements NotificationRowContentBinder
boolean usesIncreasedHeadsUpHeight,
InflationCallback callback,
RemoteViews.OnClickHandler remoteViewClickHandler,
- boolean isMediaFlagEnabled) {
+ boolean isMediaFlagEnabled,
+ SmartRepliesAndActionsInflater smartRepliesInflater) {
mEntry = entry;
mRow = row;
- mSmartReplyConstants = smartReplyConstants;
- mSmartReplyController = smartReplyController;
mBgExecutor = bgExecutor;
mInflateSynchronously = inflateSynchronously;
mReInflateFlags = reInflateFlags;
mRemoteViewCache = cache;
+ mSmartRepliesInflater = smartRepliesInflater;
mContext = mRow.getContext();
mIsLowPriority = isLowPriority;
mUsesIncreasedHeight = usesIncreasedHeight;
@@ -786,10 +776,16 @@ public class NotificationContentInflater implements NotificationRowContentBinder
InflationProgress inflationProgress = createRemoteViews(mReInflateFlags,
recoveredBuilder, mIsLowPriority, mUsesIncreasedHeight,
mUsesIncreasedHeadsUpHeight, packageContext);
- return inflateSmartReplyViews(inflationProgress, mReInflateFlags, mEntry,
- mRow.getContext(), packageContext, mRow.getHeadsUpManager(),
- mSmartReplyConstants, mSmartReplyController,
- mRow.getExistingSmartRepliesAndActions());
+ SmartRepliesAndActions repliesAndActions =
+ mRow.getExistingSmartRepliesAndActions();
+ return inflateSmartReplyViews(
+ inflationProgress,
+ mReInflateFlags,
+ mEntry,
+ mContext,
+ packageContext,
+ repliesAndActions,
+ mSmartRepliesInflater);
} catch (Exception e) {
mError = e;
return null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 1de9308a40b1..8a644ed4d3ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -57,6 +57,7 @@ import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewW
import com.android.systemui.statusbar.policy.InflatedSmartReplies;
import com.android.systemui.statusbar.policy.InflatedSmartReplies.SmartRepliesAndActions;
import com.android.systemui.statusbar.policy.RemoteInputView;
+import com.android.systemui.statusbar.policy.SmartRepliesAndActionsInflaterKt;
import com.android.systemui.statusbar.policy.SmartReplyConstants;
import com.android.systemui.statusbar.policy.SmartReplyView;
@@ -1191,23 +1192,31 @@ public class NotificationContentView extends FrameLayout {
View bigContentView = mExpandedChild;
if (bigContentView != null && (bigContentView instanceof ViewGroup)) {
- mMediaTransferManager.applyMediaTransferView((ViewGroup) bigContentView,
- entry);
+ mMediaTransferManager.applyMediaTransferView((ViewGroup) bigContentView, entry);
}
View smallContentView = mContractedChild;
if (smallContentView != null && (smallContentView instanceof ViewGroup)) {
- mMediaTransferManager.applyMediaTransferView((ViewGroup) smallContentView,
- entry);
+ mMediaTransferManager.applyMediaTransferView((ViewGroup) smallContentView, entry);
}
}
+ /**
+ * Returns whether the {@link Notification} represented by entry has a free-form remote input.
+ * Such an input can be used e.g. to implement smart reply buttons - by passing the replies
+ * through the remote input.
+ */
+ public static boolean hasFreeformRemoteInput(NotificationEntry entry) {
+ Notification notification = entry.getSbn().getNotification();
+ return null != notification.findRemoteInputActionPair(true /* freeform */);
+ }
+
private void applyRemoteInputAndSmartReply(final NotificationEntry entry) {
if (mRemoteInputController == null) {
return;
}
- applyRemoteInput(entry, InflatedSmartReplies.hasFreeformRemoteInput(entry));
+ applyRemoteInput(entry, hasFreeformRemoteInput(entry));
if (mExpandedInflatedSmartReplies == null && mHeadsUpInflatedSmartReplies == null) {
if (DEBUG) {
@@ -1438,7 +1447,8 @@ public class NotificationContentView extends FrameLayout {
}
LinearLayout smartReplyContainer = (LinearLayout) smartReplyContainerCandidate;
- if (!InflatedSmartReplies.shouldShowSmartReplyView(entry, smartRepliesAndActions)) {
+ if (!SmartRepliesAndActionsInflaterKt
+ .shouldShowSmartReplyView(entry, smartRepliesAndActions)) {
smartReplyContainer.setVisibility(View.GONE);
return null;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplies.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplies.java
index c6ae669d5d08..cbc8405cc057 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplies.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/InflatedSmartReplies.java
@@ -19,27 +19,8 @@ package com.android.systemui.statusbar.policy;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
-import android.app.RemoteInput;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ResolveInfo;
-import android.os.Build;
-import android.util.Log;
-import android.util.Pair;
import android.widget.Button;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.ArrayUtils;
-import com.android.systemui.Dependency;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
-import com.android.systemui.shared.system.PackageManagerWrapper;
-import com.android.systemui.statusbar.NotificationUiAdjustment;
-import com.android.systemui.statusbar.SmartReplyController;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -48,13 +29,11 @@ import java.util.List;
* thread, to later be accessed and modified on the (performance critical) UI thread.
*/
public class InflatedSmartReplies {
- private static final String TAG = "InflatedSmartReplies";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@Nullable private final SmartReplyView mSmartReplyView;
@Nullable private final List<Button> mSmartSuggestionButtons;
@NonNull private final SmartRepliesAndActions mSmartRepliesAndActions;
- private InflatedSmartReplies(
+ public InflatedSmartReplies(
@Nullable SmartReplyView smartReplyView,
@Nullable List<Button> smartSuggestionButtons,
@NonNull SmartRepliesAndActions smartRepliesAndActions) {
@@ -76,206 +55,6 @@ public class InflatedSmartReplies {
}
/**
- * Inflate a SmartReplyView and its smart suggestions.
- */
- public static InflatedSmartReplies inflate(
- Context context,
- Context packageContext,
- NotificationEntry entry,
- SmartReplyConstants smartReplyConstants,
- SmartReplyController smartReplyController,
- HeadsUpManager headsUpManager,
- SmartRepliesAndActions existingSmartRepliesAndActions) {
- SmartRepliesAndActions newSmartRepliesAndActions =
- chooseSmartRepliesAndActions(smartReplyConstants, entry);
- if (!shouldShowSmartReplyView(entry, newSmartRepliesAndActions)) {
- return new InflatedSmartReplies(null /* smartReplyView */,
- null /* smartSuggestionButtons */, newSmartRepliesAndActions);
- }
-
- // Only block clicks if the smart buttons are different from the previous set - to avoid
- // scenarios where a user incorrectly cannot click smart buttons because the notification is
- // updated.
- boolean delayOnClickListener =
- !areSuggestionsSimilar(existingSmartRepliesAndActions, newSmartRepliesAndActions);
-
- SmartReplyView smartReplyView = SmartReplyView.inflate(context);
-
- List<Button> suggestionButtons = new ArrayList<>();
- if (newSmartRepliesAndActions.smartReplies != null) {
- suggestionButtons.addAll(smartReplyView.inflateRepliesFromRemoteInput(
- newSmartRepliesAndActions.smartReplies, smartReplyController, entry,
- delayOnClickListener));
- }
- if (newSmartRepliesAndActions.smartActions != null) {
- suggestionButtons.addAll(
- smartReplyView.inflateSmartActions(packageContext,
- newSmartRepliesAndActions.smartActions, smartReplyController, entry,
- headsUpManager, delayOnClickListener));
- }
-
- return new InflatedSmartReplies(smartReplyView, suggestionButtons,
- newSmartRepliesAndActions);
- }
-
- @VisibleForTesting
- static boolean areSuggestionsSimilar(
- SmartRepliesAndActions left, SmartRepliesAndActions right) {
- if (left == right) return true;
- if (left == null || right == null) return false;
-
- if (!left.getSmartReplies().equals(right.getSmartReplies())) {
- return false;
- }
-
- return !NotificationUiAdjustment.areDifferent(
- left.getSmartActions(), right.getSmartActions());
- }
-
- /**
- * Returns whether we should show the smart reply view and its smart suggestions.
- */
- public static boolean shouldShowSmartReplyView(
- NotificationEntry entry,
- SmartRepliesAndActions smartRepliesAndActions) {
- if (smartRepliesAndActions.smartReplies == null
- && smartRepliesAndActions.smartActions == null) {
- // There are no smart replies and no smart actions.
- return false;
- }
- // If we are showing the spinner we don't want to add the buttons.
- boolean showingSpinner = entry.getSbn().getNotification()
- .extras.getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false);
- if (showingSpinner) {
- return false;
- }
- // If we are keeping the notification around while sending we don't want to add the buttons.
- boolean hideSmartReplies = entry.getSbn().getNotification()
- .extras.getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false);
- if (hideSmartReplies) {
- return false;
- }
- return true;
- }
-
- /**
- * Chose what smart replies and smart actions to display. App generated suggestions take
- * precedence. So if the app provides any smart replies, we don't show any
- * replies or actions generated by the NotificationAssistantService (NAS), and if the app
- * provides any smart actions we also don't show any NAS-generated replies or actions.
- */
- @NonNull
- public static SmartRepliesAndActions chooseSmartRepliesAndActions(
- SmartReplyConstants smartReplyConstants,
- final NotificationEntry entry) {
- Notification notification = entry.getSbn().getNotification();
- Pair<RemoteInput, Notification.Action> remoteInputActionPair =
- notification.findRemoteInputActionPair(false /* freeform */);
- Pair<RemoteInput, Notification.Action> freeformRemoteInputActionPair =
- notification.findRemoteInputActionPair(true /* freeform */);
-
- if (!smartReplyConstants.isEnabled()) {
- if (DEBUG) {
- Log.d(TAG, "Smart suggestions not enabled, not adding suggestions for "
- + entry.getSbn().getKey());
- }
- return new SmartRepliesAndActions(null, null);
- }
- // Only use smart replies from the app if they target P or above. We have this check because
- // the smart reply API has been used for other things (Wearables) in the past. The API to
- // add smart actions is new in Q so it doesn't require a target-sdk check.
- boolean enableAppGeneratedSmartReplies = (!smartReplyConstants.requiresTargetingP()
- || entry.targetSdk >= Build.VERSION_CODES.P);
-
- boolean appGeneratedSmartRepliesExist =
- enableAppGeneratedSmartReplies
- && remoteInputActionPair != null
- && !ArrayUtils.isEmpty(remoteInputActionPair.first.getChoices())
- && remoteInputActionPair.second.actionIntent != null;
-
- List<Notification.Action> appGeneratedSmartActions = notification.getContextualActions();
- boolean appGeneratedSmartActionsExist = !appGeneratedSmartActions.isEmpty();
-
- SmartReplyView.SmartReplies smartReplies = null;
- SmartReplyView.SmartActions smartActions = null;
- if (appGeneratedSmartRepliesExist) {
- smartReplies = new SmartReplyView.SmartReplies(
- Arrays.asList(remoteInputActionPair.first.getChoices()),
- remoteInputActionPair.first,
- remoteInputActionPair.second.actionIntent,
- false /* fromAssistant */);
- }
- if (appGeneratedSmartActionsExist) {
- smartActions = new SmartReplyView.SmartActions(appGeneratedSmartActions,
- false /* fromAssistant */);
- }
- // Apps didn't provide any smart replies / actions, use those from NAS (if any).
- if (!appGeneratedSmartRepliesExist && !appGeneratedSmartActionsExist) {
- boolean useGeneratedReplies = !ArrayUtils.isEmpty(entry.getSmartReplies())
- && freeformRemoteInputActionPair != null
- && freeformRemoteInputActionPair.second.getAllowGeneratedReplies()
- && freeformRemoteInputActionPair.second.actionIntent != null;
- if (useGeneratedReplies) {
- smartReplies = new SmartReplyView.SmartReplies(
- entry.getSmartReplies(),
- freeformRemoteInputActionPair.first,
- freeformRemoteInputActionPair.second.actionIntent,
- true /* fromAssistant */);
- }
- boolean useSmartActions = !ArrayUtils.isEmpty(entry.getSmartActions())
- && notification.getAllowSystemGeneratedContextualActions();
- if (useSmartActions) {
- List<Notification.Action> systemGeneratedActions =
- entry.getSmartActions();
- // Filter actions if we're in kiosk-mode - we don't care about screen pinning mode,
- // since notifications aren't shown there anyway.
- ActivityManagerWrapper activityManagerWrapper =
- Dependency.get(ActivityManagerWrapper.class);
- if (activityManagerWrapper.isLockTaskKioskModeActive()) {
- systemGeneratedActions = filterWhiteListedLockTaskApps(systemGeneratedActions);
- }
- smartActions = new SmartReplyView.SmartActions(
- systemGeneratedActions, true /* fromAssistant */);
- }
- }
- return new SmartRepliesAndActions(smartReplies, smartActions);
- }
-
- /**
- * Filter actions so that only actions pointing to whitelisted apps are allowed.
- * This filtering is only meaningful when in lock-task mode.
- */
- private static List<Notification.Action> filterWhiteListedLockTaskApps(
- List<Notification.Action> actions) {
- PackageManagerWrapper packageManagerWrapper = Dependency.get(PackageManagerWrapper.class);
- DevicePolicyManagerWrapper devicePolicyManagerWrapper =
- Dependency.get(DevicePolicyManagerWrapper.class);
- List<Notification.Action> filteredActions = new ArrayList<>();
- for (Notification.Action action : actions) {
- if (action.actionIntent == null) continue;
- Intent intent = action.actionIntent.getIntent();
- // Only allow actions that are explicit (implicit intents are not handled in lock-task
- // mode), and link to whitelisted apps.
- ResolveInfo resolveInfo = packageManagerWrapper.resolveActivity(intent, 0 /* flags */);
- if (resolveInfo != null && devicePolicyManagerWrapper.isLockTaskPermitted(
- resolveInfo.activityInfo.packageName)) {
- filteredActions.add(action);
- }
- }
- return filteredActions;
- }
-
- /**
- * Returns whether the {@link Notification} represented by entry has a free-form remote input.
- * Such an input can be used e.g. to implement smart reply buttons - by passing the replies
- * through the remote input.
- */
- public static boolean hasFreeformRemoteInput(NotificationEntry entry) {
- Notification notification = entry.getSbn().getNotification();
- return null != notification.findRemoteInputActionPair(true /* freeform */);
- }
-
- /**
* A storage for smart replies and smart action.
*/
public static class SmartRepliesAndActions {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
index f52a6e0191a1..f45178cd2230 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java
@@ -342,7 +342,7 @@ public class KeyguardUserSwitcher {
}
v.setActivated(true);
}
- switchTo(user);
+ onUserListItemClicked(user);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartRepliesAndActionsInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartRepliesAndActionsInflater.kt
new file mode 100644
index 000000000000..b2c1f4840068
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartRepliesAndActionsInflater.kt
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy
+
+import android.app.Notification
+import android.app.PendingIntent
+import android.app.RemoteInput
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import android.os.Bundle
+import android.os.SystemClock
+import android.util.Log
+import android.view.ContextThemeWrapper
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.accessibility.AccessibilityNodeInfo
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction
+import android.widget.Button
+import com.android.systemui.R
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.shared.system.ActivityManagerWrapper
+import com.android.systemui.shared.system.DevicePolicyManagerWrapper
+import com.android.systemui.shared.system.PackageManagerWrapper
+import com.android.systemui.statusbar.NotificationRemoteInputManager
+import com.android.systemui.statusbar.NotificationUiAdjustment
+import com.android.systemui.statusbar.SmartReplyController
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.logging.NotificationLogger
+import com.android.systemui.statusbar.phone.KeyguardDismissUtil
+import com.android.systemui.statusbar.policy.InflatedSmartReplies.SmartRepliesAndActions
+import com.android.systemui.statusbar.policy.SmartReplyView.SmartActions
+import com.android.systemui.statusbar.policy.SmartReplyView.SmartButtonType
+import com.android.systemui.statusbar.policy.SmartReplyView.SmartReplies
+import javax.inject.Inject
+
+/** Returns whether we should show the smart reply view and its smart suggestions. */
+fun shouldShowSmartReplyView(
+ entry: NotificationEntry,
+ smartRepliesAndActions: SmartRepliesAndActions
+): Boolean {
+ if (smartRepliesAndActions.smartReplies == null
+ && smartRepliesAndActions.smartActions == null) {
+ // There are no smart replies and no smart actions.
+ return false
+ }
+ // If we are showing the spinner we don't want to add the buttons.
+ val showingSpinner = entry.sbn.notification.extras
+ .getBoolean(Notification.EXTRA_SHOW_REMOTE_INPUT_SPINNER, false)
+ if (showingSpinner) {
+ return false
+ }
+ // If we are keeping the notification around while sending we don't want to add the buttons.
+ return !entry.sbn.notification.extras
+ .getBoolean(Notification.EXTRA_HIDE_SMART_REPLIES, false)
+}
+
+/** Determines if two [SmartRepliesAndActions] are visually similar. */
+fun areSuggestionsSimilar(
+ left: SmartRepliesAndActions?,
+ right: SmartRepliesAndActions?
+): Boolean = when {
+ left === right -> true
+ left == null || right == null -> false
+ left.getSmartReplies() != right.getSmartReplies() -> false
+ else -> !NotificationUiAdjustment.areDifferent(left.getSmartActions(), right.getSmartActions())
+}
+
+interface SmartRepliesAndActionsInflater {
+ fun inflateSmartReplies(
+ sysuiContext: Context,
+ notifPackageContext: Context,
+ entry: NotificationEntry,
+ existingRepliesAndAction: SmartRepliesAndActions
+ ): InflatedSmartReplies
+}
+
+/*internal*/ class SmartRepliesAndActionsInflaterImpl @Inject constructor(
+ private val constants: SmartReplyConstants,
+ private val activityManagerWrapper: ActivityManagerWrapper,
+ private val packageManagerWrapper: PackageManagerWrapper,
+ private val devicePolicyManagerWrapper: DevicePolicyManagerWrapper,
+ private val smartRepliesInflater: SmartReplyInflater,
+ private val smartActionsInflater: SmartActionInflater
+) : SmartRepliesAndActionsInflater {
+
+ override fun inflateSmartReplies(
+ sysuiContext: Context,
+ notifPackageContext: Context,
+ entry: NotificationEntry,
+ existingRepliesAndAction: SmartRepliesAndActions
+ ): InflatedSmartReplies {
+ val newRepliesAndActions = chooseSmartRepliesAndActions(entry)
+ if (!shouldShowSmartReplyView(entry, newRepliesAndActions)) {
+ return InflatedSmartReplies(
+ null /* smartReplyView */,
+ null /* smartSuggestionButtons */,
+ newRepliesAndActions)
+ }
+
+ // Only block clicks if the smart buttons are different from the previous set - to avoid
+ // scenarios where a user incorrectly cannot click smart buttons because the
+ // notification is updated.
+ val delayOnClickListener =
+ !areSuggestionsSimilar(existingRepliesAndAction, newRepliesAndActions)
+
+ val smartReplyView = SmartReplyView.inflate(sysuiContext, constants)
+
+ val smartReplies = newRepliesAndActions.smartReplies
+ smartReplyView.setSmartRepliesGeneratedByAssistant(smartReplies?.fromAssistant ?: false)
+ val smartReplyButtons = smartReplies?.let {
+ smartReplies.choices.asSequence().mapIndexed { index, choice ->
+ smartRepliesInflater.inflateReplyButton(
+ smartReplyView,
+ entry,
+ smartReplies,
+ index,
+ choice,
+ delayOnClickListener)
+ }
+ } ?: emptySequence()
+
+ val smartActionButtons = newRepliesAndActions.smartActions?.let { smartActions ->
+ val themedPackageContext =
+ ContextThemeWrapper(notifPackageContext, sysuiContext.theme)
+ smartActions.actions.asSequence()
+ .filter { it.actionIntent != null }
+ .mapIndexed { index, action ->
+ smartActionsInflater.inflateActionButton(
+ smartReplyView,
+ entry,
+ smartActions,
+ index,
+ action,
+ delayOnClickListener,
+ themedPackageContext)
+ }
+ } ?: emptySequence()
+
+ return InflatedSmartReplies(
+ smartReplyView,
+ (smartReplyButtons + smartActionButtons).toList(),
+ newRepliesAndActions)
+ }
+
+ /**
+ * Chose what smart replies and smart actions to display. App generated suggestions take
+ * precedence. So if the app provides any smart replies, we don't show any
+ * replies or actions generated by the NotificationAssistantService (NAS), and if the app
+ * provides any smart actions we also don't show any NAS-generated replies or actions.
+ */
+ fun chooseSmartRepliesAndActions(entry: NotificationEntry): SmartRepliesAndActions {
+ val notification = entry.sbn.notification
+ val remoteInputActionPair = notification.findRemoteInputActionPair(false /* freeform */)
+ val freeformRemoteInputActionPair =
+ notification.findRemoteInputActionPair(true /* freeform */)
+ if (!constants.isEnabled) {
+ if (DEBUG) {
+ Log.d(TAG, "Smart suggestions not enabled, not adding suggestions for "
+ + entry.sbn.key)
+ }
+ return SmartRepliesAndActions(null, null)
+ }
+ // Only use smart replies from the app if they target P or above. We have this check because
+ // the smart reply API has been used for other things (Wearables) in the past. The API to
+ // add smart actions is new in Q so it doesn't require a target-sdk check.
+ val enableAppGeneratedSmartReplies = (!constants.requiresTargetingP()
+ || entry.targetSdk >= Build.VERSION_CODES.P)
+ val appGeneratedSmartActions = notification.contextualActions
+
+ var smartReplies: SmartReplies? = when {
+ enableAppGeneratedSmartReplies -> remoteInputActionPair?.let { pair ->
+ pair.second.actionIntent?.let { actionIntent ->
+ if (pair.first.choices?.isNotEmpty() == true)
+ SmartReplies(
+ pair.first.choices.asList(),
+ pair.first,
+ actionIntent,
+ false /* fromAssistant */)
+ else null
+ }
+ }
+ else -> null
+ }
+ var smartActions: SmartActions? = when {
+ appGeneratedSmartActions.isNotEmpty() ->
+ SmartActions(appGeneratedSmartActions, false /* fromAssistant */)
+ else -> null
+ }
+ // Apps didn't provide any smart replies / actions, use those from NAS (if any).
+ if (smartReplies == null && smartActions == null) {
+ if (entry.smartReplies.isNotEmpty()
+ && freeformRemoteInputActionPair != null
+ && freeformRemoteInputActionPair.second.allowGeneratedReplies
+ && freeformRemoteInputActionPair.second.actionIntent != null) {
+ smartReplies = SmartReplies(
+ entry.smartReplies,
+ freeformRemoteInputActionPair.first,
+ freeformRemoteInputActionPair.second.actionIntent,
+ true /* fromAssistant */)
+ }
+ if (entry.smartActions.isNotEmpty()
+ && notification.allowSystemGeneratedContextualActions) {
+ val systemGeneratedActions: List<Notification.Action> = when {
+ activityManagerWrapper.isLockTaskKioskModeActive ->
+ // Filter actions if we're in kiosk-mode - we don't care about screen
+ // pinning mode, since notifications aren't shown there anyway.
+ filterAllowlistedLockTaskApps(entry.smartActions)
+ else -> entry.smartActions
+ }
+ smartActions = SmartActions(systemGeneratedActions, true /* fromAssistant */)
+ }
+ }
+ return SmartRepliesAndActions(smartReplies, smartActions)
+ }
+
+ /**
+ * Filter actions so that only actions pointing to allowlisted apps are permitted.
+ * This filtering is only meaningful when in lock-task mode.
+ */
+ private fun filterAllowlistedLockTaskApps(
+ actions: List<Notification.Action>
+ ): List<Notification.Action> = actions.filter { action ->
+ // Only allow actions that are explicit (implicit intents are not handled in lock-task
+ // mode), and link to allowlisted apps.
+ action.actionIntent?.intent?.let { intent ->
+ packageManagerWrapper.resolveActivity(intent, 0 /* flags */)
+ }?.let { resolveInfo ->
+ devicePolicyManagerWrapper.isLockTaskPermitted(resolveInfo.activityInfo.packageName)
+ } ?: false
+ }
+}
+
+interface SmartActionInflater {
+ fun inflateActionButton(
+ parent: ViewGroup,
+ entry: NotificationEntry,
+ smartActions: SmartActions,
+ actionIndex: Int,
+ action: Notification.Action,
+ delayOnClickListener: Boolean,
+ packageContext: Context
+ ): Button
+}
+
+/* internal */ class SmartActionInflaterImpl @Inject constructor(
+ private val constants: SmartReplyConstants,
+ private val activityStarter: ActivityStarter,
+ private val smartReplyController: SmartReplyController,
+ private val headsUpManager: HeadsUpManager
+) : SmartActionInflater {
+
+ override fun inflateActionButton(
+ parent: ViewGroup,
+ entry: NotificationEntry,
+ smartActions: SmartActions,
+ actionIndex: Int,
+ action: Notification.Action,
+ delayOnClickListener: Boolean,
+ packageContext: Context
+ ): Button =
+ (LayoutInflater.from(parent.context)
+ .inflate(R.layout.smart_action_button, parent, false) as Button
+ ).apply {
+ text = action.title
+
+ // We received the Icon from the application - so use the Context of the application to
+ // reference icon resources.
+ val iconDrawable = action.getIcon().loadDrawable(packageContext)
+ .apply {
+ val newIconSize: Int = context.resources.getDimensionPixelSize(
+ R.dimen.smart_action_button_icon_size)
+ setBounds(0, 0, newIconSize, newIconSize)
+ }
+ // Add the action icon to the Smart Action button.
+ setCompoundDrawables(iconDrawable, null, null, null)
+
+ val onClickListener = View.OnClickListener {
+ onSmartActionClick(entry, smartActions, actionIndex, action)
+ }
+ setOnClickListener(
+ if (delayOnClickListener)
+ DelayedOnClickListener(onClickListener, constants.onClickInitDelay)
+ else onClickListener)
+
+ // Mark this as an Action button
+ (layoutParams as SmartReplyView.LayoutParams).mButtonType = SmartButtonType.ACTION
+ }
+
+ private fun onSmartActionClick(
+ entry: NotificationEntry,
+ smartActions: SmartActions,
+ actionIndex: Int,
+ action: Notification.Action
+ ) =
+ activityStarter.startPendingIntentDismissingKeyguard(action.actionIntent, entry.row) {
+ smartReplyController
+ .smartActionClicked(entry, actionIndex, action, smartActions.fromAssistant)
+ headsUpManager.removeNotification(entry.key, true /* releaseImmediately */)
+ }
+}
+
+interface SmartReplyInflater {
+ fun inflateReplyButton(
+ parent: SmartReplyView,
+ entry: NotificationEntry,
+ smartReplies: SmartReplies,
+ replyIndex: Int,
+ choice: CharSequence,
+ delayOnClickListener: Boolean
+ ): Button
+}
+
+class SmartReplyInflaterImpl @Inject constructor(
+ private val constants: SmartReplyConstants,
+ private val keyguardDismissUtil: KeyguardDismissUtil,
+ private val remoteInputManager: NotificationRemoteInputManager,
+ private val smartReplyController: SmartReplyController,
+ private val context: Context
+) : SmartReplyInflater {
+
+ override fun inflateReplyButton(
+ parent: SmartReplyView,
+ entry: NotificationEntry,
+ smartReplies: SmartReplies,
+ replyIndex: Int,
+ choice: CharSequence,
+ delayOnClickListener: Boolean
+ ): Button =
+ (LayoutInflater.from(parent.context)
+ .inflate(R.layout.smart_reply_button, parent, false) as Button
+ ).apply {
+ text = choice
+ val onClickListener = View.OnClickListener {
+ onSmartReplyClick(
+ entry,
+ smartReplies,
+ replyIndex,
+ parent,
+ this,
+ choice)
+ }
+ setOnClickListener(
+ if (delayOnClickListener)
+ DelayedOnClickListener(onClickListener, constants.onClickInitDelay)
+ else onClickListener)
+ accessibilityDelegate = object : View.AccessibilityDelegate() {
+ override fun onInitializeAccessibilityNodeInfo(
+ host: View,
+ info: AccessibilityNodeInfo
+ ) {
+ super.onInitializeAccessibilityNodeInfo(host, info)
+ val label = parent.resources
+ .getString(R.string.accessibility_send_smart_reply)
+ val action = AccessibilityAction(AccessibilityNodeInfo.ACTION_CLICK, label)
+ info.addAction(action)
+ }
+ }
+ // TODO: probably shouldn't do this here, bad API
+ // Mark this as a Reply button
+ (layoutParams as SmartReplyView.LayoutParams).mButtonType = SmartButtonType.REPLY
+ }
+
+ private fun onSmartReplyClick(
+ entry: NotificationEntry,
+ smartReplies: SmartReplies,
+ replyIndex: Int,
+ smartReplyView: SmartReplyView,
+ button: Button,
+ choice: CharSequence
+ ) = keyguardDismissUtil.executeWhenUnlocked(!entry.isRowPinned) {
+ val canEditBeforeSend = constants.getEffectiveEditChoicesBeforeSending(
+ smartReplies.remoteInput.editChoicesBeforeSending)
+ if (canEditBeforeSend) {
+ remoteInputManager.activateRemoteInput(
+ button,
+ arrayOf(smartReplies.remoteInput),
+ smartReplies.remoteInput,
+ smartReplies.pendingIntent,
+ NotificationEntry.EditedSuggestionInfo(choice, replyIndex))
+ } else {
+ smartReplyController.smartReplySent(
+ entry,
+ replyIndex,
+ button.text,
+ NotificationLogger.getNotificationLocation(entry).toMetricsEventEnum(),
+ false /* modifiedBeforeSending */)
+ entry.setHasSentReply()
+ try {
+ val intent = createRemoteInputIntent(smartReplies, choice)
+ smartReplies.pendingIntent.send(context, 0, intent)
+ } catch (e: PendingIntent.CanceledException) {
+ Log.w(TAG, "Unable to send smart reply", e)
+ }
+ smartReplyView.hideSmartSuggestions()
+ }
+ false // do not defer
+ }
+
+ private fun createRemoteInputIntent(smartReplies: SmartReplies, choice: CharSequence): Intent {
+ val results = Bundle()
+ results.putString(smartReplies.remoteInput.resultKey, choice.toString())
+ val intent = Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+ RemoteInput.addResultsToIntent(arrayOf(smartReplies.remoteInput), intent, results)
+ RemoteInput.setResultsSource(intent, RemoteInput.SOURCE_CHOICE)
+ return intent
+ }
+}
+
+/**
+ * An OnClickListener wrapper that blocks the underlying OnClickListener for a given amount of
+ * time.
+ */
+private class DelayedOnClickListener(
+ private val mActualListener: View.OnClickListener,
+ private val mInitDelayMs: Long
+) : View.OnClickListener {
+
+ private val mInitTimeMs = SystemClock.elapsedRealtime()
+
+ override fun onClick(v: View) {
+ if (hasFinishedInitialization()) {
+ mActualListener.onClick(v)
+ } else {
+ Log.i(TAG, "Accidental Smart Suggestion click registered, delay: $mInitDelayMs")
+ }
+ }
+
+ private fun hasFinishedInitialization(): Boolean =
+ SystemClock.elapsedRealtime() >= mInitTimeMs + mInitDelayMs
+}
+
+private const val TAG = "SmartReplyViewInflater"
+private val DEBUG = Log.isLoggable(TAG, Log.DEBUG)
+
+// convenience function that swaps parameter order so that lambda can be placed at the end
+private fun KeyguardDismissUtil.executeWhenUnlocked(
+ requiresShadeOpen: Boolean,
+ onDismissAction: () -> Boolean
+) = executeWhenUnlocked(onDismissAction, requiresShadeOpen)
+
+// convenience function that swaps parameter order so that lambda can be placed at the end
+private fun ActivityStarter.startPendingIntentDismissingKeyguard(
+ intent: PendingIntent,
+ associatedView: View?,
+ runnable: () -> Unit
+) = startPendingIntentDismissingKeyguard(intent, runnable::invoke, associatedView) \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 949ac4df88ba..e7f84a55eb5f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -6,7 +6,6 @@ import android.app.Notification;
import android.app.PendingIntent;
import android.app.RemoteInput;
import android.content.Context;
-import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Canvas;
@@ -15,34 +14,20 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.InsetDrawable;
import android.graphics.drawable.RippleDrawable;
-import android.os.Bundle;
-import android.os.SystemClock;
import android.text.Layout;
import android.text.TextPaint;
import android.text.method.TransformationMethod;
import android.util.AttributeSet;
import android.util.Log;
-import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import android.widget.Button;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ContrastColorUtil;
-import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.notification.NotificationUtils;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry.EditedSuggestionInfo;
-import com.android.systemui.statusbar.notification.logging.NotificationLogger;
-import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import java.text.BreakIterator;
import java.util.ArrayList;
@@ -64,10 +49,6 @@ public class SmartReplyView extends ViewGroup {
private static final int SQUEEZE_FAILED = -1;
- private final SmartReplyConstants mConstants;
- private final KeyguardDismissUtil mKeyguardDismissUtil;
- private final NotificationRemoteInputManager mRemoteInputManager;
-
/**
* The upper bound for the height of this view in pixels. Notifications are automatically
* recreated on density or font size changes so caching this should be fine.
@@ -98,30 +79,25 @@ public class SmartReplyView extends ViewGroup {
*/
private boolean mSmartRepliesGeneratedByAssistant = false;
- @ColorInt
- private int mCurrentBackgroundColor;
- @ColorInt
- private final int mDefaultBackgroundColor;
- @ColorInt
- private final int mDefaultStrokeColor;
- @ColorInt
- private final int mDefaultTextColor;
- @ColorInt
- private final int mDefaultTextColorDarkBg;
- @ColorInt
- private final int mRippleColorDarkBg;
- @ColorInt
- private final int mRippleColor;
+ @ColorInt private int mCurrentBackgroundColor;
+ @ColorInt private final int mDefaultBackgroundColor;
+ @ColorInt private final int mDefaultStrokeColor;
+ @ColorInt private final int mDefaultTextColor;
+ @ColorInt private final int mDefaultTextColorDarkBg;
+ @ColorInt private final int mRippleColorDarkBg;
+ @ColorInt private final int mRippleColor;
private final int mStrokeWidth;
private final double mMinStrokeContrast;
- private ActivityStarter mActivityStarter;
+ @ColorInt private int mCurrentStrokeColor;
+ @ColorInt private int mCurrentTextColor;
+ @ColorInt private int mCurrentRippleColor;
+ private int mMaxSqueezeRemeasureAttempts;
+ private int mMaxNumActions;
+ private int mMinNumSystemGeneratedReplies;
public SmartReplyView(Context context, AttributeSet attrs) {
super(context, attrs);
- mConstants = Dependency.get(SmartReplyConstants.class);
- mKeyguardDismissUtil = Dependency.get(KeyguardDismissUtil.class);
- mRemoteInputManager = Dependency.get(NotificationRemoteInputManager.class);
mHeightUpperLimit = NotificationUtils.getFontScaledHeight(mContext,
R.dimen.smart_reply_button_max_height);
@@ -172,6 +148,18 @@ public class SmartReplyView extends ViewGroup {
}
/**
+ * Inflate an instance of this class.
+ */
+ public static SmartReplyView inflate(Context context, SmartReplyConstants constants) {
+ SmartReplyView view = (SmartReplyView) LayoutInflater.from(context).inflate(
+ R.layout.smart_reply_view, null /* root */);
+ view.setMaxNumActions(constants.getMaxNumActions());
+ view.setMaxSqueezeRemeasureAttempts(constants.getMaxSqueezeRemeasureAttempts());
+ view.setMinNumSystemGeneratedReplies(constants.getMinNumSystemGeneratedReplies());
+ return view;
+ }
+
+ /**
* Returns an upper bound for the height of this view in pixels. This method is intended to be
* invoked before onMeasure, so it doesn't do any analysis on the contents of the buttons.
*/
@@ -197,174 +185,25 @@ public class SmartReplyView extends ViewGroup {
mCurrentBackgroundColor = mDefaultBackgroundColor;
}
- /**
- * Add buttons to the {@link SmartReplyView} - these buttons must have been preinflated using
- * one of the methods in this class.
- */
+ /** Add buttons to the {@link SmartReplyView} */
public void addPreInflatedButtons(List<Button> smartSuggestionButtons) {
for (Button button : smartSuggestionButtons) {
addView(button);
+ setButtonColors(button);
}
reallocateCandidateButtonQueueForSqueezing();
}
- /**
- * Add smart replies to this view, using the provided {@link RemoteInput} and
- * {@link PendingIntent} to respond when the user taps a smart reply. Only the replies that fit
- * into the notification are shown.
- */
- public List<Button> inflateRepliesFromRemoteInput(
- @NonNull SmartReplies smartReplies,
- SmartReplyController smartReplyController, NotificationEntry entry,
- boolean delayOnClickListener) {
- List<Button> buttons = new ArrayList<>();
-
- if (smartReplies.remoteInput != null && smartReplies.pendingIntent != null) {
- if (smartReplies.choices != null) {
- for (int i = 0; i < smartReplies.choices.size(); ++i) {
- buttons.add(inflateReplyButton(
- this, getContext(), i, smartReplies, smartReplyController, entry,
- delayOnClickListener));
- }
- this.mSmartRepliesGeneratedByAssistant = smartReplies.fromAssistant;
- }
- }
- return buttons;
- }
-
- /**
- * Add smart actions to be shown next to smart replies. Only the actions that fit into the
- * notification are shown.
- */
- public List<Button> inflateSmartActions(Context packageContext,
- @NonNull SmartActions smartActions, SmartReplyController smartReplyController,
- NotificationEntry entry, HeadsUpManager headsUpManager, boolean delayOnClickListener) {
- Context themedPackageContext = new ContextThemeWrapper(packageContext, mContext.getTheme());
- List<Button> buttons = new ArrayList<>();
- int numSmartActions = smartActions.actions.size();
- for (int n = 0; n < numSmartActions; n++) {
- Notification.Action action = smartActions.actions.get(n);
- if (action.actionIntent != null) {
- buttons.add(inflateActionButton(
- this, getContext(), themedPackageContext, n, smartActions,
- smartReplyController,
- entry, headsUpManager, delayOnClickListener));
- }
- }
- return buttons;
- }
-
- /**
- * Inflate an instance of this class.
- */
- public static SmartReplyView inflate(Context context) {
- return (SmartReplyView) LayoutInflater.from(context).inflate(
- R.layout.smart_reply_view, null /* root */);
+ public void setMaxNumActions(int maxNumActions) {
+ mMaxNumActions = maxNumActions;
}
- @VisibleForTesting
- static Button inflateReplyButton(SmartReplyView smartReplyView, Context context,
- int replyIndex, SmartReplies smartReplies, SmartReplyController smartReplyController,
- NotificationEntry entry, boolean useDelayedOnClickListener) {
- Button b = (Button) LayoutInflater.from(context).inflate(
- R.layout.smart_reply_button, smartReplyView, false);
- CharSequence choice = smartReplies.choices.get(replyIndex);
- b.setText(choice);
-
- OnDismissAction action = () -> {
- if (smartReplyView.mConstants.getEffectiveEditChoicesBeforeSending(
- smartReplies.remoteInput.getEditChoicesBeforeSending())) {
- EditedSuggestionInfo editedSuggestionInfo =
- new EditedSuggestionInfo(choice, replyIndex);
- smartReplyView.mRemoteInputManager.activateRemoteInput(b,
- new RemoteInput[] { smartReplies.remoteInput }, smartReplies.remoteInput,
- smartReplies.pendingIntent, editedSuggestionInfo);
- return false;
- }
-
- smartReplyController.smartReplySent(entry, replyIndex, b.getText(),
- NotificationLogger.getNotificationLocation(entry).toMetricsEventEnum(),
- false /* modifiedBeforeSending */);
- Bundle results = new Bundle();
- results.putString(smartReplies.remoteInput.getResultKey(), choice.toString());
- Intent intent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- RemoteInput.addResultsToIntent(new RemoteInput[] { smartReplies.remoteInput }, intent,
- results);
- RemoteInput.setResultsSource(intent, RemoteInput.SOURCE_CHOICE);
- entry.setHasSentReply();
- try {
- smartReplies.pendingIntent.send(context, 0, intent);
- } catch (PendingIntent.CanceledException e) {
- Log.w(TAG, "Unable to send smart reply", e);
- }
- // Note that as inflateReplyButton is called mSmartReplyContainer is null, but when the
- // reply Button is added to the SmartReplyView mSmartReplyContainer will be set. So, it
- // will not be possible for a user to trigger this on-click-listener without
- // mSmartReplyContainer being set.
- smartReplyView.mSmartReplyContainer.setVisibility(View.GONE);
- return false; // do not defer
- };
-
- OnClickListener onClickListener = view ->
- smartReplyView.mKeyguardDismissUtil.executeWhenUnlocked(action, !entry.isRowPinned());
- if (useDelayedOnClickListener) {
- onClickListener = new DelayedOnClickListener(onClickListener,
- smartReplyView.mConstants.getOnClickInitDelay());
- }
- b.setOnClickListener(onClickListener);
-
- b.setAccessibilityDelegate(new AccessibilityDelegate() {
- public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(host, info);
- String label = smartReplyView.getResources().getString(
- R.string.accessibility_send_smart_reply);
- info.addAction(new AccessibilityAction(AccessibilityNodeInfo.ACTION_CLICK, label));
- }
- });
-
- SmartReplyView.setButtonColors(b, smartReplyView.mCurrentBackgroundColor,
- smartReplyView.mDefaultStrokeColor, smartReplyView.mDefaultTextColor,
- smartReplyView.mRippleColor, smartReplyView.mStrokeWidth);
- return b;
+ public void setMinNumSystemGeneratedReplies(int minNumSystemGeneratedReplies) {
+ mMinNumSystemGeneratedReplies = minNumSystemGeneratedReplies;
}
- @VisibleForTesting
- static Button inflateActionButton(SmartReplyView smartReplyView, Context context,
- Context packageContext, int actionIndex, SmartActions smartActions,
- SmartReplyController smartReplyController, NotificationEntry entry,
- HeadsUpManager headsUpManager, boolean useDelayedOnClickListener) {
- Notification.Action action = smartActions.actions.get(actionIndex);
- Button button = (Button) LayoutInflater.from(context).inflate(
- R.layout.smart_action_button, smartReplyView, false);
- button.setText(action.title);
-
- // We received the Icon from the application - so use the Context of the application to
- // reference icon resources.
- Drawable iconDrawable = action.getIcon().loadDrawable(packageContext);
- // Add the action icon to the Smart Action button.
- int newIconSize = context.getResources().getDimensionPixelSize(
- R.dimen.smart_action_button_icon_size);
- iconDrawable.setBounds(0, 0, newIconSize, newIconSize);
- button.setCompoundDrawables(iconDrawable, null, null, null);
-
- OnClickListener onClickListener = view ->
- smartReplyView.getActivityStarter().startPendingIntentDismissingKeyguard(
- action.actionIntent,
- () -> {
- smartReplyController.smartActionClicked(
- entry, actionIndex, action, smartActions.fromAssistant);
- headsUpManager.removeNotification(entry.getKey(), true);
- }, entry.getRow());
- if (useDelayedOnClickListener) {
- onClickListener = new DelayedOnClickListener(onClickListener,
- smartReplyView.mConstants.getOnClickInitDelay());
- }
- button.setOnClickListener(onClickListener);
-
- // Mark this as an Action button
- final LayoutParams lp = (LayoutParams) button.getLayoutParams();
- lp.buttonType = SmartButtonType.ACTION;
- return button;
+ public void setMaxSqueezeRemeasureAttempts(int maxSqueezeRemeasureAttempts) {
+ mMaxSqueezeRemeasureAttempts = maxSqueezeRemeasureAttempts;
}
@Override
@@ -416,13 +255,13 @@ public class SmartReplyView extends ViewGroup {
// reply button is added.
SmartSuggestionMeasures actionsMeasures = null;
- final int maxNumActions = mConstants.getMaxNumActions();
+ final int maxNumActions = mMaxNumActions;
int numShownActions = 0;
for (View child : smartSuggestions) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (maxNumActions != -1 // -1 means 'no limit'
- && lp.buttonType == SmartButtonType.ACTION
+ && lp.mButtonType == SmartButtonType.ACTION
&& numShownActions >= maxNumActions) {
// We've reached the maximum number of actions, don't add another one!
continue;
@@ -446,7 +285,7 @@ public class SmartReplyView extends ViewGroup {
// Remember the current measurements in case the current button doesn't fit in.
SmartSuggestionMeasures originalMeasures = accumulatedMeasures.clone();
- if (actionsMeasures == null && lp.buttonType == SmartButtonType.REPLY) {
+ if (actionsMeasures == null && lp.mButtonType == SmartButtonType.REPLY) {
// We've added all actions (we go through actions first), now add their
// measurements.
actionsMeasures = accumulatedMeasures.clone();
@@ -510,7 +349,7 @@ public class SmartReplyView extends ViewGroup {
lp.show = true;
displayedChildCount++;
- if (lp.buttonType == SmartButtonType.ACTION) {
+ if (lp.mButtonType == SmartButtonType.ACTION) {
numShownActions++;
}
}
@@ -551,6 +390,19 @@ public class SmartReplyView extends ViewGroup {
resolveSize(buttonHeight, heightMeasureSpec));
}
+ // TODO: this should be replaced, and instead, setMinSystemGenerated... should be invoked
+ // with MAX_VALUE if mSmartRepliesGeneratedByAssistant would be false (essentially, this is a
+ // ViewModel decision, as opposed to a View decision)
+ void setSmartRepliesGeneratedByAssistant(boolean fromAssistant) {
+ mSmartRepliesGeneratedByAssistant = fromAssistant;
+ }
+
+ void hideSmartSuggestions() {
+ if (mSmartReplyContainer != null) {
+ mSmartReplyContainer.setVisibility(View.GONE);
+ }
+ }
+
/**
* Fields we keep track of inside onMeasure() to correctly measure the SmartReplyView depending
* on which suggestions are added.
@@ -577,6 +429,7 @@ public class SmartReplyView extends ViewGroup {
* Returns whether our notification contains at least N smart replies (or 0) where N is
* determined by {@link SmartReplyConstants}.
*/
+ // TODO: we probably sholdn't make this deliberation in the View
private boolean gotEnoughSmartReplies(List<View> smartReplies) {
int numShownReplies = 0;
for (View smartReplyButton : smartReplies) {
@@ -585,8 +438,7 @@ public class SmartReplyView extends ViewGroup {
numShownReplies++;
}
}
- if (numShownReplies == 0
- || numShownReplies >= mConstants.getMinNumSystemGeneratedReplies()) {
+ if (numShownReplies == 0 || numShownReplies >= mMinNumSystemGeneratedReplies) {
// We have enough replies, yay!
return true;
}
@@ -602,7 +454,7 @@ public class SmartReplyView extends ViewGroup {
if (child.getVisibility() != View.VISIBLE || !(child instanceof Button)) {
continue;
}
- if (lp.buttonType == buttonType) {
+ if (lp.mButtonType == buttonType) {
actions.add(child);
}
}
@@ -656,7 +508,7 @@ public class SmartReplyView extends ViewGroup {
// See if there's a better line-break point (leading to a more narrow button) in
// either left or right direction.
final boolean moveLeft = initialLeftTextWidth > initialRightTextWidth;
- final int maxSqueezeRemeasureAttempts = mConstants.getMaxSqueezeRemeasureAttempts();
+ final int maxSqueezeRemeasureAttempts = mMaxSqueezeRemeasureAttempts;
for (int i = 0; i < maxSqueezeRemeasureAttempts; i++) {
final int newPosition =
moveLeft ? mBreakIterator.previous() : mBreakIterator.next();
@@ -833,41 +685,38 @@ public class SmartReplyView extends ViewGroup {
final boolean dark = !ContrastColorUtil.isColorLight(backgroundColor);
- int textColor = ContrastColorUtil.ensureTextContrast(
+ mCurrentTextColor = ContrastColorUtil.ensureTextContrast(
dark ? mDefaultTextColorDarkBg : mDefaultTextColor,
backgroundColor | 0xff000000, dark);
- int strokeColor = ContrastColorUtil.ensureContrast(
+ mCurrentStrokeColor = ContrastColorUtil.ensureContrast(
mDefaultStrokeColor, backgroundColor | 0xff000000, dark, mMinStrokeContrast);
- int rippleColor = dark ? mRippleColorDarkBg : mRippleColor;
+ mCurrentRippleColor = dark ? mRippleColorDarkBg : mRippleColor;
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
- final Button child = (Button) getChildAt(i);
- setButtonColors(child, backgroundColor, strokeColor, textColor, rippleColor,
- mStrokeWidth);
+ setButtonColors((Button) getChildAt(i));
}
}
- private static void setButtonColors(Button button, int backgroundColor, int strokeColor,
- int textColor, int rippleColor, int strokeWidth) {
+ private void setButtonColors(Button button) {
Drawable drawable = button.getBackground();
if (drawable instanceof RippleDrawable) {
// Mutate in case other notifications are using this drawable.
drawable = drawable.mutate();
RippleDrawable ripple = (RippleDrawable) drawable;
- ripple.setColor(ColorStateList.valueOf(rippleColor));
+ ripple.setColor(ColorStateList.valueOf(mCurrentRippleColor));
Drawable inset = ripple.getDrawable(0);
if (inset instanceof InsetDrawable) {
Drawable background = ((InsetDrawable) inset).getDrawable();
if (background instanceof GradientDrawable) {
GradientDrawable gradientDrawable = (GradientDrawable) background;
- gradientDrawable.setColor(backgroundColor);
- gradientDrawable.setStroke(strokeWidth, strokeColor);
+ gradientDrawable.setColor(mCurrentBackgroundColor);
+ gradientDrawable.setStroke(mStrokeWidth, mCurrentStrokeColor);
}
}
button.setBackground(drawable);
}
- button.setTextColor(textColor);
+ button.setTextColor(mCurrentTextColor);
}
private void setCornerRadius(Button button, float radius) {
@@ -887,14 +736,7 @@ public class SmartReplyView extends ViewGroup {
}
}
- private ActivityStarter getActivityStarter() {
- if (mActivityStarter == null) {
- mActivityStarter = Dependency.get(ActivityStarter.class);
- }
- return mActivityStarter;
- }
-
- private enum SmartButtonType {
+ enum SmartButtonType {
REPLY,
ACTION
}
@@ -924,7 +766,7 @@ public class SmartReplyView extends ViewGroup {
private boolean show = false;
private int squeezeStatus = SQUEEZE_STATUS_NONE;
- private SmartButtonType buttonType = SmartButtonType.REPLY;
+ SmartButtonType mButtonType = SmartButtonType.REPLY;
private LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
@@ -975,32 +817,4 @@ public class SmartReplyView extends ViewGroup {
this.fromAssistant = fromAssistant;
}
}
-
- /**
- * An OnClickListener wrapper that blocks the underlying OnClickListener for a given amount of
- * time.
- */
- private static class DelayedOnClickListener implements OnClickListener {
- private final OnClickListener mActualListener;
- private final long mInitDelayMs;
- private final long mInitTimeMs;
-
- DelayedOnClickListener(OnClickListener actualOnClickListener, long initDelayMs) {
- mActualListener = actualOnClickListener;
- mInitDelayMs = initDelayMs;
- mInitTimeMs = SystemClock.elapsedRealtime();
- }
-
- public void onClick(View v) {
- if (hasFinishedInitialization()) {
- mActualListener.onClick(v);
- } else {
- Log.i(TAG, "Accidental Smart Suggestion click registered, delay: " + mInitDelayMs);
- }
- }
-
- private boolean hasFinishedInitialization() {
- return SystemClock.elapsedRealtime() >= mInitTimeMs + mInitDelayMs;
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 17fcb1dd6f1a..72e8e38735e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -23,6 +23,7 @@ import static com.android.systemui.DejankUtils.whitelistIpcs;
import android.app.ActivityManager;
import android.app.Dialog;
+import android.app.IActivityTaskManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
@@ -53,7 +54,6 @@ import android.widget.BaseAdapter;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.util.UserIcons;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.systemui.Dumpable;
import com.android.systemui.GuestResumeSessionReceiver;
@@ -69,6 +69,7 @@ import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.qs.QSUserSwitcherEvent;
import com.android.systemui.qs.tiles.UserDetailView;
import com.android.systemui.statusbar.phone.SystemUIDialog;
+import com.android.systemui.user.CreateUserActivity;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -104,6 +105,7 @@ public class UserSwitcherController implements Dumpable {
protected final Handler mHandler;
private final ActivityStarter mActivityStarter;
private final BroadcastDispatcher mBroadcastDispatcher;
+ private final IActivityTaskManager mActivityTaskManager;
private ArrayList<UserRecord> mUsers = new ArrayList<>();
private Dialog mExitGuestDialog;
@@ -121,9 +123,11 @@ public class UserSwitcherController implements Dumpable {
@Inject
public UserSwitcherController(Context context, KeyguardStateController keyguardStateController,
@Main Handler handler, ActivityStarter activityStarter,
- BroadcastDispatcher broadcastDispatcher, UiEventLogger uiEventLogger) {
+ BroadcastDispatcher broadcastDispatcher, UiEventLogger uiEventLogger,
+ IActivityTaskManager activityTaskManager) {
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
+ mActivityTaskManager = activityTaskManager;
mUiEventLogger = uiEventLogger;
if (!UserManager.isGuestUserEphemeral()) {
mGuestResumeSessionReceiver.register(mBroadcastDispatcher);
@@ -363,7 +367,7 @@ public class UserSwitcherController implements Dumpable {
}
}
- public void switchTo(UserRecord record) {
+ private void onUserListItemClicked(UserRecord record) {
int id;
if (record.isGuest && record.info == null) {
// No guest user. Create one.
@@ -408,19 +412,6 @@ public class UserSwitcherController implements Dumpable {
switchToUserId(id);
}
- public void switchTo(int userId) {
- final int count = mUsers.size();
- for (int i = 0; i < count; ++i) {
- UserRecord record = mUsers.get(i);
- if (record.info != null && record.info.id == userId) {
- switchTo(record);
- return;
- }
- }
-
- Log.e(TAG, "Couldn't switch to user, id=" + userId);
- }
-
protected void switchToUserId(int id) {
try {
pauseRefreshUsers();
@@ -666,8 +657,11 @@ public class UserSwitcherController implements Dumpable {
return position;
}
- public void switchTo(UserRecord record) {
- mController.switchTo(record);
+ /**
+ * It handles click events on user list items.
+ */
+ public void onUserListItemClicked(UserRecord record) {
+ mController.onUserListItemClicked(record);
}
public String getName(Context context, UserRecord item) {
@@ -924,18 +918,33 @@ public class UserSwitcherController implements Dumpable {
if (ActivityManager.isUserAMonkey()) {
return;
}
- UserInfo user = mUserManager.createUser(
- mContext.getString(R.string.user_new_user_name), 0 /* flags */);
- if (user == null) {
- // Couldn't create user, most likely because there are too many, but we haven't
- // been able to reload the list yet.
- return;
+ Intent intent = CreateUserActivity.createIntentForStart(getContext());
+
+ // There are some differences between ActivityStarter and ActivityTaskManager in
+ // terms of how they start an activity. ActivityStarter hides the notification bar
+ // before starting the activity to make sure nothing is in front of the new
+ // activity. ActivityStarter also tries to unlock the device if it's locked.
+ // When locked with PIN/pattern/password then it shows the prompt, if there are no
+ // security steps then it dismisses the keyguard and then starts the activity.
+ // ActivityTaskManager doesn't hide the notification bar or unlocks the device, but
+ // it can start an activity on top of the locked screen.
+ if (!mKeyguardStateController.isUnlocked()
+ && !mKeyguardStateController.canDismissLockScreen()) {
+ // Device is locked and can't be unlocked without a PIN/pattern/password so we
+ // need to use ActivityTaskManager to start the activity on top of the locked
+ // screen.
+ try {
+ mActivityTaskManager.startActivity(null,
+ mContext.getBasePackageName(), mContext.getAttributionTag(), intent,
+ intent.resolveTypeIfNeeded(mContext.getContentResolver()), null,
+ null, 0, 0, null, null);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ Log.e(TAG, "Couldn't start create user activity", e);
+ }
+ } else {
+ mActivityStarter.startActivity(intent, true);
}
- int id = user.id;
- Bitmap icon = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(
- mContext.getResources(), id, /* light= */ false));
- mUserManager.setUserIcon(id, icon);
- switchToUserId(id);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/SmartRepliesInflationModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/SmartRepliesInflationModule.kt
new file mode 100644
index 000000000000..803d26ec3286
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/dagger/SmartRepliesInflationModule.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.policy.dagger
+
+import com.android.systemui.statusbar.policy.SmartActionInflater
+import com.android.systemui.statusbar.policy.SmartActionInflaterImpl
+import com.android.systemui.statusbar.policy.SmartRepliesAndActionsInflater
+import com.android.systemui.statusbar.policy.SmartRepliesAndActionsInflaterImpl
+import com.android.systemui.statusbar.policy.SmartReplyInflater
+import com.android.systemui.statusbar.policy.SmartReplyInflaterImpl
+import dagger.Binds
+import dagger.Module
+
+@Module
+interface SmartRepliesInflationModule {
+ @Binds fun bindSmartActionsInflater(impl: SmartActionInflaterImpl): SmartActionInflater
+ @Binds fun bindSmartReplyInflater(impl: SmartReplyInflaterImpl): SmartReplyInflater
+ @Binds fun bindsInflatedSmartRepliesProvider(
+ impl: SmartRepliesAndActionsInflaterImpl
+ ): SmartRepliesAndActionsInflater
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
new file mode 100644
index 000000000000..e9fcf1aa9598
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.toast;
+
+import android.animation.Animator;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.view.View;
+import android.widget.ToastPresenter;
+
+import com.android.internal.R;
+import com.android.systemui.plugins.ToastPlugin;
+
+/**
+ * SystemUI TextToast that can be customized by ToastPlugins. Should never instantiate this class
+ * directly. Instead, use {@link ToastFactory#createToast}.
+ */
+public class SystemUIToast implements ToastPlugin.Toast {
+ final Context mContext;
+ final CharSequence mText;
+ final ToastPlugin.Toast mPluginToast;
+
+ final int mDefaultGravity;
+ final int mDefaultY;
+ final int mDefaultX = 0;
+ final int mDefaultHorizontalMargin = 0;
+ final int mDefaultVerticalMargin = 0;
+
+ SystemUIToast(Context context, CharSequence text) {
+ this(context, text, null);
+ }
+
+ SystemUIToast(Context context, CharSequence text, ToastPlugin.Toast pluginToast) {
+ mContext = context;
+ mText = text;
+ mPluginToast = pluginToast;
+
+ mDefaultGravity = context.getResources().getInteger(R.integer.config_toastDefaultGravity);
+ mDefaultY = context.getResources().getDimensionPixelSize(R.dimen.toast_y_offset);
+ }
+
+ @Override
+ @NonNull
+ public Integer getGravity() {
+ if (isPluginToast() && mPluginToast.getGravity() != null) {
+ return mPluginToast.getGravity();
+ }
+ return mDefaultGravity;
+ }
+
+ @Override
+ @NonNull
+ public Integer getXOffset() {
+ if (isPluginToast() && mPluginToast.getXOffset() != null) {
+ return mPluginToast.getXOffset();
+ }
+ return mDefaultX;
+ }
+
+ @Override
+ @NonNull
+ public Integer getYOffset() {
+ if (isPluginToast() && mPluginToast.getYOffset() != null) {
+ return mPluginToast.getYOffset();
+ }
+ return mDefaultY;
+ }
+
+ @Override
+ @NonNull
+ public Integer getHorizontalMargin() {
+ if (isPluginToast() && mPluginToast.getHorizontalMargin() != null) {
+ return mPluginToast.getHorizontalMargin();
+ }
+ return mDefaultHorizontalMargin;
+ }
+
+ @Override
+ @NonNull
+ public Integer getVerticalMargin() {
+ if (isPluginToast() && mPluginToast.getVerticalMargin() != null) {
+ return mPluginToast.getVerticalMargin();
+ }
+ return mDefaultVerticalMargin;
+ }
+
+ @Override
+ @NonNull
+ public View getView() {
+ if (isPluginToast() && mPluginToast.getView() != null) {
+ return mPluginToast.getView();
+ }
+ return ToastPresenter.getTextToastView(mContext, mText);
+ }
+
+ @Override
+ @Nullable
+ public Animator getInAnimation() {
+ if (isPluginToast() && mPluginToast.getInAnimation() != null) {
+ return mPluginToast.getInAnimation();
+ }
+ return null;
+ }
+
+ @Override
+ @Nullable
+ public Animator getOutAnimation() {
+ if (isPluginToast() && mPluginToast.getOutAnimation() != null) {
+ return mPluginToast.getOutAnimation();
+ }
+ return null;
+ }
+
+ /**
+ * Whether this toast has a custom animation.
+ */
+ public boolean hasCustomAnimation() {
+ return getInAnimation() != null || getOutAnimation() != null;
+ }
+
+ private boolean isPluginToast() {
+ return mPluginToast != null;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java b/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java
new file mode 100644
index 000000000000..d8cb61c6b349
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastFactory.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.toast;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+
+import com.android.systemui.Dumpable;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.plugins.PluginListener;
+import com.android.systemui.plugins.ToastPlugin;
+import com.android.systemui.shared.plugins.PluginManager;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+import javax.inject.Inject;
+
+/**
+ * Factory for creating toasts to be shown by ToastUI.
+ * These toasts can be customized by {@link ToastPlugin}.
+ */
+@SysUISingleton
+public class ToastFactory implements Dumpable {
+ // only one ToastPlugin can be connected at a time.
+ private ToastPlugin mPlugin;
+
+ @Inject
+ public ToastFactory(PluginManager pluginManager, DumpManager dumpManager) {
+ dumpManager.registerDumpable("ToastFactory", this);
+ pluginManager.addPluginListener(
+ new PluginListener<ToastPlugin>() {
+ @Override
+ public void onPluginConnected(ToastPlugin plugin, Context pluginContext) {
+ mPlugin = plugin;
+ }
+
+ @Override
+ public void onPluginDisconnected(ToastPlugin plugin) {
+ if (plugin.equals(mPlugin)) {
+ mPlugin = null;
+ }
+ }
+ }, ToastPlugin.class, false /* Allow multiple plugins */);
+ }
+
+ /**
+ * Create a toast to be shown by ToastUI.
+ */
+ public SystemUIToast createToast(Context context, CharSequence text, String packageName,
+ int userId) {
+ if (isPluginAvailable()) {
+ return new SystemUIToast(context, text, mPlugin.createToast(text, packageName, userId));
+ }
+ return new SystemUIToast(context, text);
+ }
+
+ private boolean isPluginAvailable() {
+ return mPlugin != null;
+ }
+
+ @Override
+ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
+ pw.println("ToastFactory:");
+ pw.println(" mAttachedPlugin=" + mPlugin);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt b/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
new file mode 100644
index 000000000000..78173cf62a93
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.toast
+
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.LogLevel.DEBUG
+import com.android.systemui.log.LogMessage
+import com.android.systemui.log.dagger.ToastLog
+import javax.inject.Inject
+
+private const val TAG = "ToastLog"
+
+class ToastLogger @Inject constructor(
+ @ToastLog private val buffer: LogBuffer
+) {
+
+ fun logOnShowToast(uid: Int, packageName: String, text: String, token: String) {
+ log(DEBUG, {
+ int1 = uid
+ str1 = packageName
+ str2 = text
+ str3 = token
+ }, {
+ "[$str3] Show toast for ($str1, $int1). msg=\'$str2\'"
+ })
+ }
+
+ fun logOnHideToast(packageName: String, token: String) {
+ log(DEBUG, {
+ str1 = packageName
+ str2 = token
+ }, {
+ "[$str2] Hide toast for [$str1]"
+ })
+ }
+
+ private inline fun log(
+ logLevel: LogLevel,
+ initializer: LogMessage.() -> Unit,
+ noinline printer: LogMessage.() -> String
+ ) {
+ buffer.log(TAG, logLevel, initializer, printer)
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
index a2203732c47c..1c682e3bb7dc 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
@@ -16,25 +16,27 @@
package com.android.systemui.toast;
+import android.animation.Animator;
import android.annotation.MainThread;
import android.annotation.Nullable;
import android.app.INotificationManager;
import android.app.ITransientNotificationCallback;
import android.content.Context;
-import android.content.res.Resources;
import android.os.IBinder;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.Log;
-import android.view.View;
+import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
+import android.widget.Toast;
import android.widget.ToastPresenter;
-import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.util.concurrency.DelayableExecutor;
import java.util.Objects;
@@ -45,35 +47,53 @@ import javax.inject.Inject;
*/
@SysUISingleton
public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
+ // values from NotificationManagerService#LONG_DELAY and NotificationManagerService#SHORT_DELAY
+ private static final int TOAST_LONG_TIME = 3500; // 3.5 seconds
+ private static final int TOAST_SHORT_TIME = 2000; // 2 seconds
+
private static final String TAG = "ToastUI";
private final CommandQueue mCommandQueue;
private final INotificationManager mNotificationManager;
- private final IAccessibilityManager mAccessibilityManager;
- private final int mGravity;
- private final int mY;
+ private final IAccessibilityManager mIAccessibilityManager;
+ private final AccessibilityManager mAccessibilityManager;
+ private final ToastFactory mToastFactory;
+ private final DelayableExecutor mMainExecutor;
+ private final ToastLogger mToastLogger;
+ private SystemUIToast mToast;
@Nullable private ToastPresenter mPresenter;
@Nullable private ITransientNotificationCallback mCallback;
@Inject
- public ToastUI(Context context, CommandQueue commandQueue) {
+ public ToastUI(
+ Context context,
+ CommandQueue commandQueue,
+ ToastFactory toastFactory,
+ @Main DelayableExecutor mainExecutor,
+ ToastLogger toastLogger) {
this(context, commandQueue,
INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE)),
IAccessibilityManager.Stub.asInterface(
- ServiceManager.getService(Context.ACCESSIBILITY_SERVICE)));
+ ServiceManager.getService(Context.ACCESSIBILITY_SERVICE)),
+ toastFactory,
+ mainExecutor,
+ toastLogger);
}
@VisibleForTesting
ToastUI(Context context, CommandQueue commandQueue, INotificationManager notificationManager,
- @Nullable IAccessibilityManager accessibilityManager) {
+ @Nullable IAccessibilityManager accessibilityManager,
+ ToastFactory toastFactory, DelayableExecutor mainExecutor, ToastLogger toastLogger
+ ) {
super(context);
mCommandQueue = commandQueue;
mNotificationManager = notificationManager;
- mAccessibilityManager = accessibilityManager;
- Resources resources = mContext.getResources();
- mGravity = resources.getInteger(R.integer.config_toastDefaultGravity);
- mY = resources.getDimensionPixelSize(R.dimen.toast_y_offset);
+ mIAccessibilityManager = accessibilityManager;
+ mToastFactory = toastFactory;
+ mMainExecutor = mainExecutor;
+ mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class);
+ mToastLogger = toastLogger;
}
@Override
@@ -88,12 +108,31 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
if (mPresenter != null) {
hideCurrentToast();
}
- Context context = mContext.createContextAsUser(UserHandle.getUserHandleForUid(uid), 0);
- View view = ToastPresenter.getTextToastView(context, text);
+ UserHandle userHandle = UserHandle.getUserHandleForUid(uid);
+ Context context = mContext.createContextAsUser(userHandle, 0);
+ mToast = mToastFactory.createToast(context, text, packageName, userHandle.getIdentifier());
+
+ if (mToast.hasCustomAnimation()) {
+ if (mToast.getInAnimation() != null) {
+ mToast.getInAnimation().start();
+ }
+ final Animator hideAnimator = mToast.getOutAnimation();
+ if (hideAnimator != null) {
+ final long durationMillis = duration == Toast.LENGTH_LONG
+ ? TOAST_LONG_TIME : TOAST_SHORT_TIME;
+ final long updatedDuration = mAccessibilityManager.getRecommendedTimeoutMillis(
+ (int) durationMillis, AccessibilityManager.FLAG_CONTENT_TEXT);
+ mMainExecutor.executeDelayed(() -> hideAnimator.start(),
+ updatedDuration - hideAnimator.getTotalDuration());
+ }
+ }
mCallback = callback;
- mPresenter = new ToastPresenter(context, mAccessibilityManager, mNotificationManager,
+ mPresenter = new ToastPresenter(context, mIAccessibilityManager, mNotificationManager,
packageName);
- mPresenter.show(view, token, windowToken, duration, mGravity, 0, mY, 0, 0, mCallback);
+ mToastLogger.logOnShowToast(uid, packageName, text.toString(), token.toString());
+ mPresenter.show(mToast.getView(), token, windowToken, duration, mToast.getGravity(),
+ mToast.getXOffset(), mToast.getYOffset(), mToast.getHorizontalMargin(),
+ mToast.getVerticalMargin(), mCallback, mToast.hasCustomAnimation());
}
@Override
@@ -104,6 +143,7 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
Log.w(TAG, "Attempt to hide non-current toast from package " + packageName);
return;
}
+ mToastLogger.logOnHideToast(packageName, token.toString());
hideCurrentToast();
}
diff --git a/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java b/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java
new file mode 100644
index 000000000000..890ee5f45309
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/CreateUserActivity.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.user;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.IActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.settingslib.users.EditUserInfoController;
+import com.android.systemui.R;
+
+import javax.inject.Inject;
+
+/**
+ * This screen shows a Dialog for choosing nickname and photo for a new user, and then delegates the
+ * user creation to a UserCreator.
+ */
+public class CreateUserActivity extends Activity {
+
+ /**
+ * Creates an intent to start this activity.
+ */
+ public static Intent createIntentForStart(Context context) {
+ return new Intent(context, CreateUserActivity.class);
+ }
+
+ private static final String TAG = "CreateUserActivity";
+ private static final String DIALOG_STATE_KEY = "create_user_dialog_state";
+
+ private final UserCreator mUserCreator;
+ private final EditUserInfoController mEditUserInfoController;
+ private final IActivityManager mActivityManager;
+
+ private Dialog mSetupUserDialog;
+
+ @Inject
+ public CreateUserActivity(UserCreator userCreator,
+ EditUserInfoController editUserInfoController, IActivityManager activityManager) {
+ mUserCreator = userCreator;
+ mEditUserInfoController = editUserInfoController;
+ mActivityManager = activityManager;
+ }
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setShowWhenLocked(true);
+ setContentView(R.layout.activity_create_new_user);
+
+ if (savedInstanceState != null) {
+ mEditUserInfoController.onRestoreInstanceState(savedInstanceState);
+ }
+
+ mSetupUserDialog = createDialog();
+ mSetupUserDialog.show();
+ }
+
+ @Override
+ protected void onSaveInstanceState(@NonNull Bundle outState) {
+ if (mSetupUserDialog != null && mSetupUserDialog.isShowing()) {
+ outState.putBundle(DIALOG_STATE_KEY, mSetupUserDialog.onSaveInstanceState());
+ }
+
+ mEditUserInfoController.onSaveInstanceState(outState);
+ super.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+ Bundle savedDialogState = savedInstanceState.getBundle(DIALOG_STATE_KEY);
+ if (savedDialogState != null && mSetupUserDialog != null) {
+ mSetupUserDialog.onRestoreInstanceState(savedDialogState);
+ }
+ }
+
+ private Dialog createDialog() {
+ String defaultUserName = getString(com.android.settingslib.R.string.user_new_user_name);
+
+ return mEditUserInfoController.createDialog(
+ this,
+ (intent, requestCode) -> {
+ mEditUserInfoController.startingActivityForResult();
+ startActivityForResult(intent, requestCode);
+ },
+ null,
+ defaultUserName,
+ getString(R.string.user_add_user),
+ this::addUserNow,
+ this::finish
+ );
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ mEditUserInfoController.onActivityResult(requestCode, resultCode, data);
+ }
+
+ @Override
+ public void onBackPressed() {
+ super.onBackPressed();
+ if (mSetupUserDialog != null) {
+ mSetupUserDialog.dismiss();
+ }
+ }
+
+ private void addUserNow(String userName, Drawable userIcon) {
+ mSetupUserDialog.dismiss();
+
+ userName = (userName == null || userName.trim().isEmpty())
+ ? getString(R.string.user_new_user_name)
+ : userName;
+
+ mUserCreator.createUser(userName, userIcon,
+ userInfo -> {
+ switchToUser(userInfo.id);
+ finishIfNeeded();
+ }, () -> {
+ Log.e(TAG, "Unable to create user");
+ finishIfNeeded();
+ });
+ }
+
+ private void finishIfNeeded() {
+ if (!isFinishing() && !isDestroyed()) {
+ finish();
+ }
+ }
+
+ private void switchToUser(int userId) {
+ try {
+ mActivityManager.switchUser(userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Couldn't switch user.", e);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserCreator.java b/packages/SystemUI/src/com/android/systemui/user/UserCreator.java
new file mode 100644
index 000000000000..3a270bb77e46
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/UserCreator.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.user;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.graphics.drawable.Drawable;
+import android.os.UserManager;
+
+import com.android.internal.util.UserIcons;
+import com.android.settingslib.users.UserCreatingDialog;
+import com.android.settingslib.utils.ThreadUtils;
+
+import java.util.function.Consumer;
+
+import javax.inject.Inject;
+
+/**
+ * A class to do the user creation process. It shows a progress dialog, and manages the user
+ * creation
+ */
+public class UserCreator {
+
+ private final Context mContext;
+ private final UserManager mUserManager;
+
+ @Inject
+ public UserCreator(Context context, UserManager userManager) {
+ mContext = context;
+ mUserManager = userManager;
+ }
+
+ /**
+ * Shows a progress dialog then starts the user creation process on the main thread.
+ *
+ * @param successCallback is called when the user creation is successful.
+ * @param errorCallback is called when userManager.createUser returns null.
+ * (Exceptions are not handled by this class)
+ */
+ public void createUser(String userName, Drawable userIcon, Consumer<UserInfo> successCallback,
+ Runnable errorCallback) {
+
+ Dialog userCreationProgressDialog = new UserCreatingDialog(mContext);
+ userCreationProgressDialog.show();
+
+ // userManager.createUser will block the thread so post is needed for the dialog to show
+ ThreadUtils.postOnMainThread(() -> {
+ UserInfo user =
+ mUserManager.createUser(userName, UserManager.USER_TYPE_FULL_SECONDARY, 0);
+ if (user == null) {
+ // Couldn't create user for some reason
+ userCreationProgressDialog.dismiss();
+ errorCallback.run();
+ return;
+ }
+
+ Drawable newUserIcon = userIcon;
+ if (newUserIcon == null) {
+ newUserIcon = UserIcons.getDefaultUserIcon(mContext.getResources(), user.id, false);
+ }
+ mUserManager.setUserIcon(user.id, UserIcons.convertToBitmap(newUserIcon));
+
+ userCreationProgressDialog.dismiss();
+ successCallback.accept(user);
+ });
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserModule.java b/packages/SystemUI/src/com/android/systemui/user/UserModule.java
new file mode 100644
index 000000000000..0ad0984e8231
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/UserModule.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.user;
+
+import com.android.settingslib.users.EditUserInfoController;
+
+import dagger.Module;
+import dagger.Provides;
+
+/**
+ * Dagger module for User related classes.
+ */
+@Module
+public class UserModule {
+
+ private static final String FILE_PROVIDER_AUTHORITY = "com.android.systemui.fileprovider";
+
+ @Provides
+ EditUserInfoController provideEditUserInfoController() {
+ return new EditUserInfoController(FILE_PROVIDER_AUTHORITY);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index b82853562049..a948103d3908 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -312,10 +312,6 @@ public final class WMShell extends SystemUI
@VisibleForTesting
void initOneHanded(OneHanded oneHanded) {
- if (!oneHanded.hasOneHandedFeature()) {
- return;
- }
-
int currentMode = mNavigationModeController.addListener(mode ->
oneHanded.setThreeButtonModeEnabled(mode == NAV_BAR_MODE_3BUTTON));
oneHanded.setThreeButtonModeEnabled(currentMode == NAV_BAR_MODE_3BUTTON);
@@ -423,8 +419,8 @@ public final class WMShell extends SystemUI
if (handleLoggingCommand(args, pw)) {
return;
}
-
// Dump WMShell stuff here if no commands were handled
+ mOneHandedOptional.ifPresent(oneHanded -> oneHanded.dump(pw));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index 970d5001172e..09678b5d1772 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -40,6 +40,7 @@ import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.onehanded.OneHanded;
+import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
import com.android.wm.shell.pip.PipUiEventLogger;
@@ -48,6 +49,8 @@ import com.android.wm.shell.pip.phone.PipMediaController;
import com.android.wm.shell.pip.phone.PipTouchHandler;
import com.android.wm.shell.splitscreen.SplitScreen;
+import java.util.Optional;
+
import dagger.BindsOptionalOf;
import dagger.Module;
import dagger.Provides;
@@ -164,6 +167,10 @@ public abstract class WMShellBaseModule {
@BindsOptionalOf
abstract Bubbles optionalBubbles();
- @BindsOptionalOf
- abstract OneHanded optionalOneHanded();
+ @SysUISingleton
+ @Provides
+ static Optional<OneHanded> provideOneHandedController(Context context,
+ DisplayController displayController) {
+ return Optional.ofNullable(OneHandedController.create(context, displayController));
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
index 61c3f9c3616f..ae7b108a2afa 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellModule.java
@@ -30,8 +30,6 @@ import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.SystemWindows;
import com.android.wm.shell.common.TransactionPool;
-import com.android.wm.shell.onehanded.OneHanded;
-import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.pip.Pip;
import com.android.wm.shell.pip.PipBoundsHandler;
import com.android.wm.shell.pip.PipSurfaceTransactionHelper;
@@ -129,11 +127,4 @@ public class WMShellModule {
pipSurfaceTransactionHelper, splitScreenOptional, displayController,
pipUiEventLogger, shellTaskOrganizer);
}
-
- @SysUISingleton
- @Provides
- static OneHanded provideOneHandedController(Context context,
- DisplayController displayController) {
- return OneHandedController.create(context, displayController);
- }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
index 64e067396059..0a51b26f4a85 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
@@ -22,11 +22,14 @@ import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_UP;
+import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK;
import static com.android.systemui.accessibility.MagnificationModeSwitch.getIconResId;
import static junit.framework.Assert.assertEquals;
+import static org.hamcrest.CoreMatchers.hasItems;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyLong;
@@ -45,10 +48,12 @@ import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewPropertyAnimator;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ImageView;
import androidx.test.filters.SmallTest;
+import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
@@ -142,13 +147,7 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
resetMockImageViewAndAnimator();
listener.onTouch(mSpyImageView, MotionEvent.obtain(
0, ViewConfiguration.getTapTimeout(), ACTION_UP, 100, 100, 0));
- verify(mViewPropertyAnimator).cancel();
- verify(mSpyImageView).setImageResource(
- getIconResId(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW));
- verify(mWindowManager).removeView(mSpyImageView);
- final int actualMode = Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
- assertEquals(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW, actualMode);
+ verifyTapAction(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
}
@Test
@@ -222,6 +221,34 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
assertShowButtonAnimation();
}
+ @Test
+ public void initializeA11yNode_showWindowModeButton_expectedValues() {
+ mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
+ final AccessibilityNodeInfo nodeInfo = new AccessibilityNodeInfo();
+
+ mSpyImageView.onInitializeAccessibilityNodeInfo(nodeInfo);
+
+ assertEquals(mContext.getString(R.string.magnification_mode_switch_description),
+ nodeInfo.getContentDescription());
+ assertEquals(mContext.getString(R.string.magnification_mode_switch_state_window),
+ nodeInfo.getStateDescription());
+ assertThat(nodeInfo.getActionList(),
+ hasItems(new AccessibilityNodeInfo.AccessibilityAction(
+ ACTION_CLICK.getId(), mContext.getResources().getString(
+ R.string.magnification_mode_switch_click_label))));
+ }
+
+ @Test
+ public void performA11yActions_showWindowModeButton_verifyTapAction() {
+ mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
+ resetMockImageViewAndAnimator();
+
+ mSpyImageView.performAccessibilityAction(
+ ACTION_CLICK.getId(), null);
+
+ verifyTapAction(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+ }
+
private void assertModeUnchanged(int expectedMode) {
final int actualMode = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
@@ -254,4 +281,19 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
Mockito.reset(mSpyImageView);
initMockImageViewAndAnimator();
}
+
+ /**
+ * Verifies the tap behaviour including the image of the button and the magnification mode.
+ *
+ * @param expectedMode the expected mode after tapping
+ */
+ private void verifyTapAction(int expectedMode) {
+ verify(mViewPropertyAnimator).cancel();
+ verify(mSpyImageView).setImageResource(
+ getIconResId(expectedMode));
+ verify(mWindowManager).removeView(mSpyImageView);
+ final int actualMode = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
+ assertEquals(expectedMode, actualMode);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
index a2f8c1cb0ad3..6b0a23f2b4ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
@@ -54,13 +54,13 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.notification.ConversationNotificationProcessor;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.BindParams;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationCallback;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
-import com.android.systemui.statusbar.policy.SmartReplyConstants;
+import com.android.systemui.statusbar.policy.InflatedSmartReplies;
+import com.android.systemui.statusbar.policy.SmartRepliesAndActionsInflater;
import org.junit.Assert;
import org.junit.Before;
@@ -87,6 +87,11 @@ public class NotificationContentInflaterTest extends SysuiTestCase {
@Mock private NotifRemoteViewCache mCache;
@Mock private ConversationNotificationProcessor mConversationNotificationProcessor;
+ @Mock private InflatedSmartReplies mInflatedSmartReplies;
+
+ private final SmartRepliesAndActionsInflater mSmartRepliesAndActionsInflater =
+ (sysuiContext, notifPackageContext, entry, existingRepliesAndAction) ->
+ mInflatedSmartReplies;
@Before
public void setUp() throws Exception {
@@ -103,16 +108,13 @@ public class NotificationContentInflaterTest extends SysuiTestCase {
ExpandableNotificationRow row = helper.createRow(mBuilder.build());
mRow = spy(row);
- final SmartReplyConstants smartReplyConstants = mock(SmartReplyConstants.class);
- final SmartReplyController smartReplyController = mock(SmartReplyController.class);
mNotificationInflater = new NotificationContentInflater(
mCache,
mock(NotificationRemoteInputManager.class),
- () -> smartReplyConstants,
- () -> smartReplyController,
mConversationNotificationProcessor,
mock(MediaFeatureFlag.class),
- mock(Executor.class));
+ mock(Executor.class),
+ mSmartRepliesAndActionsInflater);
}
@Test
@@ -120,13 +122,15 @@ public class NotificationContentInflaterTest extends SysuiTestCase {
BindParams params = new BindParams();
params.usesIncreasedHeadsUpHeight = true;
Notification.Builder builder = spy(mBuilder);
- mNotificationInflater.inflateNotificationViews(mRow.getEntry(),
+ mNotificationInflater.inflateNotificationViews(
+ mRow.getEntry(),
mRow,
params,
true /* inflateSynchronously */,
FLAG_CONTENT_VIEW_ALL,
builder,
- mContext);
+ mContext,
+ mSmartRepliesAndActionsInflater);
verify(builder).createHeadsUpContentView(true);
}
@@ -135,13 +139,15 @@ public class NotificationContentInflaterTest extends SysuiTestCase {
BindParams params = new BindParams();
params.usesIncreasedHeight = true;
Notification.Builder builder = spy(mBuilder);
- mNotificationInflater.inflateNotificationViews(mRow.getEntry(),
+ mNotificationInflater.inflateNotificationViews(
+ mRow.getEntry(),
mRow,
params,
true /* inflateSynchronously */,
FLAG_CONTENT_VIEW_ALL,
builder,
- mContext);
+ mContext,
+ mSmartRepliesAndActionsInflater);
verify(builder).createContentView(true);
}
@@ -366,7 +372,7 @@ public class NotificationContentInflaterTest extends SysuiTestCase {
}
}
- private class AsyncFailRemoteView extends RemoteViews {
+ private static class AsyncFailRemoteView extends RemoteViews {
Handler mHandler = Handler.createAsync(Looper.getMainLooper());
public AsyncFailRemoteView(String packageName, int layoutId) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index aff8ade6f1ae..1255b6de6608 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -79,7 +79,7 @@ import com.android.systemui.statusbar.notification.row.dagger.NotificationRowCom
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.SmartReplyConstants;
+import com.android.systemui.statusbar.policy.InflatedSmartReplies;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.leak.LeakDetector;
import com.android.systemui.util.time.FakeSystemClock;
@@ -138,6 +138,7 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
@Mock private ActivatableNotificationViewController mActivatableNotificationViewController;
@Mock private NotificationRowComponent.Builder mNotificationRowComponentBuilder;
@Mock private PeopleNotificationIdentifier mPeopleNotificationIdentifier;
+ @Mock private InflatedSmartReplies mInflatedSmartReplies;
private StatusBarNotification mSbn;
private NotificationListenerService.RankingMap mRankingMap;
@@ -199,11 +200,11 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase {
NotificationContentInflater binder = new NotificationContentInflater(
cache,
mRemoteInputManager,
- () -> mock(SmartReplyConstants.class),
- () -> mock(SmartReplyController.class),
mock(ConversationNotificationProcessor.class),
mock(MediaFeatureFlag.class),
- mBgExecutor);
+ mBgExecutor,
+ (sysuiContext, notifPackageContext, entry, existingRepliesAndAction) ->
+ mInflatedSmartReplies);
mRowContentBindStage = new RowContentBindStage(
binder,
mock(NotifInflationErrorManager.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 2ce8b34b193a..fb37ed57c1da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -53,7 +53,6 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
-import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.notification.ConversationNotificationProcessor;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
@@ -69,7 +68,7 @@ import com.android.systemui.statusbar.notification.row.NotificationRowContentBin
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
-import com.android.systemui.statusbar.policy.SmartReplyConstants;
+import com.android.systemui.statusbar.policy.InflatedSmartReplies;
import org.mockito.ArgumentCaptor;
@@ -134,11 +133,11 @@ public class NotificationTestHelper {
NotificationContentInflater contentBinder = new NotificationContentInflater(
mock(NotifRemoteViewCache.class),
mock(NotificationRemoteInputManager.class),
- () -> mock(SmartReplyConstants.class),
- () -> mock(SmartReplyController.class),
mock(ConversationNotificationProcessor.class),
mock(MediaFeatureFlag.class),
- mock(Executor.class));
+ mock(Executor.class),
+ (sysuiContext, notifPackageContext, entry, existingRepliesAndAction) ->
+ mock(InflatedSmartReplies.class));
contentBinder.setInflateSynchronously(true);
mBindStage = new RowContentBindStage(contentBinder,
mock(NotifInflationErrorManager.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java
index 53d8e5866347..e93c5dbdadc1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/InflatedSmartRepliesTest.java
@@ -67,16 +67,20 @@ public class InflatedSmartRepliesTest extends SysuiTestCase {
private static final Intent WHITELISTED_TEST_INTENT =
new Intent("com.android.WHITELISTED_TEST_ACTION");
- @Mock SmartReplyConstants mSmartReplyConstants;
- @Mock Notification mNotification;
- NotificationEntry mEntry;
- @Mock RemoteInput mRemoteInput;
- @Mock RemoteInput mFreeFormRemoteInput;
- @Mock ActivityManagerWrapper mActivityManagerWrapper;
- @Mock PackageManagerWrapper mPackageManagerWrapper;
- @Mock DevicePolicyManagerWrapper mDevicePolicyManagerWrapper;
+ @Mock private SmartReplyConstants mSmartReplyConstants;
+ @Mock private Notification mNotification;
+ @Mock private RemoteInput mRemoteInput;
+ @Mock private RemoteInput mFreeFormRemoteInput;
+ @Mock private ActivityManagerWrapper mActivityManagerWrapper;
+ @Mock private PackageManagerWrapper mPackageManagerWrapper;
+ @Mock private DevicePolicyManagerWrapper mDevicePolicyManagerWrapper;
+ @Mock private SmartRepliesAndActions mSmartRepliesAndActions;
+ @Mock private SmartReplyInflater mSmartReplyInflater;
+ @Mock private SmartActionInflater mSmartActionInflater;
private Icon mActionIcon;
+ private NotificationEntry mEntry;
+ private SmartRepliesAndActionsInflaterImpl mSmartRepliesInflater;
@Before
@UiThreadTest
@@ -96,6 +100,14 @@ public class InflatedSmartRepliesTest extends SysuiTestCase {
mActionIcon = Icon.createWithResource(mContext, R.drawable.ic_person);
when(mActivityManagerWrapper.isLockTaskKioskModeActive()).thenReturn(false);
+
+ mSmartRepliesInflater = new SmartRepliesAndActionsInflaterImpl(
+ mSmartReplyConstants,
+ mActivityManagerWrapper,
+ mPackageManagerWrapper,
+ mDevicePolicyManagerWrapper,
+ mSmartReplyInflater,
+ mSmartActionInflater);
}
@Test
@@ -107,7 +119,7 @@ public class InflatedSmartRepliesTest extends SysuiTestCase {
when(mSmartReplyConstants.isEnabled()).thenReturn(false);
SmartRepliesAndActions repliesAndActions =
- InflatedSmartReplies.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
+ mSmartRepliesInflater.chooseSmartRepliesAndActions(mEntry);
assertThat(repliesAndActions.smartReplies).isNull();
assertThat(repliesAndActions.smartActions).isNull();
@@ -123,7 +135,7 @@ public class InflatedSmartRepliesTest extends SysuiTestCase {
when(mSmartReplyConstants.isEnabled()).thenReturn(false);
SmartRepliesAndActions repliesAndActions =
- InflatedSmartReplies.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
+ mSmartRepliesInflater.chooseSmartRepliesAndActions(mEntry);
assertThat(repliesAndActions.smartReplies).isNull();
assertThat(repliesAndActions.smartActions).isNull();
@@ -135,7 +147,7 @@ public class InflatedSmartRepliesTest extends SysuiTestCase {
setupAppGeneratedReplies(smartReplies);
SmartRepliesAndActions repliesAndActions =
- InflatedSmartReplies.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
+ mSmartRepliesInflater.chooseSmartRepliesAndActions(mEntry);
assertThat(repliesAndActions.smartReplies.choices).isEqualTo(Arrays.asList(smartReplies));
assertThat(repliesAndActions.smartReplies.fromAssistant).isFalse();
@@ -150,7 +162,7 @@ public class InflatedSmartRepliesTest extends SysuiTestCase {
setupAppGeneratedSuggestions(smartReplies, smartActions);
SmartRepliesAndActions repliesAndActions =
- InflatedSmartReplies.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
+ mSmartRepliesInflater.chooseSmartRepliesAndActions(mEntry);
assertThat(repliesAndActions.smartReplies.choices).isEqualTo(Arrays.asList(smartReplies));
assertThat(repliesAndActions.smartReplies.fromAssistant).isFalse();
@@ -169,7 +181,7 @@ public class InflatedSmartRepliesTest extends SysuiTestCase {
.build();
SmartRepliesAndActions repliesAndActions =
- InflatedSmartReplies.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
+ mSmartRepliesInflater.chooseSmartRepliesAndActions(mEntry);
assertThat(repliesAndActions.smartReplies.choices).isEqualTo(
mEntry.getSmartReplies());
@@ -187,7 +199,7 @@ public class InflatedSmartRepliesTest extends SysuiTestCase {
.setSmartReplies(createReplies("Sys Smart Reply 1", "Sys Smart Reply 2"))
.build();
SmartRepliesAndActions repliesAndActions =
- InflatedSmartReplies.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
+ mSmartRepliesInflater.chooseSmartRepliesAndActions(mEntry);
assertThat(repliesAndActions.smartReplies).isNull();
assertThat(repliesAndActions.smartActions).isNull();
@@ -202,8 +214,9 @@ public class InflatedSmartRepliesTest extends SysuiTestCase {
modifyRanking(mEntry)
.setSmartActions(createActions("Sys Smart Action 1", "Sys Smart Action 2"))
.build();
+
SmartRepliesAndActions repliesAndActions =
- InflatedSmartReplies.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
+ mSmartRepliesInflater.chooseSmartRepliesAndActions(mEntry);
assertThat(repliesAndActions.smartReplies).isNull();
assertThat(repliesAndActions.smartActions.actions)
@@ -226,7 +239,7 @@ public class InflatedSmartRepliesTest extends SysuiTestCase {
.build();
SmartRepliesAndActions repliesAndActions =
- InflatedSmartReplies.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
+ mSmartRepliesInflater.chooseSmartRepliesAndActions(mEntry);
assertThat(repliesAndActions.smartReplies.choices)
.isEqualTo(Arrays.asList(appGenSmartReplies));
@@ -248,7 +261,7 @@ public class InflatedSmartRepliesTest extends SysuiTestCase {
.build();
SmartRepliesAndActions repliesAndActions =
- InflatedSmartReplies.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
+ mSmartRepliesInflater.chooseSmartRepliesAndActions(mEntry);
assertThat(repliesAndActions.smartActions).isNull();
assertThat(repliesAndActions.smartReplies).isNull();
@@ -270,7 +283,7 @@ public class InflatedSmartRepliesTest extends SysuiTestCase {
.build();
SmartRepliesAndActions repliesAndActions =
- InflatedSmartReplies.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
+ mSmartRepliesInflater.chooseSmartRepliesAndActions(mEntry);
assertThat(repliesAndActions.smartReplies.choices).isEqualTo(
mEntry.getSmartReplies());
@@ -306,7 +319,7 @@ public class InflatedSmartRepliesTest extends SysuiTestCase {
.build();
SmartRepliesAndActions repliesAndActions =
- InflatedSmartReplies.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
+ mSmartRepliesInflater.chooseSmartRepliesAndActions(mEntry);
// Only the action for the whitelisted package should be allowed.
assertThat(repliesAndActions.smartActions.actions.size()).isEqualTo(1);
@@ -329,7 +342,7 @@ public class InflatedSmartRepliesTest extends SysuiTestCase {
.build();
SmartRepliesAndActions repliesAndActions =
- InflatedSmartReplies.chooseSmartRepliesAndActions(mSmartReplyConstants, mEntry);
+ mSmartRepliesInflater.chooseSmartRepliesAndActions(mEntry);
// We don't restrict replies or actions in screen pinning mode.
assertThat(repliesAndActions.smartReplies.choices).isEqualTo(
@@ -356,8 +369,10 @@ public class InflatedSmartRepliesTest extends SysuiTestCase {
new SmartReplies(rightReplies, null, null, false /* fromAssistant */),
new SmartActions(rightActions, false /* fromAssistant */));
- assertThat(InflatedSmartReplies.areSuggestionsSimilar(
- leftRepliesAndActions, rightRepliesAndActions)).isTrue();
+ assertThat(
+ SmartRepliesAndActionsInflaterKt
+ .areSuggestionsSimilar(leftRepliesAndActions, rightRepliesAndActions))
+ .isTrue();
}
@Test
@@ -378,7 +393,7 @@ public class InflatedSmartRepliesTest extends SysuiTestCase {
new SmartReplies(rightReplies, null, null, false /* fromAssistant */),
new SmartActions(rightActions, false /* fromAssistant */));
- assertThat(InflatedSmartReplies.areSuggestionsSimilar(
+ assertThat(SmartRepliesAndActionsInflaterKt.areSuggestionsSimilar(
leftRepliesAndActions, rightRepliesAndActions)).isFalse();
}
@@ -400,7 +415,7 @@ public class InflatedSmartRepliesTest extends SysuiTestCase {
new SmartReplies(rightReplies, null, null, false /* fromAssistant */),
new SmartActions(rightActions, false /* fromAssistant */));
- assertThat(InflatedSmartReplies.areSuggestionsSimilar(
+ assertThat(SmartRepliesAndActionsInflaterKt.areSuggestionsSimilar(
leftRepliesAndActions, rightRepliesAndActions)).isFalse();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index f1a6e67edb43..836a81e42193 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -70,6 +70,12 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+import kotlin.sequences.Sequence;
+import kotlin.sequences.SequencesKt;
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -98,31 +104,32 @@ public class SmartReplyViewTest extends SysuiTestCase {
private int mDoubleLinePaddingHorizontal;
private int mSpacing;
- @Mock private SmartReplyController mLogger;
private NotificationEntry mEntry;
private Notification mNotification;
+
+ private SmartReplyInflaterImpl mSmartReplyInflater;
+ private SmartActionInflaterImpl mSmartActionInflater;
+
@Mock private SmartReplyConstants mConstants;
+ @Mock private ActivityStarter mActivityStarter;
+ @Mock private HeadsUpManager mHeadsUpManager;
+ @Mock private NotificationRemoteInputManager mNotificationRemoteInputManager;
+ @Mock private SmartReplyController mSmartReplyController;
- @Mock ActivityStarter mActivityStarter;
- @Mock HeadsUpManager mHeadsUpManager;
+ private final KeyguardDismissUtil mKeyguardDismissUtil = new KeyguardDismissUtil();
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mReceiver = new BlockingQueueIntentReceiver();
mContext.registerReceiver(mReceiver, new IntentFilter(TEST_ACTION));
- mDependency.get(KeyguardDismissUtil.class).setDismissHandler((action, unused) -> {
- action.onDismiss();
- });
+ mKeyguardDismissUtil.setDismissHandler((action, unused) -> action.onDismiss());
mDependency.injectMockDependency(KeyguardUpdateMonitor.class);
mDependency.injectMockDependency(ShadeController.class);
mDependency.injectMockDependency(NotificationRemoteInputManager.class);
mDependency.injectTestDependency(ActivityStarter.class, mActivityStarter);
mDependency.injectTestDependency(SmartReplyConstants.class, mConstants);
- mContainer = new View(mContext, null);
- mView = SmartReplyView.inflate(mContext);
-
// Any number of replies are fine.
when(mConstants.getMinNumSystemGeneratedReplies()).thenReturn(0);
when(mConstants.getMaxSqueezeRemeasureAttempts()).thenReturn(3);
@@ -130,6 +137,9 @@ public class SmartReplyViewTest extends SysuiTestCase {
// Ensure there's no delay before we can click smart suggestions.
when(mConstants.getOnClickInitDelay()).thenReturn(0L);
+ mContainer = new View(mContext, null);
+ mView = SmartReplyView.inflate(mContext, mConstants);
+
final Resources res = mContext.getResources();
mSingleLinePaddingHorizontal = res.getDimensionPixelSize(
R.dimen.smart_reply_button_padding_horizontal_single_line);
@@ -147,6 +157,18 @@ public class SmartReplyViewTest extends SysuiTestCase {
.build();
mActionIcon = Icon.createWithResource(mContext, R.drawable.ic_person);
+
+ mSmartReplyInflater = new SmartReplyInflaterImpl(
+ mConstants,
+ mKeyguardDismissUtil,
+ mNotificationRemoteInputManager,
+ mSmartReplyController,
+ mContext);
+ mSmartActionInflater = new SmartActionInflaterImpl(
+ mConstants,
+ mActivityStarter,
+ mSmartReplyController,
+ mHeadsUpManager);
}
@After
@@ -168,7 +190,7 @@ public class SmartReplyViewTest extends SysuiTestCase {
@Test
public void testSendSmartReply_keyguardCancelled() throws InterruptedException {
- mDependency.get(KeyguardDismissUtil.class).setDismissHandler((action, unused) -> {});
+ mKeyguardDismissUtil.setDismissHandler((action, unused) -> { });
setSmartReplies(TEST_CHOICES);
mView.getChildAt(2).performClick();
@@ -179,9 +201,8 @@ public class SmartReplyViewTest extends SysuiTestCase {
@Test
public void testSendSmartReply_waitsForKeyguard() throws InterruptedException {
AtomicReference<OnDismissAction> actionRef = new AtomicReference<>();
- mDependency.get(KeyguardDismissUtil.class).setDismissHandler((action, unused) -> {
- actionRef.set(action);
- });
+
+ mKeyguardDismissUtil.setDismissHandler((action, unused) -> actionRef.set(action));
setSmartReplies(TEST_CHOICES);
mView.getChildAt(2).performClick();
@@ -202,7 +223,7 @@ public class SmartReplyViewTest extends SysuiTestCase {
public void testSendSmartReply_controllerCalled() {
setSmartReplies(TEST_CHOICES);
mView.getChildAt(2).performClick();
- verify(mLogger).smartReplySent(mEntry, 2, TEST_CHOICES[2],
+ verify(mSmartReplyController).smartReplySent(mEntry, 2, TEST_CHOICES[2],
MetricsEvent.LOCATION_UNKNOWN, false /* modifiedBeforeSending */);
}
@@ -461,24 +482,28 @@ public class SmartReplyViewTest extends SysuiTestCase {
private void setSmartReplies(CharSequence[] choices, boolean useDelayedOnClickListener) {
mView.resetSmartSuggestions(mContainer);
- List<Button> replyButtons = inflateSmartReplies(choices, false /* fromAssistant */,
- useDelayedOnClickListener);
+ List<Button> replyButtons =
+ inflateSmartReplies(
+ choices, false /* fromAssistant */, useDelayedOnClickListener)
+ .collect(Collectors.toList());
mView.addPreInflatedButtons(replyButtons);
}
- private List<Button> inflateSmartReplies(CharSequence[] choices, boolean fromAssistant,
- boolean useDelayedOnClickListener) {
- PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0,
- new Intent(TEST_ACTION), 0);
+ private SmartReplyView.SmartReplies createSmartReplies(CharSequence[] choices,
+ boolean fromAssistant) {
+ PendingIntent pendingIntent =
+ PendingIntent.getBroadcast(mContext, 0, new Intent(TEST_ACTION), 0);
RemoteInput input = new RemoteInput.Builder(TEST_RESULT_KEY).setChoices(choices).build();
- SmartReplyView.SmartReplies smartReplies =
- new SmartReplyView.SmartReplies(
- Arrays.asList(choices),
- input,
- pendingIntent,
- fromAssistant);
- return mView.inflateRepliesFromRemoteInput(smartReplies, mLogger, mEntry,
- useDelayedOnClickListener);
+ return new SmartReplyView.SmartReplies(
+ Arrays.asList(choices), input, pendingIntent, fromAssistant);
+ }
+
+ private Stream<Button> inflateSmartReplies(CharSequence[] choices, boolean fromAssistant,
+ boolean useDelayedOnClickListener) {
+ SmartReplyView.SmartReplies smartReplies = createSmartReplies(choices, fromAssistant);
+ return IntStream.range(0, choices.length).mapToObj(idx ->
+ mSmartReplyInflater.inflateReplyButton(
+ mView, mEntry, smartReplies, idx, choices[idx], useDelayedOnClickListener));
}
private Notification.Action createAction(String actionTitle) {
@@ -501,14 +526,20 @@ public class SmartReplyViewTest extends SysuiTestCase {
private void setSmartActions(String[] actionTitles, boolean useDelayedOnClickListener) {
mView.resetSmartSuggestions(mContainer);
- List<Button> actions = mView.inflateSmartActions(
- getContext(),
- new SmartReplyView.SmartActions(createActions(actionTitles), false),
- mLogger,
- mEntry,
- mHeadsUpManager,
- useDelayedOnClickListener);
- mView.addPreInflatedButtons(actions);
+ SmartReplyView.SmartActions smartActions = new SmartReplyView.SmartActions(
+ createActions(actionTitles), false);
+
+ Stream<Button> buttons = IntStream.range(0, smartActions.actions.size()).mapToObj(idx ->
+ mSmartActionInflater.inflateActionButton(
+ mView,
+ mEntry,
+ smartActions,
+ idx,
+ smartActions.actions.get(idx),
+ useDelayedOnClickListener,
+ getContext()));
+
+ mView.addPreInflatedButtons(buttons.collect(Collectors.toList()));
}
private void setSmartRepliesAndActions(CharSequence[] choices, String[] actionTitles) {
@@ -520,16 +551,25 @@ public class SmartReplyViewTest extends SysuiTestCase {
CharSequence[] choices, String[] actionTitles, boolean fromAssistant,
boolean useDelayedOnClickListener) {
mView.resetSmartSuggestions(mContainer);
- List<Button> smartSuggestions = inflateSmartReplies(choices, fromAssistant,
- useDelayedOnClickListener);
- smartSuggestions.addAll(mView.inflateSmartActions(
- getContext(),
- new SmartReplyView.SmartActions(createActions(actionTitles), fromAssistant),
- mLogger,
- mEntry,
- mHeadsUpManager,
- useDelayedOnClickListener));
- mView.addPreInflatedButtons(smartSuggestions);
+ Sequence<Button> inflatedReplies = SequencesKt.asSequence(
+ inflateSmartReplies(choices, fromAssistant, useDelayedOnClickListener)
+ .iterator());
+ SmartReplyView.SmartActions smartActions = new SmartReplyView.SmartActions(
+ createActions(actionTitles), fromAssistant);
+ Sequence<Button> inflatedSmartActions = SequencesKt.asSequence(
+ IntStream.range(0, smartActions.actions.size())
+ .mapToObj(idx -> mSmartActionInflater.inflateActionButton(
+ mView,
+ mEntry,
+ smartActions,
+ idx,
+ smartActions.actions.get(idx),
+ useDelayedOnClickListener,
+ getContext()))
+ .iterator());
+ mView.addPreInflatedButtons(
+ SequencesKt.toList(SequencesKt.plus(inflatedReplies, inflatedSmartActions)));
+ mView.setSmartRepliesGeneratedByAssistant(fromAssistant);
}
private ViewGroup buildExpectedView(CharSequence[] choices, int lineCount) {
@@ -564,10 +604,18 @@ public class SmartReplyViewTest extends SysuiTestCase {
Button previous = null;
SmartReplyView.SmartReplies smartReplies =
new SmartReplyView.SmartReplies(Arrays.asList(choices), null, null, false);
- for (int i = 0; i < choices.length; ++i) {
- Button current = SmartReplyView.inflateReplyButton(mView, mContext, i, smartReplies,
- null /* SmartReplyController */, null /* NotificationEntry */,
- true /* useDelayedOnClickListener */);
+
+ Iterable<Button> inflatedReplies = SequencesKt.asIterable(SequencesKt.asSequence(
+ IntStream.range(0, smartReplies.choices.size()).mapToObj(
+ idx -> mSmartReplyInflater.inflateReplyButton(
+ mView,
+ mEntry,
+ smartReplies,
+ idx,
+ smartReplies.choices.get(idx),
+ true /* delayOnClickListener */))
+ .iterator()));
+ for (Button current : inflatedReplies) {
current.setPadding(paddingHorizontal, current.getPaddingTop(), paddingHorizontal,
current.getPaddingBottom());
if (previous != null) {
@@ -583,9 +631,21 @@ public class SmartReplyViewTest extends SysuiTestCase {
previous = current;
}
+ SmartReplyView.SmartActions smartActions = new SmartReplyView.SmartActions(actions, false);
+ Iterable<Button> inflatedSmartActions = SequencesKt.asIterable(SequencesKt.asSequence(
+ IntStream.range(0, smartActions.actions.size())
+ .mapToObj(idx -> mSmartActionInflater.inflateActionButton(
+ mView,
+ mEntry,
+ smartActions,
+ idx,
+ smartActions.actions.get(idx),
+ true /* delayOnClickListener */,
+ getContext()))
+ .iterator()));
+
// Add smart actions
- for (int i = 0; i < actions.size(); ++i) {
- Button current = inflateActionButton(actions.get(i));
+ for (Button current : inflatedSmartActions) {
current.setPadding(paddingHorizontal, current.getPaddingTop(), paddingHorizontal,
current.getPaddingBottom());
if (previous != null) {
@@ -672,8 +732,8 @@ public class SmartReplyViewTest extends SysuiTestCase {
Thread.sleep(delayMs);
mView.getChildAt(2).performClick();
- verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any(), any(),
- any());
+ verify(mActivityStarter, times(1))
+ .startPendingIntentDismissingKeyguard(any(), any(), any());
}
@Test
@@ -684,8 +744,8 @@ public class SmartReplyViewTest extends SysuiTestCase {
mView.getChildAt(2).performClick();
- verify(mActivityStarter, times(1)).startPendingIntentDismissingKeyguard(any(), any(),
- any());
+ verify(mActivityStarter, times(1))
+ .startPendingIntentDismissingKeyguard(any(), any(), any());
}
@Test
@@ -869,18 +929,26 @@ public class SmartReplyViewTest extends SysuiTestCase {
assertReplyButtonHidden(mView.getChildAt(2));
}
- private Button inflateActionButton(Notification.Action action) {
- return SmartReplyView.inflateActionButton(mView, getContext(), getContext(), 0,
- new SmartReplyView.SmartActions(Collections.singletonList(action), false),
- mLogger, mEntry, mHeadsUpManager, true /* useDelayedOnClickListener */);
- }
-
@Test
public void testInflateActionButton_smartActionIconSingleLineSizeForTwoLineButton() {
// Ensure smart action icons are the same size regardless of the number of text rows in the
// button.
- Button singleLineButton = inflateActionButton(createAction("One line"));
- Button doubleLineButton = inflateActionButton(createAction("Two\nlines"));
+ List<Notification.Action> actions = Stream.of("One line", "Two\nlines")
+ .map(this::createAction)
+ .collect(Collectors.toList());
+ SmartReplyView.SmartActions smartActions = new SmartReplyView.SmartActions(actions, false);
+ List<Button> buttons = IntStream.range(0, smartActions.actions.size())
+ .mapToObj(idx -> mSmartActionInflater.inflateActionButton(
+ mView,
+ mEntry,
+ smartActions,
+ idx,
+ smartActions.actions.get(idx),
+ true /* delayOnClickListener */,
+ getContext()))
+ .collect(Collectors.toList());
+ Button singleLineButton = buttons.get(0);
+ Button doubleLineButton = buttons.get(1);
Drawable singleLineDrawable = singleLineButton.getCompoundDrawables()[0]; // left drawable
Drawable doubleLineDrawable = doubleLineButton.getCompoundDrawables()[0]; // left drawable
assertEquals(singleLineDrawable.getBounds().width(),
@@ -1068,7 +1136,7 @@ public class SmartReplyViewTest extends SysuiTestCase {
@Test
public void testMeasure_minNumSystemGeneratedSmartReplies_notEnoughReplies() {
- when(mConstants.getMinNumSystemGeneratedReplies()).thenReturn(3);
+ mView.setMinNumSystemGeneratedReplies(3);
// Add 2 replies when the minimum is 3 -> we should end up with 0 replies.
String[] choices = new String[] {"reply1", "reply2"};
@@ -1082,7 +1150,9 @@ public class SmartReplyViewTest extends SysuiTestCase {
choices, actions, true /* fromAssistant */, true /* useDelayedOnClickListener */);
mView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ // 395, 168
assertEqualMeasures(expectedView, mView);
+
// smart replies
assertReplyButtonHidden(mView.getChildAt(0));
assertReplyButtonHidden(mView.getChildAt(1));
@@ -1121,7 +1191,7 @@ public class SmartReplyViewTest extends SysuiTestCase {
*/
@Test
public void testMeasure_minNumSystemGeneratedSmartReplies_unSqueezeActions() {
- when(mConstants.getMinNumSystemGeneratedReplies()).thenReturn(2);
+ mView.setMinNumSystemGeneratedReplies(2);
// Add 2 replies when the minimum is 3 -> we should end up with 0 replies.
String[] choices = new String[] {"This is a very long two-line reply."};
diff --git a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
index 0a10ab2fbf02..c743fd07c492 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
@@ -54,7 +54,11 @@ import androidx.test.filters.SmallTest;
import com.android.internal.R;
import com.android.internal.util.IntPair;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dump.DumpManager;
+import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
@@ -84,6 +88,7 @@ public class ToastUITest extends SysuiTestCase {
private static final String TEXT = "Hello World";
private static final int MESSAGE_RES_ID = R.id.message;
+ private FakeExecutor mFakeDelayableExecutor = new FakeExecutor(new FakeSystemClock());
private Context mContextSpy;
private ToastUI mToastUI;
@Mock private LayoutInflater mLayoutInflater;
@@ -91,6 +96,10 @@ public class ToastUITest extends SysuiTestCase {
@Mock private WindowManager mWindowManager;
@Mock private INotificationManager mNotificationManager;
@Mock private IAccessibilityManager mAccessibilityManager;
+ @Mock private PluginManager mPluginManager;
+ @Mock private DumpManager mDumpManager;
+ @Mock private ToastLogger mToastLogger;
+
@Mock private ITransientNotificationCallback mCallback;
@Captor private ArgumentCaptor<View> mViewCaptor;
@Captor private ArgumentCaptor<ViewGroup.LayoutParams> mParamsCaptor;
@@ -109,8 +118,10 @@ public class ToastUITest extends SysuiTestCase {
mContextSpy = spy(mContext);
doReturn(mContextSpy).when(mContextSpy).createContextAsUser(any(), anyInt());
+ doReturn(mContextSpy).when(mContextSpy).createContextAsUser(any(), anyInt());
mToastUI = new ToastUI(mContextSpy, mCommandQueue, mNotificationManager,
- mAccessibilityManager);
+ mAccessibilityManager, new ToastFactory(mPluginManager, mDumpManager),
+ mFakeDelayableExecutor, mToastLogger);
}
@Test
@@ -271,6 +282,29 @@ public class ToastUITest extends SysuiTestCase {
verify(mCallback).onToastHidden();
}
+ @Test
+ public void testShowToast_logs() {
+ mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+ mCallback);
+
+ verify(mToastLogger).logOnShowToast(UID_1, PACKAGE_NAME_1, TEXT, TOKEN_1.toString());
+ }
+
+ @Test
+ public void testHideToast_logs() {
+ mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+ mCallback);
+ mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
+ verify(mToastLogger).logOnHideToast(PACKAGE_NAME_1, TOKEN_1.toString());
+ }
+
+ @Test
+ public void testHideToast_error_noLog() {
+ // no toast was shown, so this hide is invalid
+ mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
+ verify(mToastLogger, never()).logOnHideToast(PACKAGE_NAME_1, TOKEN_1.toString());
+ }
+
private View verifyWmAddViewAndAttachToParent() {
ArgumentCaptor<View> viewCaptor = ArgumentCaptor.forClass(View.class);
verify(mWindowManager).addView(viewCaptor.capture(), any());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index a5fbf195ed27..76fe3bf96500 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -142,7 +142,6 @@ public class WMShellTest extends SysuiTestCase {
@Test
public void initOneHanded_registersCallbacks() {
- when(mOneHanded.hasOneHandedFeature()).thenReturn(true);
mWMShell.initOneHanded(mOneHanded);
verify(mKeyguardUpdateMonitor).registerCallback(any(KeyguardUpdateMonitorCallback.class));
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index 336124dc1b90..52d59fcdc19b 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -616,7 +616,7 @@ public class IpServer extends StateMachine {
if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")");
if (enabled) {
- mIpv4Address = requestIpv4Address();
+ mIpv4Address = requestIpv4Address(true /* useLastAddress */);
}
if (mIpv4Address == null) {
@@ -661,14 +661,14 @@ public class IpServer extends StateMachine {
return configureDhcp(enabled, mIpv4Address, mStaticIpv4ClientAddr);
}
- private LinkAddress requestIpv4Address() {
+ private LinkAddress requestIpv4Address(final boolean useLastAddress) {
if (mStaticIpv4ServerAddr != null) return mStaticIpv4ServerAddr;
if (mInterfaceType == TetheringManager.TETHERING_BLUETOOTH) {
return new LinkAddress(BLUETOOTH_IFACE_ADDR);
}
- return mPrivateAddressCoordinator.requestDownstreamAddress(this);
+ return mPrivateAddressCoordinator.requestDownstreamAddress(this, useLastAddress);
}
private boolean startIPv6() {
@@ -957,7 +957,7 @@ public class IpServer extends StateMachine {
}
final LinkAddress deprecatedLinkAddress = mIpv4Address;
- mIpv4Address = requestIpv4Address();
+ mIpv4Address = requestIpv4Address(false);
if (mIpv4Address == null) {
mLog.e("Fail to request a new downstream prefix");
return;
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
index b285849f9edf..6276c4e2aa7d 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
@@ -16,7 +16,9 @@
package com.android.networkstack.tethering;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+import static android.net.TetheringManager.TETHERING_BLUETOOTH;
import static android.net.TetheringManager.TETHERING_WIFI_P2P;
+import static android.net.util.PrefixUtils.asIpPrefix;
import static java.util.Arrays.asList;
@@ -26,9 +28,9 @@ import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.Network;
import android.net.ip.IpServer;
-import android.net.util.PrefixUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.SparseArray;
import androidx.annotation.Nullable;
@@ -58,9 +60,6 @@ public class PrivateAddressCoordinator {
private static final int MAX_UBYTE = 256;
private static final int BYTE_MASK = 0xff;
- // reserved for bluetooth tethering.
- private static final int BLUETOOTH_RESERVED = 44;
- private static final int WIFI_P2P_RESERVED = 49;
private static final byte DEFAULT_ID = (byte) 42;
// Upstream monitor would be stopped when tethering is down. When tethering restart, downstream
@@ -75,9 +74,12 @@ public class PrivateAddressCoordinator {
// Tethering use 192.168.0.0/16 that has 256 contiguous class C network numbers.
private static final String DEFAULT_TETHERING_PREFIX = "192.168.0.0/16";
private static final String LEGACY_WIFI_P2P_IFACE_ADDRESS = "192.168.49.1/24";
+ private static final String LEGACY_BLUETOOTH_IFACE_ADDRESS = "192.168.44.1/24";
private final IpPrefix mTetheringPrefix;
private final ConnectivityManager mConnectivityMgr;
private final TetheringConfiguration mConfig;
+ // keyed by downstream type(TetheringManager.TETHERING_*).
+ private final SparseArray<LinkAddress> mCachedAddresses;
public PrivateAddressCoordinator(Context context, TetheringConfiguration config) {
mDownstreams = new ArraySet<>();
@@ -86,6 +88,10 @@ public class PrivateAddressCoordinator {
mConnectivityMgr = (ConnectivityManager) context.getSystemService(
Context.CONNECTIVITY_SERVICE);
mConfig = config;
+ mCachedAddresses = new SparseArray<>();
+ // Reserved static addresses for bluetooth and wifi p2p.
+ mCachedAddresses.put(TETHERING_BLUETOOTH, new LinkAddress(LEGACY_BLUETOOTH_IFACE_ADDRESS));
+ mCachedAddresses.put(TETHERING_WIFI_P2P, new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS));
}
/**
@@ -94,7 +100,8 @@ public class PrivateAddressCoordinator {
* UpstreamNetworkState must have an already populated LinkProperties.
*/
public void updateUpstreamPrefix(final UpstreamNetworkState ns) {
- // Do not support VPN as upstream
+ // Do not support VPN as upstream. Normally, networkCapabilities is not expected to be null,
+ // but just checking to be sure.
if (ns.networkCapabilities != null && ns.networkCapabilities.hasTransport(TRANSPORT_VPN)) {
removeUpstreamPrefix(ns.network);
return;
@@ -116,7 +123,7 @@ public class PrivateAddressCoordinator {
for (LinkAddress address : linkAddresses) {
if (!address.isIpv4()) continue;
- list.add(PrefixUtils.asIpPrefix(address));
+ list.add(asIpPrefix(address));
}
return list;
@@ -155,21 +162,23 @@ public class PrivateAddressCoordinator {
mUpstreamPrefixMap.removeAll(toBeRemoved);
}
- private boolean isReservedSubnet(final int subnet) {
- return subnet == BLUETOOTH_RESERVED || subnet == WIFI_P2P_RESERVED;
- }
-
/**
* Pick a random available address and mark its prefix as in use for the provided IpServer,
* returns null if there is no available address.
*/
@Nullable
- public LinkAddress requestDownstreamAddress(final IpServer ipServer) {
+ public LinkAddress requestDownstreamAddress(final IpServer ipServer, boolean useLastAddress) {
if (mConfig.shouldEnableWifiP2pDedicatedIp()
&& ipServer.interfaceType() == TETHERING_WIFI_P2P) {
return new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS);
}
+ final LinkAddress cachedAddress = mCachedAddresses.get(ipServer.interfaceType());
+ if (useLastAddress && cachedAddress != null
+ && !isConflictWithUpstream(asIpPrefix(cachedAddress))) {
+ return cachedAddress;
+ }
+
// Address would be 192.168.[subAddress]/24.
final byte[] bytes = mTetheringPrefix.getRawAddress();
final int subAddress = getRandomSubAddr();
@@ -177,9 +186,8 @@ public class PrivateAddressCoordinator {
bytes[3] = getSanitizedAddressSuffix(subAddress, (byte) 0, (byte) 1, (byte) 0xff);
for (int i = 0; i < MAX_UBYTE; i++) {
final int newSubNet = (subNet + i) & BYTE_MASK;
- if (isReservedSubnet(newSubNet)) continue;
-
bytes[2] = (byte) newSubNet;
+
final InetAddress addr;
try {
addr = InetAddress.getByAddress(bytes);
@@ -187,20 +195,23 @@ public class PrivateAddressCoordinator {
throw new IllegalStateException("Invalid address, shouldn't happen.", e);
}
- final IpPrefix prefix = new IpPrefix(addr, PREFIX_LENGTH);
- // Check whether this prefix is in use.
- if (isDownstreamPrefixInUse(prefix)) continue;
- // Check whether this prefix is conflict with any current upstream network.
- if (isConflictWithUpstream(prefix)) continue;
+ if (isConflict(new IpPrefix(addr, PREFIX_LENGTH))) continue;
mDownstreams.add(ipServer);
- return new LinkAddress(addr, PREFIX_LENGTH);
+ final LinkAddress newAddress = new LinkAddress(addr, PREFIX_LENGTH);
+ mCachedAddresses.put(ipServer.interfaceType(), newAddress);
+ return newAddress;
}
// No available address.
return null;
}
+ private boolean isConflict(final IpPrefix prefix) {
+ // Check whether this prefix is in use or conflict with any current upstream network.
+ return isDownstreamPrefixInUse(prefix) || isConflictWithUpstream(prefix);
+ }
+
/** Get random sub address value. Return value is in 0 ~ 0xffff. */
@VisibleForTesting
public int getRandomSubAddr() {
@@ -244,13 +255,24 @@ public class PrivateAddressCoordinator {
return prefix1.contains(prefix2.getAddress());
}
- private boolean isDownstreamPrefixInUse(final IpPrefix source) {
+ // InUse Prefixes are prefixes of mCachedAddresses which are active downstream addresses, last
+ // downstream addresses(reserved for next time) and static addresses(e.g. bluetooth, wifi p2p).
+ private boolean isDownstreamPrefixInUse(final IpPrefix prefix) {
// This class always generates downstream prefixes with the same prefix length, so
// prefixes cannot be contained in each other. They can only be equal to each other.
+ for (int i = 0; i < mCachedAddresses.size(); i++) {
+ if (prefix.equals(asIpPrefix(mCachedAddresses.valueAt(i)))) return true;
+ }
+
+ // IpServer may use manually-defined address (mStaticIpv4ServerAddr) which does not include
+ // in mCachedAddresses.
for (IpServer downstream : mDownstreams) {
- final IpPrefix prefix = getDownstreamPrefix(downstream);
- if (source.equals(prefix)) return true;
+ final IpPrefix target = getDownstreamPrefix(downstream);
+ if (target == null) continue;
+
+ if (isConflictPrefix(prefix, target)) return true;
}
+
return false;
}
@@ -258,7 +280,7 @@ public class PrivateAddressCoordinator {
final LinkAddress address = downstream.getAddress();
if (address == null) return null;
- return PrefixUtils.asIpPrefix(address);
+ return asIpPrefix(address);
}
void dump(final IndentingPrintWriter pw) {
@@ -268,11 +290,19 @@ public class PrivateAddressCoordinator {
pw.println(mUpstreamPrefixMap.keyAt(i) + " - " + mUpstreamPrefixMap.valueAt(i));
}
pw.decreaseIndent();
+
pw.println("mDownstreams:");
pw.increaseIndent();
for (IpServer ipServer : mDownstreams) {
pw.println(ipServer.interfaceType() + " - " + ipServer.getAddress());
}
pw.decreaseIndent();
+
+ pw.println("mCachedAddresses:");
+ pw.increaseIndent();
+ for (int i = 0; i < mCachedAddresses.size(); i++) {
+ pw.println(mCachedAddresses.keyAt(i) + " - " + mCachedAddresses.valueAt(i));
+ }
+ pw.decreaseIndent();
}
}
diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 1a976adc60e0..2eb75895ac3e 100644
--- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -47,6 +47,7 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
@@ -230,7 +231,8 @@ public class IpServerTest {
dispatchTetherConnectionChanged(upstreamIface, lp, 0);
}
reset(mNetd, mCallback, mAddressCoordinator);
- when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress);
+ when(mAddressCoordinator.requestDownstreamAddress(any(), anyBoolean())).thenReturn(
+ mTestAddress);
}
private void setUpDhcpServer() throws Exception {
@@ -250,7 +252,8 @@ public class IpServerTest {
@Before public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog);
- when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress);
+ when(mAddressCoordinator.requestDownstreamAddress(any(), anyBoolean())).thenReturn(
+ mTestAddress);
when(mTetherConfig.isBpfOffloadEnabled()).thenReturn(true /* default value */);
mBpfCoordinator = spy(new BpfCoordinator(
@@ -372,7 +375,7 @@ public class IpServerTest {
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_TETHERED);
InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator);
- inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any());
+ inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true));
inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP)));
inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
@@ -393,7 +396,7 @@ public class IpServerTest {
dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY);
InOrder inOrder = inOrder(mCallback, mNetd, mAddressCoordinator);
- inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any());
+ inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true));
inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg ->
IFACE_NAME.equals(cfg.ifName) && assertNotContainsFlag(cfg.flags, IF_STATE_UP)));
inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME);
@@ -607,7 +610,7 @@ public class IpServerTest {
final ArgumentCaptor<LinkProperties> lpCaptor =
ArgumentCaptor.forClass(LinkProperties.class);
InOrder inOrder = inOrder(mNetd, mCallback, mAddressCoordinator);
- inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any());
+ inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(true));
inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME);
// One for ipv4 route, one for ipv6 link local route.
inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME),
@@ -620,11 +623,12 @@ public class IpServerTest {
// Simulate the DHCP server receives DHCPDECLINE on MirrorLink and then signals
// onNewPrefixRequest callback.
final LinkAddress newAddress = new LinkAddress("192.168.100.125/24");
- when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(newAddress);
+ when(mAddressCoordinator.requestDownstreamAddress(any(), anyBoolean())).thenReturn(
+ newAddress);
eventCallbacks.onNewPrefixRequest(new IpPrefix("192.168.42.0/24"));
mLooper.dispatchAll();
- inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any());
+ inOrder.verify(mAddressCoordinator).requestDownstreamAddress(any(), eq(false));
inOrder.verify(mNetd).tetherApplyDnsInterfaces();
inOrder.verify(mCallback).updateLinkProperties(eq(mIpServer), lpCaptor.capture());
verifyNoMoreInteractions(mCallback);
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
index 7b6632c36f24..191eb6e71149 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/PrivateAddressCoordinatorTest.java
@@ -23,6 +23,7 @@ import static android.net.TetheringManager.TETHERING_ETHERNET;
import static android.net.TetheringManager.TETHERING_USB;
import static android.net.TetheringManager.TETHERING_WIFI;
import static android.net.TetheringManager.TETHERING_WIFI_P2P;
+import static android.net.util.PrefixUtils.asIpPrefix;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
@@ -40,7 +41,6 @@ import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.ip.IpServer;
-import android.net.util.PrefixUtils;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -65,7 +65,7 @@ public final class PrivateAddressCoordinatorTest {
@Mock private TetheringConfiguration mConfig;
private PrivateAddressCoordinator mPrivateAddressCoordinator;
- private final IpPrefix mBluetoothPrefix = new IpPrefix("192.168.44.0/24");
+ private final LinkAddress mBluetoothAddress = new LinkAddress("192.168.44.1/24");
private final LinkAddress mLegacyWifiP2pAddress = new LinkAddress("192.168.49.1/24");
private final Network mWifiNetwork = new Network(1);
private final Network mMobileNetwork = new Network(2);
@@ -91,98 +91,119 @@ public final class PrivateAddressCoordinatorTest {
}
@Test
- public void testDownstreamPrefixRequest() throws Exception {
- LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer);
- final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address);
- assertNotEquals(hotspotPrefix, mBluetoothPrefix);
+ public void testRequestDownstreamAddressWithoutUsingLastAddress() throws Exception {
+ final IpPrefix bluetoothPrefix = asIpPrefix(mBluetoothAddress);
+ final LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mHotspotIpServer, false /* useLastAddress */);
+ final IpPrefix hotspotPrefix = asIpPrefix(address);
+ assertNotEquals(hotspotPrefix, bluetoothPrefix);
+ when(mHotspotIpServer.getAddress()).thenReturn(address);
- address = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer);
- final IpPrefix testDupRequest = PrefixUtils.asIpPrefix(address);
+ final LinkAddress newAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mHotspotIpServer, false /* useLastAddress */);
+ final IpPrefix testDupRequest = asIpPrefix(newAddress);
assertNotEquals(hotspotPrefix, testDupRequest);
- assertNotEquals(mBluetoothPrefix, testDupRequest);
+ assertNotEquals(bluetoothPrefix, testDupRequest);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
- address = mPrivateAddressCoordinator.requestDownstreamAddress(
- mUsbIpServer);
- final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(address);
- assertNotEquals(usbPrefix, mBluetoothPrefix);
+ final LinkAddress usbAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mUsbIpServer, false /* useLastAddress */);
+ final IpPrefix usbPrefix = asIpPrefix(usbAddress);
+ assertNotEquals(usbPrefix, bluetoothPrefix);
assertNotEquals(usbPrefix, hotspotPrefix);
mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer);
}
@Test
- public void testRequestDownstreamAddress() throws Exception {
- LinkAddress expectedAddress = new LinkAddress("192.168.43.42/24");
- int fakeSubAddr = 0x2b00;
+ public void testSanitizedAddress() throws Exception {
+ int fakeSubAddr = 0x2b00; // 43.0.
when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr);
LinkAddress actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer);
- assertEquals(actualAddress, expectedAddress);
+ mHotspotIpServer, false /* useLastAddress */);
+ assertEquals(new LinkAddress("192.168.43.42/24"), actualAddress);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
- fakeSubAddr = 0x2b01;
+ fakeSubAddr = 0x2d01; // 45.1.
when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr);
actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer);
- assertEquals(actualAddress, expectedAddress);
+ mHotspotIpServer, false /* useLastAddress */);
+ assertEquals(new LinkAddress("192.168.45.42/24"), actualAddress);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
- fakeSubAddr = 0x2bff;
+ fakeSubAddr = 0x2eff; // 46.255.
when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr);
actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer);
- assertEquals(actualAddress, expectedAddress);
+ mHotspotIpServer, false /* useLastAddress */);
+ assertEquals(new LinkAddress("192.168.46.42/24"), actualAddress);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
- expectedAddress = new LinkAddress("192.168.43.5/24");
- fakeSubAddr = 0x2b05;
+ fakeSubAddr = 0x2f05; // 47.5.
when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeSubAddr);
actualAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer);
- assertEquals(actualAddress, expectedAddress);
+ mHotspotIpServer, false /* useLastAddress */);
+ assertEquals(new LinkAddress("192.168.47.5/24"), actualAddress);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
}
- private int getBluetoothSubAddress() {
- final byte[] rawAddress = mBluetoothPrefix.getRawAddress();
- int bluetoothSubNet = rawAddress[2] & 0xff;
- return (bluetoothSubNet << 8) + 0x5;
- }
-
@Test
- public void testReserveBluetoothPrefix() throws Exception {
- when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(getBluetoothSubAddress());
- LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer);
- final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address);
- assertNotEquals("Should not get reserved prefix: ", mBluetoothPrefix, hotspotPrefix);
+ public void testReservedPrefix() throws Exception {
+ // - Test bluetooth prefix is reserved.
+ when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(
+ getSubAddress(mBluetoothAddress.getAddress().getAddress()));
+ final LinkAddress hotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mHotspotIpServer, false /* useLastAddress */);
+ final IpPrefix hotspotPrefix = asIpPrefix(hotspotAddress);
+ assertNotEquals(asIpPrefix(mBluetoothAddress), hotspotPrefix);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
+
+ // - Test previous enabled hotspot prefix(cached prefix) is reserved.
+ when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(
+ getSubAddress(hotspotAddress.getAddress().getAddress()));
+ final LinkAddress usbAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mUsbIpServer, false /* useLastAddress */);
+ final IpPrefix usbPrefix = asIpPrefix(usbAddress);
+ assertNotEquals(asIpPrefix(mBluetoothAddress), usbPrefix);
+ assertNotEquals(hotspotPrefix, usbPrefix);
+ mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer);
+
+ // - Test wifi p2p prefix is reserved.
+ when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(
+ getSubAddress(mLegacyWifiP2pAddress.getAddress().getAddress()));
+ final LinkAddress etherAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mEthernetIpServer, false /* useLastAddress */);
+ final IpPrefix etherPrefix = asIpPrefix(etherAddress);
+ assertNotEquals(asIpPrefix(mLegacyWifiP2pAddress), etherPrefix);
+ assertNotEquals(asIpPrefix(mBluetoothAddress), etherPrefix);
+ assertNotEquals(hotspotPrefix, etherPrefix);
+ mPrivateAddressCoordinator.releaseDownstream(mEthernetIpServer);
}
@Test
- public void testNoConflictDownstreamPrefix() throws Exception {
+ public void testRequestLastDownstreamAddress() throws Exception {
final int fakeHotspotSubAddr = 0x2b05;
final IpPrefix predefinedPrefix = new IpPrefix("192.168.43.0/24");
when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr);
- LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer);
- final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address);
- assertEquals("Wrong wifi prefix: ", predefinedPrefix, hotspotPrefix);
- when(mHotspotIpServer.getAddress()).thenReturn(address);
+ final LinkAddress hotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mHotspotIpServer, true /* useLastAddress */);
+ assertEquals("Wrong wifi prefix: ", predefinedPrefix, asIpPrefix(hotspotAddress));
+ when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddress);
- address = mPrivateAddressCoordinator.requestDownstreamAddress(
- mUsbIpServer);
- final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(address);
- assertNotEquals(predefinedPrefix, usbPrefix);
+ final LinkAddress usbAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mUsbIpServer, true /* useLastAddress */);
+ assertNotEquals(predefinedPrefix, asIpPrefix(usbAddress));
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
mPrivateAddressCoordinator.releaseDownstream(mUsbIpServer);
- address = mPrivateAddressCoordinator.requestDownstreamAddress(
- mUsbIpServer);
- final IpPrefix allowUseFreePrefix = PrefixUtils.asIpPrefix(address);
- assertEquals("Fail to reselect available prefix: ", predefinedPrefix, allowUseFreePrefix);
+
+ final int newFakeSubAddr = 0x3c05;
+ when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr);
+
+ final LinkAddress newHotspotAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mHotspotIpServer, true /* useLastAddress */);
+ assertEquals(hotspotAddress, newHotspotAddress);
+ final LinkAddress newUsbAddress = mPrivateAddressCoordinator.requestDownstreamAddress(
+ mUsbIpServer, true /* useLastAddress */);
+ assertEquals(usbAddress, newUsbAddress);
}
private UpstreamNetworkState buildUpstreamNetworkState(final Network network,
@@ -215,12 +236,13 @@ public final class PrivateAddressCoordinatorTest {
when(mPrivateAddressCoordinator.getRandomSubAddr()).thenReturn(fakeHotspotSubAddr);
// - Enable hotspot with prefix 192.168.43.0/24
final LinkAddress hotspotAddr = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer);
- final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(hotspotAddr);
+ mHotspotIpServer, true /* useLastAddress */);
+ final IpPrefix hotspotPrefix = asIpPrefix(hotspotAddr);
assertEquals("Wrong wifi prefix: ", predefinedPrefix, hotspotPrefix);
when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr);
- // - test mobile network with null NetworkCapabilities. Ideally this should not happen,
- // just make sure no crash in this case.
+ // - test mobile network with null NetworkCapabilities. Ideally this should not happen
+ // because NetworkCapabilities update should always happen before LinkProperties update
+ // and the UpstreamNetworkState update, just make sure no crash in this case.
final UpstreamNetworkState noCapUpstream = buildUpstreamNetworkState(mMobileNetwork,
new LinkAddress("10.0.0.8/24"), null, null);
mPrivateAddressCoordinator.updateUpstreamPrefix(noCapUpstream);
@@ -269,24 +291,24 @@ public final class PrivateAddressCoordinatorTest {
// - Restart hotspot again and its prefix is different previous.
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
final LinkAddress hotspotAddr2 = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer);
- final IpPrefix hotspotPrefix2 = PrefixUtils.asIpPrefix(hotspotAddr2);
+ mHotspotIpServer, true /* useLastAddress */);
+ final IpPrefix hotspotPrefix2 = asIpPrefix(hotspotAddr2);
assertNotEquals(hotspotPrefix, hotspotPrefix2);
when(mHotspotIpServer.getAddress()).thenReturn(hotspotAddr2);
mPrivateAddressCoordinator.updateUpstreamPrefix(v4OnlyWifi);
verify(mHotspotIpServer, never()).sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
// - Usb tethering can be enabled and its prefix is different with conflict one.
final LinkAddress usbAddr = mPrivateAddressCoordinator.requestDownstreamAddress(
- mUsbIpServer);
- final IpPrefix usbPrefix = PrefixUtils.asIpPrefix(usbAddr);
+ mUsbIpServer, true /* useLastAddress */);
+ final IpPrefix usbPrefix = asIpPrefix(usbAddr);
assertNotEquals(predefinedPrefix, usbPrefix);
assertNotEquals(hotspotPrefix2, usbPrefix);
when(mUsbIpServer.getAddress()).thenReturn(usbAddr);
// - Disable wifi upstream, then wifi's prefix can be selected again.
mPrivateAddressCoordinator.removeUpstreamPrefix(mWifiNetwork);
final LinkAddress ethAddr = mPrivateAddressCoordinator.requestDownstreamAddress(
- mEthernetIpServer);
- final IpPrefix ethPrefix = PrefixUtils.asIpPrefix(ethAddr);
+ mEthernetIpServer, true /* useLastAddress */);
+ final IpPrefix ethPrefix = asIpPrefix(ethAddr);
assertEquals(predefinedPrefix, ethPrefix);
}
@@ -299,9 +321,9 @@ public final class PrivateAddressCoordinatorTest {
private void assertReseveredWifiP2pPrefix() throws Exception {
LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
- mHotspotIpServer);
- final IpPrefix hotspotPrefix = PrefixUtils.asIpPrefix(address);
- final IpPrefix legacyWifiP2pPrefix = PrefixUtils.asIpPrefix(mLegacyWifiP2pAddress);
+ mHotspotIpServer, true /* useLastAddress */);
+ final IpPrefix hotspotPrefix = asIpPrefix(address);
+ final IpPrefix legacyWifiP2pPrefix = asIpPrefix(mLegacyWifiP2pAddress);
assertNotEquals(legacyWifiP2pPrefix, hotspotPrefix);
mPrivateAddressCoordinator.releaseDownstream(mHotspotIpServer);
}
@@ -319,7 +341,7 @@ public final class PrivateAddressCoordinatorTest {
// If #shouldEnableWifiP2pDedicatedIp() is enabled, wifi P2P gets the configured address.
LinkAddress address = mPrivateAddressCoordinator.requestDownstreamAddress(
- mWifiP2pIpServer);
+ mWifiP2pIpServer, true /* useLastAddress */);
assertEquals(mLegacyWifiP2pAddress, address);
mPrivateAddressCoordinator.releaseDownstream(mWifiP2pIpServer);
}
diff --git a/services/Android.bp b/services/Android.bp
index 25a0d7e06b22..a68923619191 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -5,6 +5,7 @@ java_defaults {
],
errorprone: {
javacflags: [
+ "-Xep:AndroidFrameworkBinderIdentity:ERROR",
"-Xep:AndroidFrameworkCompatChange:ERROR",
"-Xep:AndroidFrameworkUid:ERROR",
],
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index ae33f0c3da9c..9ddf7a4fb79b 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2073,9 +2073,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
private void updateAccessibilityEnabledSettingLocked(AccessibilityUserState userState) {
- final long identity = Binder.clearCallingIdentity();
final boolean isA11yEnabled = mUiAutomationManager.isUiAutomationRunningLocked()
|| userState.isHandlingAccessibilityEventsLocked();
+ final long identity = Binder.clearCallingIdentity();
try {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_ENABLED,
@@ -2384,8 +2384,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
int numServices = services.size();
for (int i = 0; i < numServices; i++) {
if (services.get(i).isCapturingFingerprintGestures()) {
- final long identity = Binder.clearCallingIdentity();
IFingerprintService service = null;
+ final long identity = Binder.clearCallingIdentity();
try {
service = IFingerprintService.Stub.asInterface(
ServiceManager.getService(Context.FINGERPRINT_SERVICE));
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
index 41f32075fb77..d7664312e2e6 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
@@ -456,7 +456,7 @@ public class AccessibilitySecurityPolicy {
}
private boolean isShellAllowedToRetrieveWindowLocked(int userId, int windowId) {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
IBinder windowToken = mAccessibilityWindowManager
.getWindowTokenForUserAndWindowIdLocked(userId, windowId);
diff --git a/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java b/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java
index 96418aac7ffa..c9ec16edc54e 100644
--- a/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/FingerprintGestureDispatcher.java
@@ -118,7 +118,7 @@ public class FingerprintGestureDispatcher extends IFingerprintClientActiveCallba
public boolean isFingerprintGestureDetectionAvailable() {
if (!mHardwareSupportsGestures) return false;
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
return !mFingerprintService.isClientActive();
} catch (RemoteException re) {
@@ -173,7 +173,7 @@ public class FingerprintGestureDispatcher extends IFingerprintClientActiveCallba
@Override
public boolean handleMessage(Message message) {
if (message.what == MSG_REGISTER) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mFingerprintService.addClientActiveCallback(this);
mRegisteredReadOnlyExceptInHandler = true;
@@ -184,7 +184,7 @@ public class FingerprintGestureDispatcher extends IFingerprintClientActiveCallba
}
return false;
} else if (message.what == MSG_UNREGISTER) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mFingerprintService.removeClientActiveCallback(this);
} catch (RemoteException re) {
diff --git a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
index 35054991d3ff..eaf269415fdc 100644
--- a/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
+++ b/services/accessibility/java/com/android/server/accessibility/SystemActionPerformer.java
@@ -308,14 +308,15 @@ public class SystemActionPerformer {
private void sendDownAndUpKeyEvents(int keyCode) {
final long token = Binder.clearCallingIdentity();
-
- // Inject down.
- final long downTime = SystemClock.uptimeMillis();
- sendKeyEventIdentityCleared(keyCode, KeyEvent.ACTION_DOWN, downTime, downTime);
- sendKeyEventIdentityCleared(
- keyCode, KeyEvent.ACTION_UP, downTime, SystemClock.uptimeMillis());
-
- Binder.restoreCallingIdentity(token);
+ try {
+ // Inject down.
+ final long downTime = SystemClock.uptimeMillis();
+ sendKeyEventIdentityCleared(keyCode, KeyEvent.ACTION_DOWN, downTime, downTime);
+ sendKeyEventIdentityCleared(
+ keyCode, KeyEvent.ACTION_UP, downTime, SystemClock.uptimeMillis());
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
private void sendKeyEventIdentityCleared(int keyCode, int action, long downTime, long time) {
@@ -329,22 +330,24 @@ public class SystemActionPerformer {
private void expandNotifications() {
final long token = Binder.clearCallingIdentity();
-
- StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService(
- android.app.Service.STATUS_BAR_SERVICE);
- statusBarManager.expandNotificationsPanel();
-
- Binder.restoreCallingIdentity(token);
+ try {
+ StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService(
+ android.app.Service.STATUS_BAR_SERVICE);
+ statusBarManager.expandNotificationsPanel();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
private void expandQuickSettings() {
final long token = Binder.clearCallingIdentity();
-
- StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService(
- android.app.Service.STATUS_BAR_SERVICE);
- statusBarManager.expandSettingsPanel();
-
- Binder.restoreCallingIdentity(token);
+ try {
+ StatusBarManager statusBarManager = (StatusBarManager) mContext.getSystemService(
+ android.app.Service.STATUS_BAR_SERVICE);
+ statusBarManager.expandSettingsPanel();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
private boolean openRecents() {
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
index c583dcc2b1be..189a3908d6bf 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
@@ -79,6 +79,8 @@ public class FullScreenMagnificationController {
private final ScreenStateObserver mScreenStateObserver;
+ private final MagnificationRequestObserver mMagnificationRequestObserver;
+
private int mUserId;
private final long mMainThreadId;
@@ -479,6 +481,8 @@ public class FullScreenMagnificationController {
sendSpecToAnimation(mCurrentMagnificationSpec, animationCallback);
if (isMagnifying() && (id != INVALID_ID)) {
mIdOfLastServiceToMagnify = id;
+ mMagnificationRequestObserver.onRequestMagnificationSpec(mDisplayId,
+ mIdOfLastServiceToMagnify);
}
return changed;
}
@@ -609,22 +613,27 @@ public class FullScreenMagnificationController {
* FullScreenMagnificationController Constructor
*/
public FullScreenMagnificationController(@NonNull Context context,
- @NonNull AccessibilityManagerService ams, @NonNull Object lock) {
+ @NonNull AccessibilityManagerService ams, @NonNull Object lock,
+ @NonNull MagnificationRequestObserver magnificationRequestObserver) {
this(new ControllerContext(context, ams,
LocalServices.getService(WindowManagerInternal.class),
new Handler(context.getMainLooper()),
- context.getResources().getInteger(R.integer.config_longAnimTime)), lock);
+ context.getResources().getInteger(R.integer.config_longAnimTime)), lock,
+ magnificationRequestObserver);
}
/**
* Constructor for tests
*/
@VisibleForTesting
- public FullScreenMagnificationController(@NonNull ControllerContext ctx, @NonNull Object lock) {
+ public FullScreenMagnificationController(@NonNull ControllerContext ctx,
+ @NonNull Object lock,
+ @NonNull MagnificationRequestObserver magnificationRequestObserver) {
mControllerCtx = ctx;
mLock = lock;
mMainThreadId = mControllerCtx.getContext().getMainLooper().getThread().getId();
mScreenStateObserver = new ScreenStateObserver(mControllerCtx.getContext(), this);
+ mMagnificationRequestObserver = magnificationRequestObserver;
}
/**
@@ -1487,4 +1496,16 @@ public class FullScreenMagnificationController {
private static MagnificationAnimationCallback transformToStubCallback(boolean animate) {
return animate ? STUB_ANIMATION_CALLBACK : null;
}
+
+ interface MagnificationRequestObserver {
+
+ /**
+ * Called when the {@link MagnificationSpec} is changed with non-default
+ * scale by the service.
+ *
+ * @param displayId the logical display id
+ * @param serviceId the ID of the service requesting the change
+ */
+ void onRequestMagnificationSpec(int displayId, int serviceId);
+ }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
index 0dc5267c47f6..b3fc07a8ab9c 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java
@@ -128,6 +128,19 @@ public class MagnificationController {
setDisableMagnificationCallbackLocked(displayId, animationEndCallback);
}
+ void onRequestMagnificationSpec(int displayId, int serviceId) {
+ synchronized (mLock) {
+ if (serviceId == AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID) {
+ return;
+ }
+ if (mWindowMagnificationMgr == null
+ || !mWindowMagnificationMgr.isWindowMagnifierEnabled(displayId)) {
+ return;
+ }
+ mWindowMagnificationMgr.disableWindowMagnification(displayId, false);
+ }
+ }
+
/**
* Updates the active user ID of {@link FullScreenMagnificationController} and {@link
* WindowMagnificationManager}.
@@ -184,7 +197,7 @@ public class MagnificationController {
synchronized (mLock) {
if (mFullScreenMagnificationController == null) {
mFullScreenMagnificationController = new FullScreenMagnificationController(mContext,
- mAms, mLock);
+ mAms, mLock, this::onRequestMagnificationSpec);
mFullScreenMagnificationController.setUserId(mAms.getCurrentUserIdLocked());
}
}
diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
index 59ba82e4616a..e9a099ae43a9 100644
--- a/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
+++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionManagerService.java
@@ -189,7 +189,7 @@ public class AppPredictionManagerService extends
throw new SecurityException(msg);
}
- long origId = Binder.clearCallingIdentity();
+ final long origId = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
final AppPredictionPerUserService service = getServiceForUserLocked(userId);
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 060d0971e391..35312a3a2fac 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -630,8 +630,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
final long identity = Binder.clearCallingIdentity();
try {
if (provider.maskedBySuspendedPackage) {
- UserInfo userInfo = mUserManager.getUserInfo(providerUserId);
- showBadge = userInfo.isManagedProfile();
+ showBadge = mUserManager.hasBadge(providerUserId);
final String suspendingPackage = mPackageManagerInternal.getSuspendingPackage(
providerPackage, providerUserId);
if (PLATFORM_PACKAGE_NAME.equals(suspendingPackage)) {
@@ -2408,7 +2407,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
intent.setComponent(provider.info.provider);
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
provider.broadcast = PendingIntent.getBroadcastAsUser(mContext, 1, intent,
PendingIntent.FLAG_UPDATE_CURRENT, provider.info.getProfile());
@@ -3616,10 +3615,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
private boolean isProfileWithLockedParent(int userId) {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
UserInfo userInfo = mUserManager.getUserInfo(userId);
- if (userInfo != null && userInfo.isManagedProfile()) {
+ if (userInfo != null && userInfo.isProfile()) {
UserInfo parentInfo = mUserManager.getProfileParent(userId);
if (parentInfo != null
&& !isUserRunningAndUnlocked(parentInfo.getUserHandle().getIdentifier())) {
@@ -3634,7 +3633,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
private boolean isProfileWithUnlockedParent(int userId) {
UserInfo userInfo = mUserManager.getUserInfo(userId);
- if (userInfo != null && userInfo.isManagedProfile()) {
+ if (userInfo != null && userInfo.isProfile()) {
UserInfo parentInfo = mUserManager.getProfileParent(userId);
if (parentInfo != null
&& mUserManager.isUserUnlockingOrUnlocked(parentInfo.getUserHandle())) {
diff --git a/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java b/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java
index 0e99b34e9dd1..bcec9c665527 100644
--- a/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java
+++ b/services/backup/java/com/android/server/backup/BackupAgentTimeoutParameters.java
@@ -19,6 +19,7 @@ package com.android.server.backup;
import android.content.ContentResolver;
import android.os.Handler;
+import android.os.UserHandle;
import android.provider.Settings;
import android.util.KeyValueListParser;
import android.util.KeyValueSettingObserver;
@@ -53,10 +54,18 @@ public class BackupAgentTimeoutParameters extends KeyValueSettingObserver {
"restore_agent_timeout_millis";
@VisibleForTesting
+ public static final String SETTING_RESTORE_SYSTEM_AGENT_TIMEOUT_MILLIS =
+ "restore_system_agent_timeout_millis";
+
+ @VisibleForTesting
public static final String SETTING_RESTORE_AGENT_FINISHED_TIMEOUT_MILLIS =
"restore_agent_finished_timeout_millis";
@VisibleForTesting
+ public static final String SETTING_RESTORE_SESSION_TIMEOUT_MILLIS =
+ "restore_session_timeout_millis";
+
+ @VisibleForTesting
public static final String SETTING_QUOTA_EXCEEDED_TIMEOUT_MILLIS =
"quota_exceeded_timeout_millis";
@@ -71,9 +80,14 @@ public class BackupAgentTimeoutParameters extends KeyValueSettingObserver {
@VisibleForTesting public static final long DEFAULT_RESTORE_AGENT_TIMEOUT_MILLIS = 60 * 1000;
+ @VisibleForTesting public static final long DEFAULT_RESTORE_SYSTEM_AGENT_TIMEOUT_MILLIS =
+ 180 * 1000;
+
@VisibleForTesting
public static final long DEFAULT_RESTORE_AGENT_FINISHED_TIMEOUT_MILLIS = 30 * 1000;
+ @VisibleForTesting public static final long DEFAULT_RESTORE_SESSION_TIMEOUT_MILLIS = 60 * 1000;
+
@VisibleForTesting
public static final long DEFAULT_QUOTA_EXCEEDED_TIMEOUT_MILLIS = 3 * 1000;
@@ -90,6 +104,12 @@ public class BackupAgentTimeoutParameters extends KeyValueSettingObserver {
private long mRestoreAgentTimeoutMillis;
@GuardedBy("mLock")
+ private long mRestoreSystemAgentTimeoutMillis;
+
+ @GuardedBy("mLock")
+ private long mRestoreSessionTimeoutMillis;
+
+ @GuardedBy("mLock")
private long mRestoreAgentFinishedTimeoutMillis;
@GuardedBy("mLock")
@@ -123,10 +143,18 @@ public class BackupAgentTimeoutParameters extends KeyValueSettingObserver {
parser.getLong(
SETTING_RESTORE_AGENT_TIMEOUT_MILLIS,
DEFAULT_RESTORE_AGENT_TIMEOUT_MILLIS);
+ mRestoreSystemAgentTimeoutMillis =
+ parser.getLong(
+ SETTING_RESTORE_SYSTEM_AGENT_TIMEOUT_MILLIS,
+ DEFAULT_RESTORE_SYSTEM_AGENT_TIMEOUT_MILLIS);
mRestoreAgentFinishedTimeoutMillis =
parser.getLong(
SETTING_RESTORE_AGENT_FINISHED_TIMEOUT_MILLIS,
DEFAULT_RESTORE_AGENT_FINISHED_TIMEOUT_MILLIS);
+ mRestoreSessionTimeoutMillis =
+ parser.getLong(
+ SETTING_RESTORE_SESSION_TIMEOUT_MILLIS,
+ DEFAULT_RESTORE_SESSION_TIMEOUT_MILLIS);
mQuotaExceededTimeoutMillis =
parser.getLong(
SETTING_QUOTA_EXCEEDED_TIMEOUT_MILLIS,
@@ -152,9 +180,20 @@ public class BackupAgentTimeoutParameters extends KeyValueSettingObserver {
}
}
- public long getRestoreAgentTimeoutMillis() {
+ /**
+ * @param applicationUid UID of the application for which to get restore timeout
+ * @return restore timeout in milliseconds
+ */
+ public long getRestoreAgentTimeoutMillis(int applicationUid) {
+ synchronized (mLock) {
+ return UserHandle.isCore(applicationUid) ? mRestoreSystemAgentTimeoutMillis :
+ mRestoreAgentTimeoutMillis;
+ }
+ }
+
+ public long getRestoreSessionTimeoutMillis() {
synchronized (mLock) {
- return mRestoreAgentTimeoutMillis;
+ return mRestoreSessionTimeoutMillis;
}
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 186812bc15c7..75bbec67c66e 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -478,7 +478,7 @@ public class BackupManagerService extends IBackupManager.Stub {
if (getUserManager().isUserUnlocked(userId)) {
// Clear calling identity as initialization enforces the system identity but we
// can be coming from shell.
- long oldId = Binder.clearCallingIdentity();
+ final long oldId = Binder.clearCallingIdentity();
try {
startServiceForUser(userId);
} finally {
@@ -1412,8 +1412,8 @@ public class BackupManagerService extends IBackupManager.Stub {
return null;
}
int callingUserId = Binder.getCallingUserHandle().getIdentifier();
- long oldId = Binder.clearCallingIdentity();
final int[] userIds;
+ final long oldId = Binder.clearCallingIdentity();
try {
userIds = getUserManager().getProfileIds(callingUserId, false);
} finally {
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index e68c07ed73f7..aa8532b67c43 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -2889,16 +2889,18 @@ public class UserBackupManagerService {
mBackupHandler.sendMessageDelayed(msg, TRANSPORT_RETRY_INTERVAL);
return;
}
- long oldId = Binder.clearCallingIdentity();
- OnTaskFinishedListener listener =
- caller ->
- mTransportManager.disposeOfTransportClient(transportClient, caller);
- mWakelock.acquire();
- Message msg = mBackupHandler.obtainMessage(
- MSG_RUN_CLEAR,
- new ClearParams(transportClient, info, listener));
- mBackupHandler.sendMessage(msg);
- Binder.restoreCallingIdentity(oldId);
+ final long oldId = Binder.clearCallingIdentity();
+ try {
+ OnTaskFinishedListener listener = caller -> mTransportManager
+ .disposeOfTransportClient(transportClient, caller);
+ mWakelock.acquire();
+ Message msg = mBackupHandler.obtainMessage(
+ MSG_RUN_CLEAR,
+ new ClearParams(transportClient, info, listener));
+ mBackupHandler.sendMessage(msg);
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
+ }
}
}
}
@@ -2910,7 +2912,7 @@ public class UserBackupManagerService {
public void backupNow() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "backupNow");
- long oldId = Binder.clearCallingIdentity();
+ final long oldId = Binder.clearCallingIdentity();
try {
final PowerSaveState result =
mPowerManager.getPowerSaveState(ServiceType.KEYVALUE_BACKUP);
@@ -2999,7 +3001,7 @@ public class UserBackupManagerService {
}
}
- long oldId = Binder.clearCallingIdentity();
+ final long oldId = Binder.clearCallingIdentity();
try {
if (!mSetupComplete) {
Slog.i(TAG, addUserIdToLogMessage(mUserId, "Backup not supported before setup"));
@@ -3156,7 +3158,7 @@ public class UserBackupManagerService {
throw new IllegalStateException("Restore supported only for the device owner");
}
- long oldId = Binder.clearCallingIdentity();
+ final long oldId = Binder.clearCallingIdentity();
try {
if (!mSetupComplete) {
@@ -3287,7 +3289,7 @@ public class UserBackupManagerService {
mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
"acknowledgeAdbBackupOrRestore");
- long oldId = Binder.clearCallingIdentity();
+ final long oldId = Binder.clearCallingIdentity();
try {
AdbParams params;
@@ -3348,7 +3350,7 @@ public class UserBackupManagerService {
Slog.i(TAG, addUserIdToLogMessage(mUserId, "Backup enabled => " + enable));
- long oldId = Binder.clearCallingIdentity();
+ final long oldId = Binder.clearCallingIdentity();
try {
boolean wasEnabled = mEnabled;
synchronized (this) {
@@ -3477,7 +3479,7 @@ public class UserBackupManagerService {
public ComponentName getCurrentTransportComponent() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BACKUP, "getCurrentTransportComponent");
- long oldId = Binder.clearCallingIdentity();
+ final long oldId = Binder.clearCallingIdentity();
try {
return mTransportManager.getCurrentTransportComponent();
} catch (TransportNotRegisteredException e) {
@@ -4088,7 +4090,7 @@ public class UserBackupManagerService {
mActiveRestoreSession = new ActiveRestoreSession(this, packageName, transport,
getEligibilityRulesForOperation(operationType));
mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT,
- mAgentTimeoutParameters.getRestoreAgentTimeoutMillis());
+ mAgentTimeoutParameters.getRestoreSessionTimeoutMillis());
}
return mActiveRestoreSession;
}
@@ -4165,7 +4167,7 @@ public class UserBackupManagerService {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BACKUP, "isAppEligibleForBackup");
- long oldToken = Binder.clearCallingIdentity();
+ final long oldToken = Binder.clearCallingIdentity();
try {
String callerLogString = "BMS.isAppEligibleForBackup";
TransportClient transportClient =
@@ -4187,7 +4189,7 @@ public class UserBackupManagerService {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BACKUP, "filterAppsEligibleForBackup");
- long oldToken = Binder.clearCallingIdentity();
+ final long oldToken = Binder.clearCallingIdentity();
try {
String callerLogString = "BMS.filterAppsEligibleForBackup";
TransportClient transportClient =
@@ -4221,7 +4223,7 @@ public class UserBackupManagerService {
/** Prints service state for 'dumpsys backup'. */
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- long identityToken = Binder.clearCallingIdentity();
+ final long identityToken = Binder.clearCallingIdentity();
try {
if (args != null) {
for (String arg : args) {
diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
index 100dbae9f01d..1cb7c11e9499 100644
--- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java
+++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
@@ -390,7 +390,7 @@ public class BackupHandler extends Handler {
// Done: reset the session timeout clock
removeMessages(MSG_RESTORE_SESSION_TIMEOUT);
sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT,
- mAgentTimeoutParameters.getRestoreAgentTimeoutMillis());
+ mAgentTimeoutParameters.getRestoreSessionTimeoutMillis());
params.listener.onFinished(callerLogString);
}
diff --git a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
index 3102b5f4a04d..602dc24541b2 100644
--- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
+++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
@@ -98,7 +98,7 @@ public class ActiveRestoreSession extends IRestoreSession.Stub {
return -1;
}
- long oldId = Binder.clearCallingIdentity();
+ final long oldId = Binder.clearCallingIdentity();
try {
TransportClient transportClient =
mTransportManager.getTransportClient(
@@ -173,7 +173,7 @@ public class ActiveRestoreSession extends IRestoreSession.Stub {
synchronized (mBackupManagerService.getQueueLock()) {
for (int i = 0; i < mRestoreSets.length; i++) {
if (token == mRestoreSets[i].token) {
- long oldId = Binder.clearCallingIdentity();
+ final long oldId = Binder.clearCallingIdentity();
try {
return sendRestoreToHandlerLocked(
(transportClient, listener) ->
@@ -265,7 +265,7 @@ public class ActiveRestoreSession extends IRestoreSession.Stub {
synchronized (mBackupManagerService.getQueueLock()) {
for (int i = 0; i < mRestoreSets.length; i++) {
if (token == mRestoreSets[i].token) {
- long oldId = Binder.clearCallingIdentity();
+ final long oldId = Binder.clearCallingIdentity();
try {
return sendRestoreToHandlerLocked(
(transportClient, listener) ->
@@ -341,7 +341,7 @@ public class ActiveRestoreSession extends IRestoreSession.Stub {
}
// So far so good; we're allowed to try to restore this package.
- long oldId = Binder.clearCallingIdentity();
+ final long oldId = Binder.clearCallingIdentity();
try {
// Check whether there is data for it in the current dataset, falling back
// to the ancestral dataset if not.
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index 16077cb6082f..5718bdfc4971 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -403,7 +403,8 @@ public class FullRestoreEngine extends RestoreEngine {
final boolean isSharedStorage = pkg.equals(SHARED_BACKUP_AGENT_PACKAGE);
final long timeout = isSharedStorage ?
mAgentTimeoutParameters.getSharedBackupAgentTimeoutMillis() :
- mAgentTimeoutParameters.getRestoreAgentTimeoutMillis();
+ mAgentTimeoutParameters.getRestoreAgentTimeoutMillis(
+ mTargetApp.uid);
try {
mBackupManagerService.prepareOperationTimeout(token,
timeout,
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index abf11bd542a1..261ebe69a15e 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -46,6 +46,7 @@ import android.content.pm.PackageManagerInternal;
import android.os.Bundle;
import android.os.Message;
import android.os.ParcelFileDescriptor;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -433,6 +434,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// Pull the Package Manager metadata from the restore set first
mCurrentPackage = new PackageInfo();
mCurrentPackage.packageName = PACKAGE_MANAGER_SENTINEL;
+ mCurrentPackage.applicationInfo = new ApplicationInfo();
+ mCurrentPackage.applicationInfo.uid = Process.SYSTEM_UID;
mPmAgent = backupManagerService.makeMetadataAgent(null);
mAgent = IBackupAgent.Stub.asInterface(mPmAgent.onBind());
if (MORE_DEBUG) {
@@ -760,7 +763,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// Kick off the restore, checking for hung agents. The timeout or
// the operationComplete() callback will schedule the next step,
// so we do not do that here.
- long restoreAgentTimeoutMillis = mAgentTimeoutParameters.getRestoreAgentTimeoutMillis();
+ long restoreAgentTimeoutMillis = mAgentTimeoutParameters.getRestoreAgentTimeoutMillis(
+ app.applicationInfo.uid);
backupManagerService.prepareOperationTimeout(
mEphemeralOpToken, restoreAgentTimeoutMillis, this, OP_TYPE_RESTORE_WAIT);
startedAgentRestore = true;
@@ -1122,7 +1126,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
} else {
// We were invoked via an active restore session, not by the Package
// Manager, so start up the session timeout again.
- long restoreAgentTimeoutMillis = mAgentTimeoutParameters.getRestoreAgentTimeoutMillis();
+ long restoreAgentTimeoutMillis =
+ mAgentTimeoutParameters.getRestoreSessionTimeoutMillis();
backupManagerService.getBackupHandler().sendEmptyMessageDelayed(
MSG_RESTORE_SESSION_TIMEOUT,
restoreAgentTimeoutMillis);
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 40b171869cf2..61570043de16 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -408,7 +408,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
PackageItemInfo.SAFE_LABEL_FLAG_TRIM
| PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE)
.toString());
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
return PendingIntent.getActivityAsUser(getContext(),
0 /* request code */,
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 0c56d46151c1..43c54b4a97b3 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -76,6 +76,7 @@ public abstract class PackageManagerInternal {
public static final int PACKAGE_COMPANION = 14;
public static final int PACKAGE_RETAIL_DEMO = 15;
public static final int PACKAGE_OVERLAY_CONFIG_SIGNATURE = 16;
+ public static final int LAST_KNOWN_PACKAGE = PACKAGE_OVERLAY_CONFIG_SIGNATURE;
@IntDef(flag = true, prefix = "RESOLVE_", value = {
RESOLVE_NON_BROWSER_ONLY,
@@ -1016,6 +1017,51 @@ public abstract class PackageManagerInternal {
@NonNull InstalledLoadingProgressCallback callback);
/**
+ * Returns the string representation of a known package. For example,
+ * {@link #PACKAGE_SETUP_WIZARD} is represented by the string Setup Wizard.
+ *
+ * @param knownPackage The known package.
+ * @return The string representation.
+ */
+ public static @NonNull String knownPackageToString(@KnownPackage int knownPackage) {
+ switch (knownPackage) {
+ case PACKAGE_SYSTEM:
+ return "System";
+ case PACKAGE_SETUP_WIZARD:
+ return "Setup Wizard";
+ case PACKAGE_INSTALLER:
+ return "Installer";
+ case PACKAGE_VERIFIER:
+ return "Verifier";
+ case PACKAGE_BROWSER:
+ return "Browser";
+ case PACKAGE_SYSTEM_TEXT_CLASSIFIER:
+ return "System Text Classifier";
+ case PACKAGE_PERMISSION_CONTROLLER:
+ return "Permission Controller";
+ case PACKAGE_WELLBEING:
+ return "Wellbeing";
+ case PACKAGE_DOCUMENTER:
+ return "Documenter";
+ case PACKAGE_CONFIGURATOR:
+ return "Configurator";
+ case PACKAGE_INCIDENT_REPORT_APPROVER:
+ return "Incident Report Approver";
+ case PACKAGE_APP_PREDICTOR:
+ return "App Predictor";
+ case PACKAGE_WIFI:
+ return "Wi-Fi";
+ case PACKAGE_COMPANION:
+ return "Companion";
+ case PACKAGE_RETAIL_DEMO:
+ return "Retail Demo";
+ case PACKAGE_OVERLAY_CONFIG_SIGNATURE:
+ return "Overlay Config Signature";
+ }
+ return "Unknown";
+ }
+
+ /**
* Callback to listen for loading progress of a package installed on Incremental File System.
*/
public abstract static class InstalledLoadingProgressCallback {
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index d92706d2dd19..9455051ad740 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -916,7 +916,7 @@ public final class BatteryService extends SystemService {
mHealthInfo.chargerAcOnline = false;
mHealthInfo.chargerUsbOnline = false;
mHealthInfo.chargerWirelessOnline = false;
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
mUpdatesStopped = true;
processValuesFromShellLocked(pw, opts);
@@ -979,7 +979,7 @@ public final class BatteryService extends SystemService {
break;
}
if (update) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
mUpdatesStopped = true;
processValuesFromShellLocked(pw, opts);
@@ -996,7 +996,7 @@ public final class BatteryService extends SystemService {
int opts = parseOptions(shell);
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.DEVICE_POWER, null);
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
if (mUpdatesStopped) {
mUpdatesStopped = false;
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 4e405cc7f7ea..011231c016e2 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -604,7 +604,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
Slog.d(TAG, "Persisting Bluetooth Setting: " + value);
}
// waive WRITE_SECURE_SETTINGS permission check
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.BLUETOOTH_ON, value);
Binder.restoreCallingIdentity(callingIdentity);
}
@@ -2378,7 +2378,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
int foregroundUser;
int callingUser = UserHandle.getCallingUserId();
int callingUid = Binder.getCallingUid();
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
UserInfo ui = um.getProfileParent(callingUser);
int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL;
@@ -2605,7 +2605,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
private boolean isBluetoothDisallowed() {
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
return mContext.getSystemService(UserManager.class)
.hasUserRestriction(UserManager.DISALLOW_BLUETOOTH, UserHandle.SYSTEM);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 8a1baf25481b..b59f7645445d 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1126,7 +1126,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Listen to package add and removal events for all users.
intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addDataScheme("package");
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java
index 1804b7f66fa2..593c406ed47b 100644
--- a/services/core/java/com/android/server/MmsServiceBroker.java
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -511,7 +511,7 @@ public class MmsServiceBroker extends SystemService {
contentUri = ContentProvider.maybeAddUserId(contentUri, callingUserId);
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
final UriGrantsManagerInternal ugm = LocalServices
.getService(UriGrantsManagerInternal.class);
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 7775354a8077..ab933a8c2be8 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1742,7 +1742,7 @@ class StorageManagerService extends IStorageManager.Stub
UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
final int callingUserId = UserHandle.getCallingUserId();
boolean isAdmin;
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
isAdmin = um.getUserInfo(callingUserId).isAdmin();
} finally {
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index ba2e147a2acf..b6a3e234ebe9 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -2418,7 +2418,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
public static final String ACTION_SIGNAL_STRENGTH_CHANGED = "android.intent.action.SIG_STR";
private void broadcastServiceStateChanged(ServiceState state, int phoneId, int subId) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
mBatteryStats.notePhoneState(state.getState());
} catch (RemoteException re) {
@@ -2442,7 +2442,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
private void broadcastSignalStrengthChanged(SignalStrength signalStrength, int phoneId,
int subId) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
mBatteryStats.notePhoneSignalStrength(signalStrength);
} catch (RemoteException e) {
@@ -2487,7 +2487,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
*/
private void broadcastCallStateChanged(int state, String incomingNumber, int phoneId,
int subId) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
if (state == TelephonyManager.CALL_STATE_IDLE) {
mBatteryStats.notePhoneOff();
@@ -2676,7 +2676,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
private boolean validateEventsAndUserLocked(Record r, int events) {
int foregroundUser;
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
boolean valid = false;
try {
foregroundUser = ActivityManager.getCurrentUser();
diff --git a/services/core/java/com/android/server/UpdateLockService.java b/services/core/java/com/android/server/UpdateLockService.java
index 06f73e28829e..38bbbdf742df 100644
--- a/services/core/java/com/android/server/UpdateLockService.java
+++ b/services/core/java/com/android/server/UpdateLockService.java
@@ -74,7 +74,7 @@ public class UpdateLockService extends IUpdateLock.Stub {
void sendLockChangedBroadcast(boolean state) {
// Safe early during boot because this broadcast only goes to registered receivers.
- long oldIdent = Binder.clearCallingIdentity();
+ final long oldIdent = Binder.clearCallingIdentity();
try {
Intent intent = new Intent(UpdateLock.UPDATE_LOCK_CHANGED)
.putExtra(UpdateLock.NOW_IS_CONVENIENT, state)
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index cb6f616f5078..0c34744c11b9 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -151,7 +151,7 @@ public class VibratorService extends IVibratorService.Stub
private SettingsObserver mSettingObserver;
private final NativeWrapper mNativeWrapper;
- private volatile VibrateThread mThread;
+ private volatile VibrateWaveformThread mThread;
// mInputDeviceVibrators lock should be acquired after mLock, if both are
// to be acquired
@@ -259,8 +259,8 @@ public class VibratorService extends IVibratorService.Stub
private Vibration(IBinder token, VibrationEffect effect,
VibrationAttributes attrs, int uid, String opPkg, String reason) {
this.token = token;
- this.effect = effect;
this.id = mNextVibrationId.getAndIncrement();
+ this.effect = effect;
this.startTime = SystemClock.elapsedRealtime();
this.startTimeDebug = System.currentTimeMillis();
this.attrs = attrs;
@@ -845,7 +845,7 @@ public class VibratorService extends IVibratorService.Stub
return;
}
linkVibration(vib);
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
doCancelVibrateLocked();
startVibrationLocked(vib);
@@ -897,7 +897,7 @@ public class VibratorService extends IVibratorService.Stub
if (DEBUG) {
Slog.d(TAG, "Canceling vibration.");
}
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
doCancelVibrateLocked();
} finally {
@@ -962,13 +962,11 @@ public class VibratorService extends IVibratorService.Stub
mCurrentVibration = vib;
if (vib.effect instanceof VibrationEffect.OneShot) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
- VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
- doVibratorOn(oneShot.getDuration(), oneShot.getAmplitude(), vib);
+ doVibratorOn(vib);
} else if (vib.effect instanceof VibrationEffect.Waveform) {
// mThread better be null here. doCancelVibrate should always be
// called before startNextVibrationLocked or startVibrationLocked.
- VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
- mThread = new VibrateThread(waveform, vib.uid, vib.attrs);
+ mThread = new VibrateWaveformThread(vib);
mThread.start();
} else if (vib.effect instanceof VibrationEffect.Prebaked) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
@@ -1070,7 +1068,7 @@ public class VibratorService extends IVibratorService.Stub
private int getAppOpMode(int uid, String packageName, VibrationAttributes attrs) {
int mode = mAppOps.checkAudioOpNoThrow(AppOpsManager.OP_VIBRATE,
- attrs.getAudioAttributes().getUsage(), uid, packageName);
+ attrs.getAudioUsage(), uid, packageName);
if (mode == AppOpsManager.MODE_ALLOWED) {
mode = mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, uid, packageName);
}
@@ -1271,41 +1269,29 @@ public class VibratorService extends IVibratorService.Stub
return mNativeWrapper.vibratorExists();
}
- /** Vibrates with native callback trigger for {@link #onVibrationComplete(long)}. */
- private void doVibratorOn(long millis, int amplitude, Vibration vib) {
- doVibratorOn(millis, amplitude, vib.uid, vib.attrs, vib.id);
- }
-
- /** Vibrates without native callback. */
- private void doVibratorOn(long millis, int amplitude, int uid, VibrationAttributes attrs) {
- doVibratorOn(millis, amplitude, uid, attrs, /* vibrationId= */ 0);
- }
-
- private void doVibratorOn(long millis, int amplitude, int uid, VibrationAttributes attrs,
- long vibrationId) {
+ private void doVibratorOn(Vibration vib) {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn");
try {
synchronized (mInputDeviceVibrators) {
- if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) {
- amplitude = mDefaultVibrationAmplitude;
- }
+ final VibrationEffect.OneShot oneShot =
+ (VibrationEffect.OneShot) vib.effect.resolve(mDefaultVibrationAmplitude);
if (DEBUG) {
- Slog.d(TAG, "Turning vibrator on for " + millis + " ms" +
- " with amplitude " + amplitude + ".");
+ Slog.d(TAG, "Turning vibrator on for " + oneShot.getDuration() + " ms"
+ + " with amplitude " + oneShot.getAmplitude() + ".");
}
- noteVibratorOnLocked(uid, millis);
+ noteVibratorOnLocked(vib.uid, oneShot.getDuration());
final int vibratorCount = mInputDeviceVibrators.size();
if (vibratorCount != 0) {
for (int i = 0; i < vibratorCount; i++) {
- Vibrator inputDeviceVibrator = mInputDeviceVibrators.get(i);
- inputDeviceVibrator.vibrate(millis, attrs.getAudioAttributes());
+ mInputDeviceVibrators.get(i).vibrate(vib.uid, vib.opPkg, oneShot,
+ vib.reason, vib.attrs);
}
} else {
// Note: ordering is important here! Many haptic drivers will reset their
// amplitude when enabled, so we always have to enable first, then set the
// amplitude.
- mNativeWrapper.vibratorOn(millis, vibrationId);
- doVibratorSetAmplitude(amplitude);
+ mNativeWrapper.vibratorOn(oneShot.getDuration(), vib.id);
+ doVibratorSetAmplitude(oneShot.getAmplitude());
}
}
} finally {
@@ -1585,18 +1571,17 @@ public class VibratorService extends IVibratorService.Stub
}
/** Thread that plays a single {@link VibrationEffect.Waveform}. */
- private class VibrateThread extends Thread {
+ private class VibrateWaveformThread extends Thread {
private final VibrationEffect.Waveform mWaveform;
- private final int mUid;
- private final VibrationAttributes mAttrs;
+ private final Vibration mVibration;
private boolean mForceStop;
- VibrateThread(VibrationEffect.Waveform waveform, int uid, VibrationAttributes attrs) {
- mWaveform = waveform;
- mUid = uid;
- mAttrs = attrs;
- mTmpWorkSource.set(uid);
+ VibrateWaveformThread(Vibration vib) {
+ mWaveform = (VibrationEffect.Waveform) vib.effect;
+ mVibration = new Vibration(vib.token, /* effect= */ null, vib.attrs, vib.uid, vib.opPkg,
+ vib.reason);
+ mTmpWorkSource.set(vib.uid);
mWakeLock.setWorkSource(mTmpWorkSource);
}
@@ -1670,7 +1655,9 @@ public class VibratorService extends IVibratorService.Stub
// appropriate intervals.
onDuration = getTotalOnDuration(timings, amplitudes, index - 1,
repeat);
- doVibratorOn(onDuration, amplitude, mUid, mAttrs);
+ mVibration.effect =
+ VibrationEffect.createOneShot(onDuration, amplitude);
+ doVibratorOn(mVibration);
} else {
doVibratorSetAmplitude(amplitude);
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index aaff831aeb96..9a94e4efdfe3 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -477,7 +477,7 @@ public class AccountManagerService
* TODO: Only allow accounts that were shared to be added by a limited user.
*/
// fails if the account already exists
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
return addAccountInternal(accounts, account, password, extras, callingUid,
@@ -506,7 +506,7 @@ public class AccountManagerService
managedTypes.add(accountType);
}
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
return getAccountsAndVisibilityForPackage(packageName, managedTypes, callingUid,
@@ -555,7 +555,7 @@ public class AccountManagerService
throw new SecurityException(msg);
}
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
synchronized (accounts.dbLock) {
@@ -604,7 +604,7 @@ public class AccountManagerService
account.type);
throw new SecurityException(msg);
}
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
if (AccountManager.PACKAGE_NAME_KEY_LEGACY_VISIBLE.equals(packageName)) {
@@ -664,7 +664,7 @@ public class AccountManagerService
Objects.requireNonNull(packageName, "packageName cannot be null");
int uid = -1;
try {
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
uid = mPackageManager.getPackageUidAsUser(packageName, accounts.userId);
} finally {
@@ -736,7 +736,7 @@ public class AccountManagerService
*/
private boolean isPreOApplication(String packageName) {
try {
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
ApplicationInfo applicationInfo;
try {
applicationInfo = mPackageManager.getApplicationInfo(packageName, 0);
@@ -769,7 +769,7 @@ public class AccountManagerService
account.type);
throw new SecurityException(msg);
}
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
return setAccountVisibility(account, packageName, newVisibility, true /* notify */,
@@ -883,7 +883,7 @@ public class AccountManagerService
mAppOpsManager.checkPackage(callingUid, opPackageName);
int userId = UserHandle.getCallingUserId();
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
registerAccountListener(accountTypes, opPackageName, accounts);
@@ -916,7 +916,7 @@ public class AccountManagerService
int callingUid = Binder.getCallingUid();
mAppOpsManager.checkPackage(callingUid, opPackageName);
int userId = UserHandle.getCallingUserId();
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
unregisterAccountListener(accountTypes, opPackageName, accounts);
@@ -1033,7 +1033,7 @@ public class AccountManagerService
private boolean packageExistsForUser(String packageName, int userId) {
try {
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
mPackageManager.getPackageUidAsUser(packageName, userId);
return true;
@@ -1499,7 +1499,7 @@ public class AccountManagerService
account.type);
throw new SecurityException(msg);
}
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
return readPasswordInternal(accounts, account);
@@ -1534,7 +1534,7 @@ public class AccountManagerService
}
Objects.requireNonNull(account, "account cannot be null");
int userId = UserHandle.getCallingUserId();
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
return readPreviousNameInternal(accounts, account);
@@ -1584,7 +1584,7 @@ public class AccountManagerService
Log.w(TAG, "User " + userId + " data is locked. callingUid " + callingUid);
return null;
}
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
if (!accountExistsCache(accounts, account)) {
@@ -1679,7 +1679,7 @@ public class AccountManagerService
Slog.d(TAG, "Copying account " + account.toSafeString()
+ " from user " + userFrom + " to user " + userTo);
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
new Session(fromAccounts, response, account.type, false,
false /* stripAuthTokenFromResult */, account.name,
@@ -1737,7 +1737,7 @@ public class AccountManagerService
return false;
}
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
return updateLastAuthenticatedTime(account);
@@ -1759,7 +1759,7 @@ public class AccountManagerService
final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
final int parentUserId){
Bundle.setDefusable(accountCredentials, true);
- long id = clearCallingIdentity();
+ final long id = clearCallingIdentity();
try {
new Session(targetUser, response, account.type, false,
false /* stripAuthTokenFromResult */, account.name,
@@ -1926,7 +1926,7 @@ public class AccountManagerService
checkReadAccountsPermitted(callingUid, account.type, userId,
opPackageName);
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
new TestFeaturesSession(accounts, response, account, features).bind();
@@ -2010,7 +2010,7 @@ public class AccountManagerService
accountToRename.type);
throw new SecurityException(msg);
}
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName);
@@ -2193,7 +2193,7 @@ public class AccountManagerService
}
return;
}
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
UserAccounts accounts = getUserAccounts(userId);
cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
synchronized(accounts.credentialsPermissionNotificationIds) {
@@ -2250,7 +2250,7 @@ public class AccountManagerService
accountId,
accounts,
callingUid);
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
return removeAccountInternal(accounts, account, callingUid);
} finally {
@@ -2367,7 +2367,7 @@ public class AccountManagerService
}
}
}
- long id = Binder.clearCallingIdentity();
+ final long id = Binder.clearCallingIdentity();
try {
int parentUserId = accounts.userId;
if (canHaveProfile(parentUserId)) {
@@ -2413,7 +2413,7 @@ public class AccountManagerService
+ ", pid " + Binder.getCallingPid());
}
int userId = UserHandle.getCallingUserId();
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
List<Pair<Account, String>> deletedTokens;
@@ -2537,7 +2537,7 @@ public class AccountManagerService
+ callingUid);
return null;
}
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
return readAuthTokenInternal(accounts, account, authTokenType);
@@ -2565,7 +2565,7 @@ public class AccountManagerService
account.type);
throw new SecurityException(msg);
}
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
@@ -2591,7 +2591,7 @@ public class AccountManagerService
account.type);
throw new SecurityException(msg);
}
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
setPasswordInternal(accounts, account, password, callingUid);
@@ -2657,7 +2657,7 @@ public class AccountManagerService
account.type);
throw new SecurityException(msg);
}
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
setPasswordInternal(accounts, account, null, callingUid);
@@ -2685,7 +2685,7 @@ public class AccountManagerService
account.type);
throw new SecurityException(msg);
}
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
if (!accountExistsCache(accounts, account)) {
@@ -2771,7 +2771,7 @@ public class AccountManagerService
throw new SecurityException("can only call from system");
}
int userId = UserHandle.getUserId(callingUid);
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
new Session(accounts, response, accountType, false /* expectActivityLaunch */,
@@ -2843,7 +2843,7 @@ public class AccountManagerService
return;
}
int userId = UserHandle.getCallingUserId();
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
final UserAccounts accounts;
final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
try {
@@ -2865,11 +2865,11 @@ public class AccountManagerService
// Get the calling package. We will use it for the purpose of caching.
final String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
List<String> callerOwnedPackageNames;
- ident = Binder.clearCallingIdentity();
+ final long ident2 = Binder.clearCallingIdentity();
try {
callerOwnedPackageNames = Arrays.asList(mPackageManager.getPackagesForUid(callerUid));
} finally {
- Binder.restoreCallingIdentity(ident);
+ Binder.restoreCallingIdentity(ident2);
}
if (callerPkg == null || !callerOwnedPackageNames.contains(callerPkg)) {
String msg = String.format(
@@ -2887,7 +2887,7 @@ public class AccountManagerService
loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
}
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
// Distill the caller's package signatures into a single digest.
final byte[] callerPkgSigDigest = calculatePackageSignatureDigest(callerPkg);
@@ -3194,7 +3194,7 @@ public class AccountManagerService
options.putInt(AccountManager.KEY_CALLER_PID, pid);
int usrId = UserHandle.getCallingUserId();
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(usrId);
logRecordWithUid(
@@ -3275,7 +3275,7 @@ public class AccountManagerService
options.putInt(AccountManager.KEY_CALLER_UID, uid);
options.putInt(AccountManager.KEY_CALLER_PID, pid);
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
logRecordWithUid(
@@ -3358,7 +3358,7 @@ public class AccountManagerService
boolean isPasswordForwardingAllowed = checkPermissionAndNote(
callerPkg, uid, Manifest.permission.GET_PASSWORD);
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
logRecordWithUid(accounts, AccountsDb.DEBUG_ACTION_CALLED_START_ACCOUNT_ADD,
@@ -3599,7 +3599,7 @@ public class AccountManagerService
return;
}
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
logRecordWithUid(
@@ -3648,7 +3648,7 @@ public class AccountManagerService
if (intent == null) {
intent = getDefaultCantAddAccountIntent(errorCode);
}
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
mContext.startActivityAsUser(intent, new UserHandle(userId));
} finally {
@@ -3692,7 +3692,7 @@ public class AccountManagerService
}
if (response == null) throw new IllegalArgumentException("response is null");
if (account == null) throw new IllegalArgumentException("account is null");
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
new Session(accounts, response, account.type, expectActivityLaunch,
@@ -3729,7 +3729,7 @@ public class AccountManagerService
if (response == null) throw new IllegalArgumentException("response is null");
if (account == null) throw new IllegalArgumentException("account is null");
int userId = UserHandle.getCallingUserId();
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
new Session(accounts, response, account.type, expectActivityLaunch,
@@ -3783,7 +3783,7 @@ public class AccountManagerService
boolean isPasswordForwardingAllowed = checkPermissionAndNote(
callerPkg, uid, Manifest.permission.GET_PASSWORD);
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
new StartAccountSession(
@@ -3839,7 +3839,7 @@ public class AccountManagerService
}
int usrId = UserHandle.getCallingUserId();
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(usrId);
new Session(accounts, response, account.type, false /* expectActivityLaunch */,
@@ -3924,7 +3924,7 @@ public class AccountManagerService
accountType);
throw new SecurityException(msg);
}
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
new Session(accounts, response, accountType, expectActivityLaunch,
@@ -4228,7 +4228,7 @@ public class AccountManagerService
if (visibleAccountTypes.isEmpty()) {
return EMPTY_ACCOUNT_ARRAY;
}
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
return getAccountsInternal(
@@ -4352,7 +4352,7 @@ public class AccountManagerService
} // else aggregate all the visible accounts (it won't matter if the
// list is empty).
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts accounts = getUserAccounts(userId);
return getAccountsInternal(
@@ -4558,7 +4558,7 @@ public class AccountManagerService
int userId = UserHandle.getCallingUserId();
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts userAccounts = getUserAccounts(userId);
if (ArrayUtils.isEmpty(features)) {
@@ -4636,7 +4636,7 @@ public class AccountManagerService
return;
}
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
UserAccounts userAccounts = getUserAccounts(userId);
if (features == null || features.length == 0) {
@@ -4781,7 +4781,7 @@ public class AccountManagerService
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
| Intent.FLAG_GRANT_PREFIX_URI_PERMISSION));
- long bid = Binder.clearCallingIdentity();
+ final long bid = Binder.clearCallingIdentity();
try {
PackageManager pm = mContext.getPackageManager();
ResolveInfo resolveInfo = pm.resolveActivityAsUser(intent, 0, mAccounts.userId);
@@ -5281,7 +5281,7 @@ public class AccountManagerService
private void doNotification(UserAccounts accounts, Account account, CharSequence message,
Intent intent, String packageName, final int userId) {
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "doNotification: " + message + " intent:" + intent);
@@ -5340,7 +5340,7 @@ public class AccountManagerService
}
private void cancelNotification(NotificationId id, String packageName, UserHandle user) {
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
INotificationManager service = mInjector.getNotificationManager();
service.cancelNotificationWithTag(
@@ -5409,7 +5409,7 @@ public class AccountManagerService
private boolean isPrivileged(int callingUid) {
String[] packages;
- long identityToken = Binder.clearCallingIdentity();
+ final long identityToken = Binder.clearCallingIdentity();
try {
packages = mPackageManager.getPackagesForUid(callingUid);
if (packages == null) {
@@ -5501,7 +5501,7 @@ public class AccountManagerService
if (accountType == null) {
return false;
}
- long identityToken = Binder.clearCallingIdentity();
+ final long identityToken = Binder.clearCallingIdentity();
Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
try {
serviceInfos = mAuthenticatorCache.getAllServices(userId);
@@ -5530,7 +5530,7 @@ public class AccountManagerService
return SIGNATURE_CHECK_MISMATCH;
}
- long identityToken = Binder.clearCallingIdentity();
+ final long identityToken = Binder.clearCallingIdentity();
Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
try {
serviceInfos = mAuthenticatorCache.getAllServices(userId);
@@ -5576,7 +5576,7 @@ public class AccountManagerService
private List<String> getTypesForCaller(
int callingUid, int userId, boolean isOtherwisePermitted) {
List<String> managedAccountTypes = new ArrayList<>();
- long identityToken = Binder.clearCallingIdentity();
+ final long identityToken = Binder.clearCallingIdentity();
Collection<RegisteredServicesCache.ServiceInfo<AuthenticatorDescription>> serviceInfos;
try {
serviceInfos = mAuthenticatorCache.getAllServices(userId);
@@ -5659,7 +5659,7 @@ public class AccountManagerService
private boolean isSystemUid(int callingUid) {
String[] packages = null;
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
packages = mPackageManager.getPackagesForUid(callingUid);
if (packages != null) {
@@ -6188,7 +6188,7 @@ public class AccountManagerService
final int uid;
try {
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
uid = mPackageManager.getPackageUidAsUser(packageName, userId);
} finally {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3610a58b6641..dbc77d81c251 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3356,7 +3356,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final ApplicationInfo appInfo;
final boolean isInstantApp;
- long callingId = Binder.clearCallingIdentity();
+ final long callingId = Binder.clearCallingIdentity();
try {
IPackageManager pm = AppGlobals.getPackageManager();
synchronized(this) {
@@ -3497,7 +3497,7 @@ public class ActivityManagerService extends IActivityManager.Stub
userId, true, ALLOW_FULL_ONLY, "killBackgroundProcesses", null);
final int[] userIds = mUserController.expandUserId(userId);
- long callingId = Binder.clearCallingIdentity();
+ final long callingId = Binder.clearCallingIdentity();
try {
IPackageManager pm = AppGlobals.getPackageManager();
for (int targetUserId : userIds) {
@@ -3596,7 +3596,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final int callingPid = Binder.getCallingPid();
userId = mUserController.handleIncomingUser(callingPid, Binder.getCallingUid(),
userId, true, ALLOW_FULL_ONLY, "forceStopPackage", null);
- long callingId = Binder.clearCallingIdentity();
+ final long callingId = Binder.clearCallingIdentity();
try {
IPackageManager pm = AppGlobals.getPackageManager();
synchronized(this) {
@@ -6155,7 +6155,7 @@ public class ActivityManagerService extends IActivityManager.Stub
enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
"setDebugApp()");
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
// Note that this is not really thread safe if there are multiple
// callers into it at the same time, but that's not a situation we
@@ -6256,7 +6256,7 @@ public class ActivityManagerService extends IActivityManager.Stub
enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
"setAlwaysFinish()");
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
Settings.Global.putInt(
mContext.getContentResolver(),
@@ -7022,7 +7022,7 @@ public class ActivityManagerService extends IActivityManager.Stub
+ android.Manifest.permission.FORCE_STOP_PACKAGES);
}
int callerUid = Binder.getCallingUid();
- long iden = Binder.clearCallingIdentity();
+ final long iden = Binder.clearCallingIdentity();
try {
mProcessList.killProcessesWhenImperceptible(pids, reason, callerUid);
} finally {
@@ -7407,7 +7407,7 @@ public class ActivityManagerService extends IActivityManager.Stub
t.traceBegin("sendUserStartBroadcast");
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
Intent intent = new Intent(Intent.ACTION_USER_STARTED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
@@ -8171,7 +8171,7 @@ public class ActivityManagerService extends IActivityManager.Stub
*/
int enforceDumpPermissionForPackage(String packageName, int userId, int callingUid,
String function) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
int uid = Process.INVALID_UID;
try {
uid = mPackageManagerInt.getPackageUid(packageName,
@@ -8431,7 +8431,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- long origId = Binder.clearCallingIdentity();
+ final long origId = Binder.clearCallingIdentity();
if (useProto) {
final ProtoOutputStream proto = new ProtoOutputStream(fd);
@@ -12699,7 +12699,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- long oldIdent = Binder.clearCallingIdentity();
+ final long oldIdent = Binder.clearCallingIdentity();
try {
IBackupManager bm = IBackupManager.Stub.asInterface(
ServiceManager.getService(Context.BACKUP_SERVICE));
@@ -15065,7 +15065,7 @@ public class ActivityManagerService extends IActivityManager.Stub
final int callingPid = Binder.getCallingPid();
userId = mUserController.handleIncomingUser(callingPid, Binder.getCallingUid(),
userId, true, ALLOW_FULL_ONLY, "makePackageIdle", null);
- long callingId = Binder.clearCallingIdentity();
+ final long callingId = Binder.clearCallingIdentity();
synchronized(this) {
try {
IPackageManager pm = AppGlobals.getPackageManager();
@@ -15789,6 +15789,11 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
+ public int getPendingIntentFlags(IIntentSender target) {
+ return mPendingIntentController.getPendingIntentFlags(target);
+ }
+
+ @Override
public void setPendingIntentAllowBgActivityStarts(IIntentSender target,
IBinder whitelistToken, int flags) {
if (!(target instanceof PendingIntentRecord)) {
@@ -16757,7 +16762,7 @@ public class ActivityManagerService extends IActivityManager.Stub
"Cannot kill the dependents of a package without its name.");
}
- long callingId = Binder.clearCallingIdentity();
+ final long callingId = Binder.clearCallingIdentity();
IPackageManager pm = AppGlobals.getPackageManager();
int pkgUid = -1;
try {
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 3f55bffc1f3e..cf900ab9b0e6 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -546,7 +546,7 @@ class AppErrors {
}
}
if (res == AppErrorDialog.FORCE_QUIT) {
- long orig = Binder.clearCallingIdentity();
+ final long orig = Binder.clearCallingIdentity();
try {
// Kill it with fire!
mService.mAtmInternal.onHandleAppCrash(r.getWindowProcessController());
@@ -800,9 +800,7 @@ class AppErrors {
// with a home activity running in the process to prevent a repeatedly crashing app
// from blocking the user to manually clear the list.
final WindowProcessController proc = app.getWindowProcessController();
- final WindowProcessController homeProc = mService.mAtmInternal.getHomeProcess();
- if (proc == homeProc && proc.hasActivities()
- && (((ProcessRecord) homeProc.mOwner).info.flags & FLAG_SYSTEM) == 0) {
+ if (proc.isHomeProcess() && proc.hasActivities() && (app.info.flags & FLAG_SYSTEM) == 0) {
proc.clearPackagePreferredForHomeActivities();
}
diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java
index 374c215fc6d0..20cad185d8d0 100644
--- a/services/core/java/com/android/server/am/AppExitInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java
@@ -503,7 +503,7 @@ public final class AppExitInfoTracker {
@VisibleForTesting
void getExitInfo(final String packageName, final int filterUid,
final int filterPid, final int maxNum, final ArrayList<ApplicationExitInfo> results) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
boolean emptyPackageName = TextUtils.isEmpty(packageName);
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 76125aabc978..3eb4ddebaf06 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -2090,7 +2090,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
return;
}
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
if (BatteryStatsHelper.checkWifiOnly(mContext)) {
flags |= BatteryStats.DUMP_DEVICE_WIFI_ONLY;
@@ -2250,7 +2250,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BATTERY_STATS, null);
}
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
// Wait for the completion of pending works if there is any
awaitCompletion();
@@ -2277,7 +2277,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.BATTERY_STATS, null);
}
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
int i=-1;
try {
// Wait for the completion of pending works if there is any
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index 1155569c6b36..950f0a0f56a3 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -682,7 +682,7 @@ public class ContentProviderHelper {
*/
void removeContentProvider(IBinder connection, boolean stable) {
mService.enforceNotIsolatedCaller("removeContentProvider");
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
synchronized (mService) {
ContentProviderConnection conn;
@@ -711,7 +711,7 @@ public class ContentProviderHelper {
mService.enforceCallingPermission(
android.Manifest.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY,
"Do not have permission in call removeContentProviderExternal()");
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
removeContentProviderExternalUnchecked(name, token, userId);
} finally {
diff --git a/services/core/java/com/android/server/am/PendingIntentController.java b/services/core/java/com/android/server/am/PendingIntentController.java
index c62df56a88c5..2ae3d355a7ed 100644
--- a/services/core/java/com/android/server/am/PendingIntentController.java
+++ b/services/core/java/com/android/server/am/PendingIntentController.java
@@ -311,6 +311,16 @@ public class PendingIntentController {
}
}
+ int getPendingIntentFlags(IIntentSender target) {
+ if (!(target instanceof PendingIntentRecord)) {
+ Slog.w(TAG, "markAsSentFromNotification(): not a PendingIntentRecord: " + target);
+ return 0;
+ }
+ synchronized (mLock) {
+ return ((PendingIntentRecord) target).key.flags;
+ }
+ }
+
private void makeIntentSenderCanceled(PendingIntentRecord rec) {
rec.canceled = true;
final RemoteCallbackList<IResultReceiver> callbacks = rec.detachCancelListenersLocked();
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index ed47616d92dc..cf0223bac289 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2540,8 +2540,8 @@ public final class ProcessList {
app.hostingRecord.getName() != null ? app.hostingRecord.getName() : "");
try {
- AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.processName, app.uid,
- app.seInfo, app.info.sourceDir, pid);
+ AppGlobals.getPackageManager().logAppProcessStartIfNeeded(app.info.packageName,
+ app.processName, app.uid, app.seInfo, app.info.sourceDir, pid);
} catch (RemoteException ex) {
// Ignore
}
@@ -3561,7 +3561,7 @@ public final class ProcessList {
int clientTargetSdk) {
outInfo.pid = app.pid;
outInfo.uid = app.info.uid;
- if (mService.mAtmInternal.isHeavyWeightProcess(app.getWindowProcessController())) {
+ if (app.getWindowProcessController().isHeavyWeightProcess()) {
outInfo.flags |= ActivityManager.RunningAppProcessInfo.FLAG_CANT_SAVE_STATE;
}
if (app.isPersistent()) {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index ebc5b59363df..2571205bb3af 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -246,7 +246,7 @@ class ProcessRecord implements WindowProcessListener {
long lastTopTime; // The last time the process was in the TOP state or greater.
boolean reportLowMemory; // Set to true when waiting to report low mem
boolean empty; // Is this an empty background process?
- private volatile boolean mCached; // Is this a cached process?
+ private boolean mCached; // Is this a cached process?
String adjType; // Debugging: primary thing impacting oom_adj.
int adjTypeCode; // Debugging: adj code to report to app.
Object adjSource; // Debugging: option dependent object.
@@ -794,10 +794,7 @@ class ProcessRecord implements WindowProcessListener {
}
void setCached(boolean cached) {
- if (mCached != cached) {
- mCached = cached;
- mWindowProcessController.onProcCachedStateChanged(cached);
- }
+ mCached = cached;
}
@Override
@@ -887,7 +884,7 @@ class ProcessRecord implements WindowProcessListener {
Slog.w(TAG, "scheduleCrash: trying to crash system process!");
return;
}
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
thread.scheduleCrash(message);
} catch (RemoteException e) {
@@ -1850,8 +1847,8 @@ class ProcessRecord implements WindowProcessListener {
boolean getCachedIsHeavyWeight() {
if (mCachedIsHeavyWeight == VALUE_INVALID) {
- mCachedIsHeavyWeight = mService.mAtmInternal.isHeavyWeightProcess(
- getWindowProcessController()) ? VALUE_TRUE : VALUE_FALSE;
+ mCachedIsHeavyWeight = getWindowProcessController().isHeavyWeightProcess()
+ ? VALUE_TRUE : VALUE_FALSE;
}
return mCachedIsHeavyWeight == VALUE_TRUE;
}
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index d925defdbc73..c10a07862123 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -855,7 +855,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
if (!com.android.internal.util.DumpUtils.checkDumpAndUsageStatsPermission(mAm.mContext,
TAG, pw)) return;
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
if (args.length > 0) {
if ("--proto".equals(args[0])) {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 6c088262a7bf..f1bad9819394 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1814,7 +1814,7 @@ class UserController implements Handler.Callback {
void sendUserSwitchBroadcasts(int oldUserId, int newUserId) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
Intent intent;
if (oldUserId >= 0) {
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 7dbb39e3cb39..5379f3218a6e 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -29,6 +29,7 @@ import static android.app.AppOpsManager.KEY_BG_STATE_SETTLE_TIME;
import static android.app.AppOpsManager.KEY_FG_SERVICE_STATE_SETTLE_TIME;
import static android.app.AppOpsManager.KEY_TOP_STATE_SETTLE_TIME;
import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.MODE_FOREGROUND;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.AppOpsManager.NoteOpEvent;
@@ -132,6 +133,7 @@ import android.util.AtomicFile;
import android.util.KeyValueListParser;
import android.util.LongSparseArray;
import android.util.Pair;
+import android.util.Pools;
import android.util.Pools.SimplePool;
import android.util.Slog;
import android.util.SparseArray;
@@ -408,14 +410,26 @@ public class AppOpsService extends IAppOpsService.Stub {
}
InProgressStartOpEvent acquire(long startTime, long elapsedTime, @NonNull IBinder clientId,
- @NonNull Runnable onDeath, int uidState) throws RemoteException {
+ @NonNull Runnable onDeath, int proxyUid, @Nullable String proxyPackageName,
+ @Nullable String proxyAttributionTag, @AppOpsManager.UidState int uidState,
+ @OpFlags int flags) throws RemoteException {
+
InProgressStartOpEvent recycled = acquire();
+
+ OpEventProxyInfo proxyInfo = null;
+ if (proxyUid != Process.INVALID_UID) {
+ proxyInfo = mOpEventProxyInfoPool.acquire(proxyUid, proxyPackageName,
+ proxyAttributionTag);
+ }
+
if (recycled != null) {
- recycled.reinit(startTime, elapsedTime, clientId, onDeath, uidState);
+ recycled.reinit(startTime, elapsedTime, clientId, onDeath, uidState, flags,
+ proxyInfo, mOpEventProxyInfoPool);
return recycled;
}
- return new InProgressStartOpEvent(startTime, elapsedTime, clientId, onDeath, uidState);
+ return new InProgressStartOpEvent(startTime, elapsedTime, clientId, onDeath, uidState,
+ proxyInfo, flags);
}
}
@@ -670,6 +684,12 @@ public class AppOpsService extends IAppOpsService.Stub {
/** uidstate used when calling startOp */
private @AppOpsManager.UidState int mUidState;
+ /** Proxy information of the startOp event */
+ private @Nullable OpEventProxyInfo mProxy;
+
+ /** Proxy flag information */
+ private @OpFlags int mFlags;
+
/** How many times the op was started but not finished yet */
int numUnfinishedStarts;
@@ -681,17 +701,22 @@ public class AppOpsService extends IAppOpsService.Stub {
* @param clientId The client id of the caller of {@link #startOperation}
* @param onDeath The code to execute on client death
* @param uidState The uidstate of the app {@link #startOperation} was called for
+ * @param proxy The proxy information, if {@link #startProxyOperation} was called
+ * @param flags The trusted/nontrusted/self flags.
*
* @throws RemoteException If the client is dying
*/
private InProgressStartOpEvent(long startTime, long startElapsedTime,
- @NonNull IBinder clientId, @NonNull Runnable onDeath, int uidState)
- throws RemoteException {
+ @NonNull IBinder clientId, @NonNull Runnable onDeath,
+ @AppOpsManager.UidState int uidState, @Nullable OpEventProxyInfo proxy,
+ @OpFlags int flags) throws RemoteException {
mStartTime = startTime;
mStartElapsedTime = startElapsedTime;
mClientId = clientId;
mOnDeath = onDeath;
mUidState = uidState;
+ mProxy = proxy;
+ mFlags = flags;
clientId.linkToDeath(this, 0);
}
@@ -714,16 +739,27 @@ public class AppOpsService extends IAppOpsService.Stub {
* @param clientId The client id of the caller of {@link #startOperation}
* @param onDeath The code to execute on client death
* @param uidState The uidstate of the app {@link #startOperation} was called for
+ * @param flags The flags relating to the proxy
+ * @param proxy The proxy information, if {@link #startProxyOperation} was called
+ * @param proxyPool The pool to release previous {@link OpEventProxyInfo} to
*
* @throws RemoteException If the client is dying
*/
public void reinit(long startTime, long startElapsedTime, @NonNull IBinder clientId,
- @NonNull Runnable onDeath, int uidState) throws RemoteException {
+ @NonNull Runnable onDeath, @AppOpsManager.UidState int uidState, @OpFlags int flags,
+ @Nullable OpEventProxyInfo proxy, @NonNull Pools.Pool<OpEventProxyInfo> proxyPool
+ ) throws RemoteException {
mStartTime = startTime;
mStartElapsedTime = startElapsedTime;
mClientId = clientId;
mOnDeath = onDeath;
mUidState = uidState;
+ mFlags = flags;
+
+ if (mProxy != null) {
+ proxyPool.release(mProxy);
+ }
+ mProxy = proxy;
clientId.linkToDeath(this, 0);
}
@@ -744,9 +780,19 @@ public class AppOpsService extends IAppOpsService.Stub {
}
/** @return uidstate used when calling startOp */
- public int getUidState() {
+ public @AppOpsManager.UidState int getUidState() {
return mUidState;
}
+
+ /** @return proxy info for the access */
+ public @Nullable OpEventProxyInfo getProxy() {
+ return mProxy;
+ }
+
+ /** @return flags used for the access */
+ public @OpFlags int getFlags() {
+ return mFlags;
+ }
}
private final class AttributedOp {
@@ -876,14 +922,22 @@ public class AppOpsService extends IAppOpsService.Stub {
* Update state when start was called
*
* @param clientId Id of the startOp caller
+ * @param proxyUid The UID of the proxy app
+ * @param proxyPackageName The package name of the proxy app
+ * @param proxyAttributionTag The attribution tag of the proxy app
* @param uidState UID state of the app startOp is called for
+ * @param flags The proxy flags
*/
- public void started(@NonNull IBinder clientId, @AppOpsManager.UidState int uidState)
- throws RemoteException {
- started(clientId, uidState, true);
+ public void started(@NonNull IBinder clientId, int proxyUid,
+ @Nullable String proxyPackageName, @Nullable String proxyAttributionTag,
+ @AppOpsManager.UidState int uidState, @OpFlags int flags) throws RemoteException {
+ started(clientId, proxyUid, proxyPackageName, proxyAttributionTag, uidState, flags,
+ true);
}
- private void started(@NonNull IBinder clientId, @AppOpsManager.UidState int uidState,
+ private void started(@NonNull IBinder clientId, int proxyUid,
+ @Nullable String proxyPackageName, @Nullable String proxyAttributionTag,
+ @AppOpsManager.UidState int uidState, @OpFlags int flags,
boolean triggerCallbackIfNeeded) throws RemoteException {
if (triggerCallbackIfNeeded && !parent.isRunning()) {
scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
@@ -899,7 +953,7 @@ public class AppOpsService extends IAppOpsService.Stub {
event = mInProgressStartOpEventPool.acquire(System.currentTimeMillis(),
SystemClock.elapsedRealtime(), clientId,
PooledLambda.obtainRunnable(AppOpsService::onClientDeath, this, clientId),
- uidState);
+ proxyUid, proxyPackageName, proxyAttributionTag, uidState, flags);
mInProgressEvents.put(clientId, event);
} else {
if (uidState != event.mUidState) {
@@ -909,9 +963,8 @@ public class AppOpsService extends IAppOpsService.Stub {
event.numUnfinishedStarts++;
- // startOp events don't support proxy, hence use flags==SELF
mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName,
- tag, uidState, OP_FLAG_SELF);
+ tag, uidState, flags);
}
/**
@@ -945,14 +998,17 @@ public class AppOpsService extends IAppOpsService.Stub {
mAccessEvents = new LongSparseArray<>(1);
}
- // startOp events don't support proxy, hence use flags==SELF
+ OpEventProxyInfo proxyCopy = event.getProxy() != null
+ ? new OpEventProxyInfo(event.getProxy()) : null;
+
NoteOpEvent finishedEvent = new NoteOpEvent(event.getStartTime(),
- SystemClock.elapsedRealtime() - event.getStartElapsedTime(), null);
- mAccessEvents.put(makeKey(event.getUidState(), OP_FLAG_SELF), finishedEvent);
+ SystemClock.elapsedRealtime() - event.getStartElapsedTime(), proxyCopy);
+ mAccessEvents.put(makeKey(event.getUidState(), event.getFlags()),
+ finishedEvent);
mHistoricalRegistry.increaseOpAccessDuration(parent.op, parent.uid,
parent.packageName, tag, event.getUidState(),
- AppOpsManager.OP_FLAG_SELF, finishedEvent.getDuration());
+ event.getFlags(), finishedEvent.getDuration());
mInProgressStartOpEventPool.release(event);
@@ -1010,9 +1066,17 @@ public class AppOpsService extends IAppOpsService.Stub {
event.numUnfinishedStarts = 1;
finished(event.getClientId(), false);
+ OpEventProxyInfo proxy = event.getProxy();
+
// Call started() to add a new start event object and then add the
// previously removed unfinished start counts back
- started(event.getClientId(), newState, false);
+ if (proxy != null) {
+ started(event.getClientId(), proxy.getUid(), proxy.getPackageName(),
+ proxy.getAttributionTag(), newState, event.getFlags(), false);
+ } else {
+ started(event.getClientId(), Process.INVALID_UID, null, null, newState,
+ OP_FLAG_SELF, false);
+ }
event.numUnfinishedStarts += numPreviousUnfinishedStarts - 1;
} catch (RemoteException e) {
if (DEBUG) Slog.e(TAG, "Cannot switch to new uidState " + newState);
@@ -1116,10 +1180,9 @@ public class AppOpsService extends IAppOpsService.Stub {
for (int i = 0; i < numInProgressEvents; i++) {
InProgressStartOpEvent event = mInProgressEvents.valueAt(i);
- // startOp events don't support proxy
- accessEvents.append(makeKey(event.getUidState(), OP_FLAG_SELF),
+ accessEvents.append(makeKey(event.getUidState(), event.getFlags()),
new NoteOpEvent(event.getStartTime(), now - event.getStartElapsedTime(),
- null));
+ event.getProxy()));
}
}
@@ -2182,14 +2245,14 @@ public class AppOpsService extends IAppOpsService.Stub {
if (mode == defaultMode) {
return;
}
- previousMode = AppOpsManager.MODE_DEFAULT;
+ previousMode = MODE_DEFAULT;
uidState = new UidState(uid);
uidState.opModes = new SparseIntArray();
uidState.opModes.put(code, mode);
mUidStates.put(uid, uidState);
scheduleWriteLocked();
} else if (uidState.opModes == null) {
- previousMode = AppOpsManager.MODE_DEFAULT;
+ previousMode = MODE_DEFAULT;
if (mode != defaultMode) {
uidState.opModes = new SparseIntArray();
uidState.opModes.put(code, mode);
@@ -2356,7 +2419,7 @@ public class AppOpsService extends IAppOpsService.Stub {
+ permissionInfo.backgroundPermission);
}
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
packageManager.updatePermissionFlags(permissionInfo.backgroundPermission,
packageName, PackageManager.FLAG_PERMISSION_REVOKED_COMPAT,
@@ -2380,7 +2443,7 @@ public class AppOpsService extends IAppOpsService.Stub {
+ switchCode + ", mode=" + mode + ", permission=" + permissionName);
}
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
packageManager.updatePermissionFlags(permissionName, packageName,
PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, isRevokedCompat
@@ -2430,7 +2493,7 @@ public class AppOpsService extends IAppOpsService.Stub {
return;
}
- int previousMode = AppOpsManager.MODE_DEFAULT;
+ int previousMode = MODE_DEFAULT;
synchronized (this) {
UidState uidState = getUidStateLocked(uid, false);
Op op = getOpLocked(code, uid, packageName, null, bypass, true);
@@ -3261,7 +3324,7 @@ public class AppOpsService extends IAppOpsService.Stub {
int callingUid = Binder.getCallingUid();
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
synchronized (this) {
Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
@@ -3409,7 +3472,75 @@ public class AppOpsService extends IAppOpsService.Stub {
return result;
}
}
+ return startOperationUnchecked(clientId, code, uid, packageName, attributionTag,
+ Process.INVALID_UID, null, null, OP_FLAG_SELF, startIfModeDefault,
+ shouldCollectAsyncNotedOp, message, shouldCollectMessage, false);
+
+ }
+
+ @Override
+ public int startProxyOperation(IBinder clientId, int code, int proxiedUid,
+ String proxiedPackageName, @Nullable String proxiedAttributionTag, int proxyUid,
+ String proxyPackageName, @Nullable String proxyAttributionTag,
+ boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message,
+ boolean shouldCollectMessage) {
+ verifyIncomingUid(proxyUid);
+ verifyIncomingOp(code);
+ verifyIncomingPackage(proxyPackageName, UserHandle.getUserId(proxyUid));
+ verifyIncomingPackage(proxiedPackageName, UserHandle.getUserId(proxiedUid));
+
+ String resolvedProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
+ if (resolvedProxyPackageName == null) {
+ return AppOpsManager.MODE_IGNORED;
+ }
+
+ final boolean isProxyTrusted = mContext.checkPermission(
+ Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid)
+ == PackageManager.PERMISSION_GRANTED;
+
+ final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
+ : AppOpsManager.OP_FLAG_UNTRUSTED_PROXY;
+ String resolvedProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
+ if (resolvedProxiedPackageName == null) {
+ return AppOpsManager.MODE_IGNORED;
+ }
+ final int proxiedFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXIED
+ : AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED;
+
+ // Test if the proxied operation will succeed before starting the proxy operation
+ final int testProxiedMode = startOperationUnchecked(clientId, code, proxiedUid,
+ resolvedProxiedPackageName, proxiedAttributionTag, proxyUid,
+ resolvedProxyPackageName, proxyAttributionTag, proxiedFlags, startIfModeDefault,
+ shouldCollectAsyncNotedOp, message, shouldCollectMessage, true);
+ if (!shouldStartForMode(testProxiedMode, startIfModeDefault)) {
+ return testProxiedMode;
+ }
+
+ final int proxyMode = startOperationUnchecked(clientId, code, proxyUid,
+ resolvedProxyPackageName, proxyAttributionTag, Process.INVALID_UID, null, null,
+ proxyFlags, startIfModeDefault, !isProxyTrusted, "proxy " + message,
+ shouldCollectMessage, false);
+ if (!shouldStartForMode(proxyMode, startIfModeDefault)
+ || Binder.getCallingUid() == proxiedUid) {
+ return proxyMode;
+ }
+
+ return startOperationUnchecked(clientId, code, proxiedUid, resolvedProxiedPackageName,
+ proxiedAttributionTag, proxyUid, resolvedProxyPackageName, proxyAttributionTag,
+ proxiedFlags, startIfModeDefault, shouldCollectAsyncNotedOp, message,
+ shouldCollectMessage, false);
+ }
+
+ private boolean shouldStartForMode(int mode, boolean startIfModeDefault) {
+ return (mode == MODE_ALLOWED || (mode == MODE_DEFAULT && startIfModeDefault));
+ }
+
+ private int startOperationUnchecked(IBinder clientId, int code, int uid,
+ @NonNull String packageName, @Nullable String attributionTag, int proxyUid,
+ String proxyPackageName, @Nullable String proxyAttributionTag, @OpFlags int flags,
+ boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, @Nullable String message,
+ boolean shouldCollectMessage, boolean dryRun) {
RestrictionBypass bypass;
try {
bypass = verifyAndGetBypass(uid, packageName, attributionTag);
@@ -3419,19 +3550,25 @@ public class AppOpsService extends IAppOpsService.Stub {
}
synchronized (this) {
- final Ops ops = getOpsLocked(uid, resolvedPackageName, attributionTag, bypass,
- true /* edit */);
+ final Ops ops = getOpsLocked(uid, packageName, attributionTag, bypass, true /* edit */);
if (ops == null) {
- scheduleOpStartedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_IGNORED);
+ if (!dryRun) {
+ scheduleOpStartedIfNeededLocked(code, uid, packageName,
+ AppOpsManager.MODE_IGNORED);
+ }
if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
- + " package " + resolvedPackageName);
+ + " package " + packageName);
return AppOpsManager.MODE_ERRORED;
}
final Op op = getOpLocked(ops, code, uid, true);
- if (isOpRestrictedLocked(uid, code, resolvedPackageName, bypass)) {
- scheduleOpStartedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_IGNORED);
+ if (isOpRestrictedLocked(uid, code, packageName, bypass)) {
+ if (!dryRun) {
+ scheduleOpStartedIfNeededLocked(code, uid, packageName,
+ AppOpsManager.MODE_IGNORED);
+ }
return AppOpsManager.MODE_IGNORED;
}
+
final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
final int switchCode = AppOpsManager.opToSwitch(code);
final UidState uidState = ops.uidState;
@@ -3439,13 +3576,16 @@ public class AppOpsService extends IAppOpsService.Stub {
// non-default) it takes over, otherwise use the per package policy.
if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
final int uidMode = uidState.evalMode(code, uidState.opModes.get(switchCode));
- if (uidMode != AppOpsManager.MODE_ALLOWED
- && (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) {
- if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
- + switchCode + " (" + code + ") uid " + uid + " package "
- + resolvedPackageName);
- attributedOp.rejected(uidState.state, AppOpsManager.OP_FLAG_SELF);
- scheduleOpStartedIfNeededLocked(code, uid, packageName, uidMode);
+ if (!shouldStartForMode(uidMode, startIfModeDefault)) {
+ if (DEBUG) {
+ Slog.d(TAG, "startOperation: uid reject #" + uidMode + " for code "
+ + switchCode + " (" + code + ") uid " + uid + " package "
+ + packageName);
+ }
+ if (!dryRun) {
+ attributedOp.rejected(uidState.state, flags);
+ scheduleOpStartedIfNeededLocked(code, uid, packageName, uidMode);
+ }
return uidMode;
}
} else {
@@ -3453,26 +3593,31 @@ public class AppOpsService extends IAppOpsService.Stub {
: op;
final int mode = switchOp.evalMode();
if (mode != AppOpsManager.MODE_ALLOWED
- && (!startIfModeDefault || mode != AppOpsManager.MODE_DEFAULT)) {
+ && (!startIfModeDefault || mode != MODE_DEFAULT)) {
if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
+ switchCode + " (" + code + ") uid " + uid + " package "
- + resolvedPackageName);
- attributedOp.rejected(uidState.state, AppOpsManager.OP_FLAG_SELF);
- scheduleOpStartedIfNeededLocked(code, uid, packageName, mode);
+ + packageName);
+ if (!dryRun) {
+ attributedOp.rejected(uidState.state, flags);
+ scheduleOpStartedIfNeededLocked(code, uid, packageName, mode);
+ }
return mode;
}
}
if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
- + " package " + resolvedPackageName);
- scheduleOpStartedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_ALLOWED);
- try {
- attributedOp.started(clientId, uidState.state);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
+ + " package " + packageName);
+ if (!dryRun) {
+ scheduleOpStartedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_ALLOWED);
+ try {
+ attributedOp.started(clientId, proxyUid, proxyPackageName, proxyAttributionTag,
+ uidState.state, flags);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
}
}
- if (shouldCollectAsyncNotedOp) {
+ if (shouldCollectAsyncNotedOp && !dryRun) {
collectAsyncNotedOp(uid, packageName, code, attributionTag, AppOpsManager.OP_FLAG_SELF,
message, shouldCollectMessage);
}
@@ -3492,6 +3637,37 @@ public class AppOpsService extends IAppOpsService.Stub {
return;
}
+ finishOperationUnchecked(clientId, code, uid, resolvedPackageName, attributionTag);
+ }
+
+ @Override
+ public void finishProxyOperation(IBinder clientId, int code, int proxiedUid,
+ String proxiedPackageName, @Nullable String proxiedAttributionTag, int proxyUid,
+ @Nullable String proxyPackageName, @Nullable String proxyAttributionTag) {
+ verifyIncomingUid(proxyUid);
+ verifyIncomingOp(code);
+ verifyIncomingPackage(proxyPackageName, UserHandle.getUserId(proxyUid));
+ verifyIncomingPackage(proxiedPackageName, UserHandle.getUserId(proxiedUid));
+
+ String resolvedProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
+ if (resolvedProxyPackageName == null) {
+ return;
+ }
+
+ finishOperationUnchecked(clientId, code, proxyUid, resolvedProxyPackageName,
+ proxyAttributionTag);
+
+ String resolvedProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
+ if (resolvedProxiedPackageName == null) {
+ return;
+ }
+
+ finishOperationUnchecked(clientId, code, proxiedUid, resolvedProxiedPackageName,
+ proxiedAttributionTag);
+ }
+
+ private void finishOperationUnchecked(IBinder clientId, int code, int uid, String packageName,
+ String attributionTag) {
RestrictionBypass bypass;
try {
bypass = verifyAndGetBypass(uid, packageName, attributionTag);
@@ -3501,7 +3677,7 @@ public class AppOpsService extends IAppOpsService.Stub {
}
synchronized (this) {
- Op op = getOpLocked(code, uid, resolvedPackageName, attributionTag, bypass, true);
+ Op op = getOpLocked(code, uid, packageName, attributionTag, bypass, true);
if (op == null) {
Slog.e(TAG, "Operation not found: uid=" + uid + " pkg=" + packageName + "("
+ attributionTag + ") op=" + AppOpsManager.opToName(code));
@@ -4937,7 +5113,7 @@ public class AppOpsService extends IAppOpsService.Stub {
case "write-settings": {
shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
Binder.getCallingUid(), -1);
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
synchronized (shell.mInternal) {
shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
@@ -4952,7 +5128,7 @@ public class AppOpsService extends IAppOpsService.Stub {
case "read-settings": {
shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
Binder.getCallingUid(), -1);
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
shell.mInternal.readState();
pw.println("Last settings read.");
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index dbfaffe2a5f1..0d077c6818b0 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -81,12 +81,22 @@ public class AttentionManagerService extends SystemService {
/** Service will unbind if connection is not used for that amount of time. */
private static final long CONNECTION_TTL_MILLIS = 60_000;
+ /**
+ * We cache the DeviceConfig values to avoid frequent ashmem-related checks; if the cached
+ * values are stale for more than this duration we will update the cache.
+ */
+ @VisibleForTesting static final long DEVICE_CONFIG_MAX_STALENESS_MILLIS = 4 * 60 * 60 * 1000L;
+
+ @VisibleForTesting long mLastReadDeviceConfigMillis = Long.MIN_VALUE;
+
/** DeviceConfig flag name, if {@code true}, enables AttentionManagerService features. */
private static final String KEY_SERVICE_ENABLED = "service_enabled";
/** Default value in absence of {@link DeviceConfig} override. */
private static final boolean DEFAULT_SERVICE_ENABLED = true;
+ private boolean mIsServiceEnabledCached;
+
/**
* DeviceConfig flag name, describes how much time we consider a result fresh; if the check
* attention called within that period - cached value will be returned.
@@ -98,6 +108,8 @@ public class AttentionManagerService extends SystemService {
@VisibleForTesting
static final long DEFAULT_STALE_AFTER_MILLIS = 1_000;
+ private long mStaleAfterMillisCached;
+
/** The size of the buffer that stores recent attention check results. */
@VisibleForTesting
protected static final int ATTENTION_CACHE_BUFFER_SIZE = 5;
@@ -176,8 +188,8 @@ public class AttentionManagerService extends SystemService {
}
private boolean isServiceEnabled() {
- return DeviceConfig.getBoolean(NAMESPACE_ATTENTION_MANAGER_SERVICE, KEY_SERVICE_ENABLED,
- DEFAULT_SERVICE_ENABLED);
+ ensureDeviceConfigCachedValuesFreshness();
+ return mIsServiceEnabledCached;
}
/**
@@ -186,16 +198,39 @@ public class AttentionManagerService extends SystemService {
*/
@VisibleForTesting
protected long getStaleAfterMillis() {
+ ensureDeviceConfigCachedValuesFreshness();
+ return mStaleAfterMillisCached;
+ }
+
+ @VisibleForTesting
+ protected void ensureDeviceConfigCachedValuesFreshness() {
+ final long now = SystemClock.elapsedRealtime();
+ final long whenBecomesStale =
+ mLastReadDeviceConfigMillis + DEVICE_CONFIG_MAX_STALENESS_MILLIS;
+ if (now < whenBecomesStale) {
+ if (DEBUG) {
+ Slog.d(LOG_TAG,
+ "Cached values are still fresh. Refreshed at=" + mLastReadDeviceConfigMillis
+ + ", now=" + now);
+ }
+ return;
+ }
+
+ mIsServiceEnabledCached = DeviceConfig.getBoolean(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+ KEY_SERVICE_ENABLED,
+ DEFAULT_SERVICE_ENABLED);
+
final long millis = DeviceConfig.getLong(NAMESPACE_ATTENTION_MANAGER_SERVICE,
KEY_STALE_AFTER_MILLIS,
DEFAULT_STALE_AFTER_MILLIS);
-
if (millis < 0 || millis > 10_000) {
Slog.w(LOG_TAG, "Bad flag value supplied for: " + KEY_STALE_AFTER_MILLIS);
- return DEFAULT_STALE_AFTER_MILLIS;
+ mStaleAfterMillisCached = DEFAULT_STALE_AFTER_MILLIS;
+ } else {
+ mStaleAfterMillisCached = millis;
}
- return millis;
+ mLastReadDeviceConfigMillis = now;
}
/**
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 7ad0f21c2f69..ff6367b96626 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -9384,7 +9384,7 @@ public class AudioService extends IAudioService.Stub
if (DEBUG_VOL) {
Log.d(TAG, "Persisting Volume Behavior for DeviceType: " + deviceType);
}
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
System.putIntForUser(mContentResolver,
getSettingsNameForDeviceVolumeBehavior(deviceType),
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index de302fc01f2d..198de78ecfa6 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -154,7 +154,7 @@ public class PacManager {
mNetThreadHandler = new Handler(netThread.getLooper());
mPacRefreshIntent = PendingIntent.getBroadcast(
- context, 0, new Intent(ACTION_PAC_REFRESH), 0);
+ context, 0, new Intent(ACTION_PAC_REFRESH), PendingIntent.FLAG_IMMUTABLE);
context.registerReceiver(new PacRefreshIntentReceiver(),
new IntentFilter(ACTION_PAC_REFRESH));
mConnectivityHandler = handler;
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index a45d94bfc002..09c01d7c21a4 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -380,8 +380,8 @@ public class Vpn {
}
}
- public boolean checkInterfacePresent(final Vpn vpn, final String iface) {
- return vpn.jniCheck(iface) == 0;
+ public boolean isInterfacePresent(final Vpn vpn, final String iface) {
+ return vpn.jniCheck(iface) != 0;
}
}
@@ -966,7 +966,7 @@ public class Vpn {
/** Prepare the VPN for the given package. Does not perform permission checks. */
@GuardedBy("this")
private void prepareInternal(String newPackage) {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
// Reset the interface.
if (mInterface != null) {
@@ -1251,7 +1251,7 @@ public class Vpn {
mNetworkCapabilities.setAdministratorUids(new int[] {mOwnerUID});
mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserId,
mConfig.allowedApplications, mConfig.disallowedApplications));
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE /* logtag */,
mNetworkInfo, mNetworkCapabilities, lp,
@@ -1270,7 +1270,7 @@ public class Vpn {
}
private boolean canHaveRestrictedProfile(int userId) {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
return UserManager.get(mContext).canHaveRestrictedProfile(userId);
} finally {
@@ -1317,7 +1317,7 @@ public class Vpn {
// Check if the service is properly declared.
Intent intent = new Intent(VpnConfig.SERVICE_INTERFACE);
intent.setClassName(mPackage, config.user);
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
// Restricted users are not allowed to create VPNs, they are tied to Owner
enforceNotRestrictedUser();
@@ -1608,7 +1608,7 @@ public class Vpn {
*/
public synchronized void onUserStopped() {
// Switch off networking lockdown (if it was enabled)
- setLockdown(false);
+ setVpnForcedLocked(false);
mAlwaysOn = false;
// Quit any active connections
@@ -2045,7 +2045,7 @@ public class Vpn {
*/
public void startLegacyVpn(VpnProfile profile, KeyStore keyStore, LinkProperties egress) {
enforceControlPermission();
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
startLegacyVpnPrivileged(profile, keyStore, egress);
} finally {
@@ -2761,7 +2761,10 @@ public class Vpn {
final LinkProperties lp = cm.getLinkProperties(network);
if (lp != null && lp.getAllInterfaceNames().contains(mOuterInterface)) {
final NetworkInfo networkInfo = cm.getNetworkInfo(network);
- if (networkInfo != null) mOuterConnection.set(networkInfo.getType());
+ if (networkInfo != null) {
+ mOuterConnection.set(networkInfo.getType());
+ break;
+ }
}
}
}
@@ -2992,7 +2995,7 @@ public class Vpn {
checkInterruptAndDelay(false);
// Check if the interface is gone while we are waiting.
- if (mDeps.checkInterfacePresent(Vpn.this, mConfig.interfaze)) {
+ if (!mDeps.isInterfacePresent(Vpn.this, mConfig.interfaze)) {
throw new IllegalStateException(mConfig.interfaze + " is gone");
}
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 1294e9030f62..a2c427b8036a 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -596,7 +596,7 @@ public final class ContentService extends IContentService.Stub {
// This makes it so that future permission checks will be in the context of this
// process rather than the caller's process. We will restore this before returning.
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
@@ -650,7 +650,7 @@ public final class ContentService extends IContentService.Stub {
// This makes it so that future permission checks will be in the context of this
// process rather than the caller's process. We will restore this before returning.
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
if (syncManager == null) {
@@ -718,7 +718,7 @@ public final class ContentService extends IContentService.Stub {
"no permission to modify the sync settings for user " + userId);
// This makes it so that future permission checks will be in the context of this
// process rather than the caller's process. We will restore this before returning.
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
if (cname != null) {
Slog.e(TAG, "cname not null.");
return;
@@ -751,7 +751,7 @@ public final class ContentService extends IContentService.Stub {
Bundle extras = new Bundle(request.getBundle());
validateExtras(callingUid, extras);
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
SyncStorageEngine.EndPoint info;
@@ -834,7 +834,7 @@ public final class ContentService extends IContentService.Stub {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
"no permission to read the sync settings");
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
@@ -866,7 +866,7 @@ public final class ContentService extends IContentService.Stub {
final int callingPid = Binder.getCallingPid();
final int syncExemptionFlag = getSyncExemptionForCaller(callingUid);
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
@@ -899,7 +899,7 @@ public final class ContentService extends IContentService.Stub {
pollFrequency = clampPeriod(pollFrequency);
long defaultFlex = SyncStorageEngine.calculateDefaultFlexTime(pollFrequency);
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
SyncStorageEngine.EndPoint info =
new SyncStorageEngine.EndPoint(account, authority, userId);
@@ -927,7 +927,7 @@ public final class ContentService extends IContentService.Stub {
final int callingUid = Binder.getCallingUid();
int userId = UserHandle.getCallingUserId();
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
getSyncManager()
.removePeriodicSync(
@@ -951,7 +951,7 @@ public final class ContentService extends IContentService.Stub {
"no permission to read the sync settings");
int userId = UserHandle.getCallingUserId();
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
return getSyncManager().getPeriodicSyncs(
new SyncStorageEngine.EndPoint(account, providerName, userId));
@@ -976,7 +976,7 @@ public final class ContentService extends IContentService.Stub {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
"no permission to read the sync settings");
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
@@ -1012,7 +1012,7 @@ public final class ContentService extends IContentService.Stub {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
@@ -1040,7 +1040,7 @@ public final class ContentService extends IContentService.Stub {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
"no permission to read the sync settings");
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
@@ -1067,7 +1067,7 @@ public final class ContentService extends IContentService.Stub {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null) {
@@ -1084,7 +1084,7 @@ public final class ContentService extends IContentService.Stub {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
int userId = UserHandle.getCallingUserId();
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
if (syncManager == null) {
@@ -1116,7 +1116,7 @@ public final class ContentService extends IContentService.Stub {
final boolean canAccessAccounts =
mContext.checkCallingOrSelfPermission(Manifest.permission.GET_ACCOUNTS)
== PackageManager.PERMISSION_GRANTED;
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
return getSyncManager().getSyncStorageEngine()
.getCurrentSyncsCopy(userId, canAccessAccounts);
@@ -1146,7 +1146,7 @@ public final class ContentService extends IContentService.Stub {
mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
"no permission to read the sync stats");
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
if (syncManager == null) {
@@ -1176,7 +1176,7 @@ public final class ContentService extends IContentService.Stub {
"no permission to read the sync stats");
enforceCrossUserPermission(userId,
"no permission to retrieve the sync settings for user " + userId);
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
SyncManager syncManager = getSyncManager();
if (syncManager == null) return false;
@@ -1196,7 +1196,7 @@ public final class ContentService extends IContentService.Stub {
@Override
public void addStatusChangeListener(int mask, ISyncStatusObserver callback) {
final int callingUid = Binder.getCallingUid();
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null && callback != null) {
@@ -1210,7 +1210,7 @@ public final class ContentService extends IContentService.Stub {
@Override
public void removeStatusChangeListener(ISyncStatusObserver callback) {
- long identityToken = clearCallingIdentity();
+ final long identityToken = clearCallingIdentity();
try {
SyncManager syncManager = getSyncManager();
if (syncManager != null && callback != null) {
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 91fa15a913a3..c686ba4c4b5c 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -2773,7 +2773,7 @@ public class SyncManager {
}
private void onReady() {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mOnReadyCallback.onReady();
} finally {
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
new file mode 100644
index 000000000000..4cff5c013bda
--- /dev/null
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.devicestate;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.util.IntArray;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.SystemService;
+import com.android.server.policy.DeviceStatePolicyImpl;
+
+import java.util.Arrays;
+
+/**
+ * A system service that manages the state of a device with user-configurable hardware like a
+ * foldable phone.
+ * <p>
+ * Device state is an abstract concept that allows mapping the current state of the device to the
+ * state of the system. For example, system services (like
+ * {@link com.android.server.display.DisplayManagerService display manager} and
+ * {@link com.android.server.wm.WindowManagerService window manager}) and system UI may have
+ * different behaviors depending on the physical state of the device. This is useful for
+ * variable-state devices, like foldable or rollable devices, that can be configured by users into
+ * differing hardware states, which each may have a different expected use case.
+ * </p>
+ * <p>
+ * The {@link DeviceStateManagerService} is responsible for receiving state change requests from
+ * 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>
+ *
+ * @see DeviceStatePolicy
+ */
+public final class DeviceStateManagerService extends SystemService {
+ /** Invalid device state. */
+ public static final int INVALID_DEVICE_STATE = -1;
+
+ private static final String TAG = "DeviceStateManagerService";
+ private static final boolean DEBUG = false;
+
+ private final Object mLock = new Object();
+ @NonNull
+ private final DeviceStatePolicy mDeviceStatePolicy;
+
+ @GuardedBy("mLock")
+ private IntArray mSupportedDeviceStates;
+
+ // The current committed device state.
+ @GuardedBy("mLock")
+ private int mCommittedState = INVALID_DEVICE_STATE;
+ // The device state that is currently pending callback from the policy to be committed.
+ @GuardedBy("mLock")
+ private int mPendingState = INVALID_DEVICE_STATE;
+ // 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.
+ @GuardedBy("mLock")
+ private int mRequestedState = INVALID_DEVICE_STATE;
+
+ public DeviceStateManagerService(@NonNull Context context) {
+ this(context, new DeviceStatePolicyImpl());
+ }
+
+ @VisibleForTesting
+ DeviceStateManagerService(@NonNull Context context, @NonNull DeviceStatePolicy policy) {
+ super(context);
+ mDeviceStatePolicy = policy;
+ }
+
+ @Override
+ public void onStart() {
+ mDeviceStatePolicy.getDeviceStateProvider().setListener(new DeviceStateProviderListener());
+ }
+
+ /**
+ * Returns the current state the system is in. Note that the system may be in the process of
+ * configuring a different state.
+ *
+ * @see #getPendingState()
+ */
+ @VisibleForTesting
+ int getCommittedState() {
+ synchronized (mLock) {
+ return mCommittedState;
+ }
+ }
+
+ /**
+ * Returns the state the system is currently configuring, or {@link #INVALID_DEVICE_STATE} if
+ * the system is not in the process of configuring a state.
+ */
+ @VisibleForTesting
+ int getPendingState() {
+ synchronized (mLock) {
+ return mPendingState;
+ }
+ }
+
+ /**
+ * Returns the requested state. The service will configure the device to match the requested
+ * state when possible.
+ */
+ @VisibleForTesting
+ int getRequestedState() {
+ synchronized (mLock) {
+ return mRequestedState;
+ }
+ }
+
+ private void updateSupportedStates(int[] supportedDeviceStates) {
+ // Must ensure sorted as isSupportedStateLocked() impl uses binary search.
+ Arrays.sort(supportedDeviceStates, 0, supportedDeviceStates.length);
+ synchronized (mLock) {
+ mSupportedDeviceStates = IntArray.wrap(supportedDeviceStates);
+
+ if (mRequestedState != INVALID_DEVICE_STATE
+ && !isSupportedStateLocked(mRequestedState)) {
+ // The current requested state is no longer valid. We'll clear it here, though
+ // we won't actually update the current state with a call to
+ // updatePendingStateLocked() as doing so will not have any effect.
+ mRequestedState = INVALID_DEVICE_STATE;
+ }
+ }
+ }
+
+ /**
+ * Returns {@code true} if the provided state is supported. Requires that
+ * {@link #mSupportedDeviceStates} is sorted prior to calling.
+ */
+ private boolean isSupportedStateLocked(int state) {
+ return mSupportedDeviceStates.binarySearch(state) >= 0;
+ }
+
+ /**
+ * 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.
+ *
+ * @see #isSupportedStateLocked(int)
+ */
+ private void requestState(int state) {
+ synchronized (mLock) {
+ if (isSupportedStateLocked(state)) {
+ mRequestedState = state;
+ }
+ updatePendingStateLocked();
+ }
+
+ notifyPolicyIfNeeded();
+ }
+
+ /**
+ * Tries to update the current configuring state with the current requested state. Must call
+ * {@link #notifyPolicyIfNeeded()} to actually notify the policy that the state is being
+ * changed.
+ */
+ private void updatePendingStateLocked() {
+ if (mRequestedState == INVALID_DEVICE_STATE) {
+ // No currently requested state.
+ return;
+ }
+
+ if (mPendingState != INVALID_DEVICE_STATE) {
+ // Have pending state, can not configure a new state until the state is committed.
+ return;
+ }
+
+ if (mRequestedState == mCommittedState) {
+ // No need to notify the policy as the committed state matches the requested state.
+ return;
+ }
+
+ mPendingState = mRequestedState;
+ mIsPolicyWaitingForState = true;
+ }
+
+ /**
+ * Notifies the policy to configure the supplied state. Should not be called with {@link #mLock}
+ * held.
+ */
+ private void notifyPolicyIfNeeded() {
+ if (Thread.holdsLock(mLock)) {
+ Throwable error = new Throwable("Attempting to notify DeviceStatePolicy with service"
+ + " lock held");
+ error.fillInStackTrace();
+ Slog.w(TAG, error);
+ }
+ int state;
+ synchronized (mLock) {
+ if (!mIsPolicyWaitingForState) {
+ return;
+ }
+ mIsPolicyWaitingForState = false;
+ state = mPendingState;
+ }
+
+ if (DEBUG) {
+ Slog.d(TAG, "Notifying policy to configure state: " + state);
+ }
+ mDeviceStatePolicy.configureDeviceForState(state, this::commitPendingState);
+ }
+
+ /**
+ * Commits the current pending state after a callback from the {@link DeviceStatePolicy}.
+ *
+ * <pre>
+ * ------------- ----------- -------------
+ * Provider -> | Requested | -> | Pending | -> Policy -> | Committed |
+ * ------------- ----------- -------------
+ * </pre>
+ * <p>
+ * When a new state is requested it immediately enters the requested state. Once the policy is
+ * available to accept a new state, which could also be immediately if there is no current
+ * pending state at the point of request, the policy is notified and a callback is provided to
+ * trigger the state to be committed.
+ * </p>
+ */
+ private void commitPendingState() {
+ synchronized (mLock) {
+ if (DEBUG) {
+ Slog.d(TAG, "Committing state: " + mPendingState);
+ }
+ mCommittedState = mPendingState;
+ mPendingState = INVALID_DEVICE_STATE;
+ updatePendingStateLocked();
+ }
+
+ notifyPolicyIfNeeded();
+ }
+
+ private final class DeviceStateProviderListener implements DeviceStateProvider.Listener {
+ @Override
+ public void onSupportedDeviceStatesChanged(int[] newDeviceStates) {
+ for (int i = 0; i < newDeviceStates.length; i++) {
+ if (newDeviceStates[i] < 0) {
+ throw new IllegalArgumentException("Supported device states includes invalid"
+ + " value: " + newDeviceStates[i]);
+ }
+ }
+
+ updateSupportedStates(newDeviceStates);
+ }
+
+ @Override
+ public void onStateChanged(int state) {
+ if (state < 0) {
+ throw new IllegalArgumentException("Invalid state: " + state);
+ }
+
+ requestState(state);
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/devicestate/DeviceStatePolicy.java b/services/core/java/com/android/server/devicestate/DeviceStatePolicy.java
new file mode 100644
index 000000000000..274b8e562098
--- /dev/null
+++ b/services/core/java/com/android/server/devicestate/DeviceStatePolicy.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.devicestate;
+
+import android.annotation.NonNull;
+
+/**
+ * Interface for the component responsible for supplying the current device state as well as
+ * configuring the state of the system in response to device state changes.
+ *
+ * @see DeviceStateManagerService
+ */
+public interface DeviceStatePolicy {
+ /** Returns the provider of device states. */
+ DeviceStateProvider getDeviceStateProvider();
+
+ /**
+ * Configures the system into the provided state. Guaranteed not to be called again until the
+ * {@code onComplete} callback has been executed.
+ *
+ * @param state the state the system should be configured for.
+ * @param onComplete a callback that must be triggered once the system has been properly
+ * configured to match the supplied state.
+ */
+ void configureDeviceForState(int state, @NonNull Runnable onComplete);
+}
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateProvider.java b/services/core/java/com/android/server/devicestate/DeviceStateProvider.java
new file mode 100644
index 000000000000..0e8bf9bda4aa
--- /dev/null
+++ b/services/core/java/com/android/server/devicestate/DeviceStateProvider.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.devicestate;
+
+/**
+ * Responsible for providing the set of currently supported device states and well as the current
+ * device state.
+ *
+ * @see DeviceStatePolicy
+ */
+public interface DeviceStateProvider {
+ /**
+ * Registers a listener for changes in provider state.
+ * <p>
+ * It is <b>required</b> that {@link Listener#onSupportedDeviceStatesChanged(int[])} be called
+ * followed by {@link Listener#onStateChanged(int)} with the initial values on successful
+ * registration of the listener.
+ */
+ void setListener(Listener listener);
+
+ /** Callback for changes in {@link DeviceStateProvider} state. */
+ interface Listener {
+ /**
+ * Called to notify the listener of a change in supported device states. Required to be
+ * called once on successful registration of the listener and then once on every
+ * subsequent change in supported device states.
+ * <p>
+ * The set of device states can change based on the current hardware state of the device.
+ * For example, if a device state depends on a particular peripheral device (display, etc)
+ * it would only be reported as supported when the device is plugged. Otherwise, it should
+ * not be included in the set of supported states.
+ * <p>
+ * All values provided must be greater than or equal to zero and there must always be at
+ * least one supported device state.
+ *
+ * @param newDeviceStates array of supported device states.
+ *
+ * @throws IllegalArgumentException if the list of device states is empty or if one of the
+ * provided states is less than 0.
+ */
+ void onSupportedDeviceStatesChanged(int[] newDeviceStates);
+
+ /**
+ * Called to notify the listener of a change in current device state. Required to be called
+ * once on successful registration of the listener and then once on every subsequent change
+ * in device state. Value must have been included in the set of supported device states
+ * provided in the most recent call to {@link #onSupportedDeviceStatesChanged(int[])}.
+ *
+ * @param state the new device state.
+ *
+ * @throws IllegalArgumentException if the state is less than 0.
+ */
+ void onStateChanged(int state);
+ }
+}
diff --git a/services/core/java/com/android/server/devicestate/OWNERS b/services/core/java/com/android/server/devicestate/OWNERS
new file mode 100644
index 000000000000..ae79fc0e2c2d
--- /dev/null
+++ b/services/core/java/com/android/server/devicestate/OWNERS
@@ -0,0 +1,3 @@
+ogunwale@google.com
+akulian@google.com
+darryljohnson@google.com
diff --git a/services/core/java/com/android/server/display/DisplayDeviceRepository.java b/services/core/java/com/android/server/display/DisplayDeviceRepository.java
index f4f77db91500..aa4db29e0d49 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceRepository.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceRepository.java
@@ -18,6 +18,7 @@ package com.android.server.display;
import android.annotation.NonNull;
import android.util.Slog;
+import android.view.Display;
import com.android.internal.annotations.GuardedBy;
import com.android.server.display.DisplayManagerService.SyncRoot;
@@ -48,15 +49,27 @@ class DisplayDeviceRepository implements DisplayAdapter.Listener {
@GuardedBy("mSyncRoot")
private final List<DisplayDevice> mDisplayDevices = new ArrayList<>();
- /** Listener for {link DisplayDevice} events. */
- private final Listener mListener;
+ /** Listeners for {link DisplayDevice} events. */
+ @GuardedBy("mSyncRoot")
+ private final List<Listener> mListeners = new ArrayList<>();
/** Global lock object from {@link DisplayManagerService}. */
private final SyncRoot mSyncRoot;
- DisplayDeviceRepository(@NonNull SyncRoot syncRoot, @NonNull Listener listener) {
+ private final PersistentDataStore mPersistentDataStore;
+
+ /**
+ * @param syncRoot The global lock for DisplayManager related objects.
+ * @param persistentDataStore Settings data store from {@link DisplayManagerService}.
+ */
+ DisplayDeviceRepository(@NonNull SyncRoot syncRoot,
+ @NonNull PersistentDataStore persistentDataStore) {
mSyncRoot = syncRoot;
- mListener = listener;
+ mPersistentDataStore = persistentDataStore;
+ }
+
+ public void addListener(@NonNull Listener listener) {
+ mListeners.add(listener);
}
@Override
@@ -78,7 +91,10 @@ class DisplayDeviceRepository implements DisplayAdapter.Listener {
@Override
public void onTraversalRequested() {
- mListener.onTraversalRequested();
+ final int size = mListeners.size();
+ for (int i = 0; i < size; i++) {
+ mListeners.get(i).onTraversalRequested();
+ }
}
public boolean containsLocked(DisplayDevice d) {
@@ -107,18 +123,37 @@ class DisplayDeviceRepository implements DisplayAdapter.Listener {
device.mDebugLastLoggedDeviceInfo = info;
mDisplayDevices.add(device);
- mListener.onDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
+ sendEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
}
}
private void handleDisplayDeviceChanged(DisplayDevice device) {
synchronized (mSyncRoot) {
- DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
+ final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
if (!mDisplayDevices.contains(device)) {
Slog.w(TAG, "Attempted to change non-existent display device: " + info);
return;
}
- mListener.onDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
+
+ int diff = device.mDebugLastLoggedDeviceInfo.diff(info);
+ if (diff == DisplayDeviceInfo.DIFF_STATE) {
+ Slog.i(TAG, "Display device changed state: \"" + info.name
+ + "\", " + Display.stateToString(info.state));
+ } else if (diff != 0) {
+ Slog.i(TAG, "Display device changed: " + info);
+ }
+
+ if ((diff & DisplayDeviceInfo.DIFF_COLOR_MODE) != 0) {
+ try {
+ mPersistentDataStore.setColorMode(device, info.colorMode);
+ } finally {
+ mPersistentDataStore.saveIfNeeded();
+ }
+ }
+ device.mDebugLastLoggedDeviceInfo = info;
+
+ device.applyPendingDisplayDeviceInfoChangesLocked();
+ sendEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
}
}
@@ -132,14 +167,21 @@ class DisplayDeviceRepository implements DisplayAdapter.Listener {
Slog.i(TAG, "Display device removed: " + info);
device.mDebugLastLoggedDeviceInfo = info;
- mListener.onDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_REMOVED);
+ sendEventLocked(device, DISPLAY_DEVICE_EVENT_REMOVED);
+ }
+ }
+
+ private void sendEventLocked(DisplayDevice device, int event) {
+ final int size = mListeners.size();
+ for (int i = 0; i < size; i++) {
+ mListeners.get(i).onDisplayDeviceEventLocked(device, event);
}
}
/**
* Listens to {@link DisplayDevice} events from {@link DisplayDeviceRepository}.
*/
- interface Listener {
+ public interface Listener {
void onDisplayDeviceEventLocked(DisplayDevice device, int event);
// TODO: multi-display - Try to remove the need for requestTraversal...it feels like
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 597f49c63193..af62aeba4cfb 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -109,10 +109,10 @@ import com.android.server.wm.WindowManagerInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Consumer;
/**
* Manages attached displays.
@@ -181,7 +181,6 @@ public final class DisplayManagerService extends SystemService {
private final Context mContext;
private final DisplayManagerHandler mHandler;
private final Handler mUiHandler;
- private final DisplayDeviceListener mDisplayDeviceListener;
private final DisplayModeDirector mDisplayModeDirector;
private WindowManagerInternal mWindowManagerInternal;
private InputManagerInternal mInputManagerInternal;
@@ -202,13 +201,6 @@ public final class DisplayManagerService extends SystemService {
// services should be started. This option may disable certain display adapters.
public boolean mOnlyCore;
- // True if the display manager service should pretend there is only one display
- // and only tell applications about the existence of the default logical display.
- // The display manager can still mirror content to secondary displays but applications
- // cannot present unique content on those displays.
- // Used for demonstration purposes only.
- private final boolean mSingleDisplayDemoMode;
-
// All callback records indexed by calling process id.
public final SparseArray<CallbackRecord> mCallbacks =
new SparseArray<CallbackRecord>();
@@ -216,13 +208,17 @@ public final class DisplayManagerService extends SystemService {
// List of all currently registered display adapters.
private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>();
+ /**
+ * Repository of all active {@link DisplayDevice}s.
+ */
private final DisplayDeviceRepository mDisplayDeviceRepo;
- // List of all logical displays indexed by logical display id.
- // Any modification to mLogicalDisplays must invalidate the DisplayManagerGlobal cache.
- private final SparseArray<LogicalDisplay> mLogicalDisplays =
- new SparseArray<LogicalDisplay>();
- private int mNextNonDefaultDisplayId = Display.DEFAULT_DISPLAY + 1;
+ /**
+ * Contains all the {@link LogicalDisplay} instances and is responsible for mapping
+ * {@link DisplayDevice}s to {@link LogicalDisplay}s. DisplayManagerService listens to display
+ * event on this object.
+ */
+ private final LogicalDisplayMapper mLogicalDisplayMapper;
// List of all display transaction listeners.
private final CopyOnWriteArrayList<DisplayTransactionListener> mDisplayTransactionListeners =
@@ -282,10 +278,6 @@ public final class DisplayManagerService extends SystemService {
// May be used outside of the lock but only on the handler thread.
private final ArrayList<CallbackRecord> mTempCallbacks = new ArrayList<CallbackRecord>();
- // Temporary display info, used for comparing display configurations.
- private final DisplayInfo mTempDisplayInfo = new DisplayInfo();
- private final DisplayInfo mTempNonOverrideDisplayInfo = new DisplayInfo();
-
// Temporary viewports, used when sending new viewport information to the
// input system. May be used outside of the lock but only on the handler thread.
private final ArrayList<DisplayViewport> mTempViewports = new ArrayList<>();
@@ -331,10 +323,10 @@ public final class DisplayManagerService extends SystemService {
mContext = context;
mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
mUiHandler = UiThread.getHandler();
- mDisplayDeviceListener = new DisplayDeviceListener();
- mDisplayDeviceRepo = new DisplayDeviceRepository(mSyncRoot, mDisplayDeviceListener);
+ mDisplayDeviceRepo = new DisplayDeviceRepository(mSyncRoot, mPersistentDataStore);
+ mLogicalDisplayMapper = new LogicalDisplayMapper(mDisplayDeviceRepo,
+ new LogicalDisplayListener(), mPersistentDataStore);
mDisplayModeDirector = new DisplayModeDirector(context, mHandler);
- mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
Resources resources = mContext.getResources();
mDefaultDisplayDefaultColorMode = mContext.getResources().getInteger(
com.android.internal.R.integer.config_defaultDisplayDefaultColorMode);
@@ -395,13 +387,13 @@ public final class DisplayManagerService extends SystemService {
synchronized (mSyncRoot) {
long timeout = SystemClock.uptimeMillis()
+ mInjector.getDefaultDisplayDelayTimeout();
- while (mLogicalDisplays.get(Display.DEFAULT_DISPLAY) == null ||
- mVirtualDisplayAdapter == null) {
+ while (mLogicalDisplayMapper.getLocked(Display.DEFAULT_DISPLAY) == null
+ || mVirtualDisplayAdapter == null) {
long delay = timeout - SystemClock.uptimeMillis();
if (delay <= 0) {
throw new RuntimeException("Timeout waiting for default display "
+ "to be initialized. DefaultDisplay="
- + mLogicalDisplays.get(Display.DEFAULT_DISPLAY)
+ + mLogicalDisplayMapper.getLocked(Display.DEFAULT_DISPLAY)
+ ", mVirtualDisplayAdapter=" + mVirtualDisplayAdapter);
}
if (DEBUG) {
@@ -451,7 +443,7 @@ public final class DisplayManagerService extends SystemService {
mSystemReady = true;
// Just in case the top inset changed before the system was ready. At this point, any
// relevant configuration should be in place.
- recordTopInsetLocked(mLogicalDisplays.get(Display.DEFAULT_DISPLAY));
+ recordTopInsetLocked(mLogicalDisplayMapper.getLocked(Display.DEFAULT_DISPLAY));
updateSettingsLocked();
}
@@ -516,13 +508,12 @@ public final class DisplayManagerService extends SystemService {
}
@VisibleForTesting
- void setDisplayInfoOverrideFromWindowManagerInternal(
- int displayId, DisplayInfo info) {
+ void setDisplayInfoOverrideFromWindowManagerInternal(int displayId, DisplayInfo info) {
synchronized (mSyncRoot) {
- LogicalDisplay display = mLogicalDisplays.get(displayId);
+ LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
if (display != null) {
if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) {
- handleLogicalDisplayChanged(displayId, display);
+ handleLogicalDisplayChangedLocked(display);
scheduleTraversalLocked(false);
}
}
@@ -534,7 +525,7 @@ public final class DisplayManagerService extends SystemService {
*/
private void getNonOverrideDisplayInfoInternal(int displayId, DisplayInfo outInfo) {
synchronized (mSyncRoot) {
- final LogicalDisplay display = mLogicalDisplays.get(displayId);
+ final LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
if (display != null) {
display.getNonOverrideDisplayInfoLocked(outInfo);
}
@@ -633,7 +624,7 @@ public final class DisplayManagerService extends SystemService {
private DisplayInfo getDisplayInfoInternal(int displayId, int callingUid) {
synchronized (mSyncRoot) {
- LogicalDisplay display = mLogicalDisplays.get(displayId);
+ LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
if (display != null) {
DisplayInfo info = display.getDisplayInfoLocked();
if (info.hasAccess(callingUid)
@@ -645,25 +636,6 @@ public final class DisplayManagerService extends SystemService {
}
}
- private int[] getDisplayIdsInternal(int callingUid) {
- synchronized (mSyncRoot) {
- final int count = mLogicalDisplays.size();
- int[] displayIds = new int[count];
- int n = 0;
- for (int i = 0; i < count; i++) {
- LogicalDisplay display = mLogicalDisplays.valueAt(i);
- DisplayInfo info = display.getDisplayInfoLocked();
- if (info.hasAccess(callingUid)) {
- displayIds[n++] = mLogicalDisplays.keyAt(i);
- }
- }
- if (n != count) {
- displayIds = Arrays.copyOfRange(displayIds, 0, n);
- }
- return displayIds;
- }
- }
-
private void registerCallbackInternal(IDisplayManagerCallback callback, int callingPid) {
synchronized (mSyncRoot) {
if (mCallbacks.get(callingPid) != null) {
@@ -798,7 +770,7 @@ public final class DisplayManagerService extends SystemService {
private void requestColorModeInternal(int displayId, int colorMode) {
synchronized (mSyncRoot) {
- LogicalDisplay display = mLogicalDisplays.get(displayId);
+ LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
if (display != null &&
display.getRequestedColorModeLocked() != colorMode) {
display.setRequestedColorModeLocked(colorMode);
@@ -835,7 +807,7 @@ public final class DisplayManagerService extends SystemService {
mDisplayDeviceRepo.onDisplayDeviceEvent(device,
DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED);
- LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
+ LogicalDisplay display = mLogicalDisplayMapper.getLocked(device);
if (display != null) {
return display.getDisplayIdLocked();
}
@@ -880,7 +852,7 @@ public final class DisplayManagerService extends SystemService {
DisplayDevice device =
mVirtualDisplayAdapter.releaseVirtualDisplayLocked(appToken);
if (device != null) {
- // TODO - handle virtual displays the same as other display adapters.
+ // TODO: multi-display - handle virtual displays the same as other display adapters.
mDisplayDeviceRepo.onDisplayDeviceEvent(device,
DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
}
@@ -958,77 +930,42 @@ public final class DisplayManagerService extends SystemService {
}
@VisibleForTesting
- void handleDisplayDeviceAdded(DisplayDevice device) {
+ void handleLogicalDisplayAdded(LogicalDisplay display) {
synchronized (mSyncRoot) {
- handleDisplayDeviceAddedLocked(device);
+ handleLogicalDisplayAddedLocked(display);
}
}
- private void handleDisplayDeviceAddedLocked(DisplayDevice device) {
- LogicalDisplay display = addLogicalDisplayLocked(device);
- Runnable work = updateDisplayStateLocked(device);
- if (work != null) {
- work.run();
- }
- scheduleTraversalLocked(false);
- }
-
- @VisibleForTesting
- void handleDisplayDeviceChanged(DisplayDevice device) {
- synchronized (mSyncRoot) {
- handleDisplayDeviceChangedLocked(device);
+ private void handleLogicalDisplayAddedLocked(LogicalDisplay display) {
+ final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
+ final int displayId = display.getDisplayIdLocked();
+ final boolean isDefault = displayId == Display.DEFAULT_DISPLAY;
+ configureColorModeLocked(display, device);
+ if (isDefault) {
+ recordStableDisplayStatsIfNeededLocked(display);
+ recordTopInsetLocked(display);
}
- }
- private void handleDisplayDeviceChangedLocked(DisplayDevice device) {
- DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
+ DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
- int diff = device.mDebugLastLoggedDeviceInfo.diff(info);
- if (diff == DisplayDeviceInfo.DIFF_STATE) {
- Slog.i(TAG, "Display device changed state: \"" + info.name
- + "\", " + Display.stateToString(info.state));
- final Optional<Integer> viewportType = getViewportType(info);
- if (viewportType.isPresent()) {
- for (DisplayViewport d : mViewports) {
- if (d.type == viewportType.get() && info.uniqueId.equals(d.uniqueId)) {
- // Update display view port power state
- d.isActive = Display.isActiveState(info.state);
- }
- }
- if (mInputManagerInternal != null) {
- mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
- }
- }
- } else if (diff != 0) {
- Slog.i(TAG, "Display device changed: " + info);
- }
- if ((diff & DisplayDeviceInfo.DIFF_COLOR_MODE) != 0) {
- try {
- mPersistentDataStore.setColorMode(device, info.colorMode);
- } finally {
- mPersistentDataStore.saveIfNeeded();
- }
+ // Wake up waitForDefaultDisplay.
+ if (isDefault) {
+ mSyncRoot.notifyAll();
}
- device.mDebugLastLoggedDeviceInfo = info;
- device.applyPendingDisplayDeviceInfoChangesLocked();
- if (updateLogicalDisplaysLocked()) {
- scheduleTraversalLocked(false);
- }
- }
+ sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
- private void handleDisplayDeviceRemoved(DisplayDevice device) {
- synchronized (mSyncRoot) {
- handleDisplayDeviceRemovedLocked(device);
+ Runnable work = updateDisplayStateLocked(device);
+ if (work != null) {
+ work.run();
}
- }
-
- private void handleDisplayDeviceRemovedLocked(DisplayDevice device) {
- updateLogicalDisplaysLocked();
scheduleTraversalLocked(false);
}
- private void handleLogicalDisplayChanged(int displayId, @NonNull LogicalDisplay display) {
+ private void handleLogicalDisplayChangedLocked(@NonNull LogicalDisplay display) {
+ updateViewportPowerStateLocked(display);
+
+ final int displayId = display.getDisplayIdLocked();
if (displayId == Display.DEFAULT_DISPLAY) {
recordTopInsetLocked(display);
}
@@ -1036,11 +973,14 @@ public final class DisplayManagerService extends SystemService {
// display info will trigger a cache invalidation inside of LogicalDisplay before we hit
// this point.
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
+ scheduleTraversalLocked(false);
}
- private void handleLogicalDisplayRemoved(int displayId) {
+ private void handleLogicalDisplayRemovedLocked(@NonNull LogicalDisplay display) {
+ final int displayId = display.getDisplayIdLocked();
DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
+ scheduleTraversalLocked(false);
}
private void applyGlobalDisplayStateLocked(List<Runnable> workQueue) {
@@ -1065,63 +1005,6 @@ public final class DisplayManagerService extends SystemService {
return null;
}
- // Adds a new logical display based on the given display device.
- // Sends notifications if needed.
- private LogicalDisplay addLogicalDisplayLocked(DisplayDevice device) {
- DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
- boolean isDefault = (deviceInfo.flags
- & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
- if (isDefault && mLogicalDisplays.get(Display.DEFAULT_DISPLAY) != null) {
- Slog.w(TAG, "Ignoring attempt to add a second default display: " + deviceInfo);
- isDefault = false;
- }
-
- if (!isDefault && mSingleDisplayDemoMode) {
- Slog.i(TAG, "Not creating a logical display for a secondary display "
- + " because single display demo mode is enabled: " + deviceInfo);
- return null;
- }
-
- final int displayId = assignDisplayIdLocked(isDefault);
- final int layerStack = assignLayerStackLocked(displayId);
-
- LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
- display.updateLocked(mDisplayDeviceRepo);
- if (!display.isValidLocked()) {
- // This should never happen currently.
- Slog.w(TAG, "Ignoring display device because the logical display "
- + "created from it was not considered valid: " + deviceInfo);
- return null;
- }
-
- configureColorModeLocked(display, device);
- if (isDefault) {
- recordStableDisplayStatsIfNeededLocked(display);
- recordTopInsetLocked(display);
- }
-
- mLogicalDisplays.put(displayId, display);
- DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
-
- // Wake up waitForDefaultDisplay.
- if (isDefault) {
- mSyncRoot.notifyAll();
- }
-
- sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
- return display;
- }
-
- private int assignDisplayIdLocked(boolean isDefault) {
- return isDefault ? Display.DEFAULT_DISPLAY : mNextNonDefaultDisplayId++;
- }
-
- private int assignLayerStackLocked(int displayId) {
- // Currently layer stacks and display ids are the same.
- // This need not be the case.
- return displayId;
- }
-
private void configureColorModeLocked(LogicalDisplay display, DisplayDevice device) {
if (display.getPrimaryDisplayDeviceLocked() == device) {
int colorMode = mPersistentDataStore.getColorMode(device);
@@ -1238,39 +1121,6 @@ public final class DisplayManagerService extends SystemService {
}
}
- // Updates all existing logical displays given the current set of display devices.
- // Removes invalid logical displays.
- // Sends notifications if needed.
- private boolean updateLogicalDisplaysLocked() {
- boolean changed = false;
- for (int i = mLogicalDisplays.size(); i-- > 0; ) {
- final int displayId = mLogicalDisplays.keyAt(i);
- LogicalDisplay display = mLogicalDisplays.valueAt(i);
-
- mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked());
- display.getNonOverrideDisplayInfoLocked(mTempNonOverrideDisplayInfo);
- display.updateLocked(mDisplayDeviceRepo);
- if (!display.isValidLocked()) {
- mLogicalDisplays.removeAt(i);
- handleLogicalDisplayRemoved(displayId);
- changed = true;
- } else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) {
- handleLogicalDisplayChanged(displayId, display);
- changed = true;
- } else {
- // While applications shouldn't know nor care about the non-overridden info, we
- // still need to let WindowManager know so it can update its own internal state for
- // things like display cutouts.
- display.getNonOverrideDisplayInfoLocked(mTempDisplayInfo);
- if (!mTempNonOverrideDisplayInfo.equals(mTempDisplayInfo)) {
- handleLogicalDisplayChanged(displayId, display);
- changed = true;
- }
- }
- }
- return changed;
- }
-
private void performTraversalLocked(SurfaceControl.Transaction t) {
// Clear all viewports before configuring displays so that we can keep
// track of which ones we have configured.
@@ -1292,7 +1142,7 @@ public final class DisplayManagerService extends SystemService {
float requestedRefreshRate, int requestedModeId, boolean preferMinimalPostProcessing,
boolean inTraversal) {
synchronized (mSyncRoot) {
- LogicalDisplay display = mLogicalDisplays.get(displayId);
+ LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
if (display == null) {
return;
}
@@ -1334,7 +1184,7 @@ public final class DisplayManagerService extends SystemService {
private void setDisplayOffsetsInternal(int displayId, int x, int y) {
synchronized (mSyncRoot) {
- LogicalDisplay display = mLogicalDisplays.get(displayId);
+ LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
if (display == null) {
return;
}
@@ -1352,7 +1202,7 @@ public final class DisplayManagerService extends SystemService {
private void setDisplayScalingDisabledInternal(int displayId, boolean disable) {
synchronized (mSyncRoot) {
- final LogicalDisplay display = mLogicalDisplays.get(displayId);
+ final LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
if (display == null) {
return;
}
@@ -1388,7 +1238,7 @@ public final class DisplayManagerService extends SystemService {
@Nullable
private IBinder getDisplayToken(int displayId) {
synchronized (mSyncRoot) {
- final LogicalDisplay display = mLogicalDisplays.get(displayId);
+ final LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
if (display != null) {
final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
if (device != null) {
@@ -1406,7 +1256,7 @@ public final class DisplayManagerService extends SystemService {
if (token == null) {
return null;
}
- final LogicalDisplay logicalDisplay = mLogicalDisplays.get(displayId);
+ final LogicalDisplay logicalDisplay = mLogicalDisplayMapper.getLocked(displayId);
if (logicalDisplay == null) {
return null;
}
@@ -1496,33 +1346,6 @@ public final class DisplayManagerService extends SystemService {
}
}
- private void onDesiredDisplayModeSpecsChangedInternal() {
- boolean changed = false;
- synchronized (mSyncRoot) {
- final int count = mLogicalDisplays.size();
- for (int i = 0; i < count; i++) {
- LogicalDisplay display = mLogicalDisplays.valueAt(i);
- int displayId = mLogicalDisplays.keyAt(i);
- DisplayModeDirector.DesiredDisplayModeSpecs desiredDisplayModeSpecs =
- mDisplayModeDirector.getDesiredDisplayModeSpecs(displayId);
- DisplayModeDirector.DesiredDisplayModeSpecs existingDesiredDisplayModeSpecs =
- display.getDesiredDisplayModeSpecsLocked();
- if (DEBUG) {
- Slog.i(TAG,
- "Comparing display specs: " + desiredDisplayModeSpecs
- + ", existing: " + existingDesiredDisplayModeSpecs);
- }
- if (!desiredDisplayModeSpecs.equals(existingDesiredDisplayModeSpecs)) {
- display.setDesiredDisplayModeSpecsLocked(desiredDisplayModeSpecs);
- changed = true;
- }
- }
- if (changed) {
- scheduleTraversalLocked(false);
- }
- }
- }
-
private void clearViewportsLocked() {
mViewports.clear();
}
@@ -1550,15 +1373,15 @@ public final class DisplayManagerService extends SystemService {
// Find the logical display that the display device is showing.
// Certain displays only ever show their own content.
- LogicalDisplay display = findLogicalDisplayForDeviceLocked(device);
+ LogicalDisplay display = mLogicalDisplayMapper.getLocked(device);
if (!ownContent) {
if (display != null && !display.hasContentLocked()) {
// If the display does not have any content of its own, then
// automatically mirror the requested logical display contents if possible.
- display = mLogicalDisplays.get(device.getDisplayIdToMirrorLocked());
+ display = mLogicalDisplayMapper.getLocked(device.getDisplayIdToMirrorLocked());
}
if (display == null) {
- display = mLogicalDisplays.get(Display.DEFAULT_DISPLAY);
+ display = mLogicalDisplayMapper.getLocked(Display.DEFAULT_DISPLAY);
}
}
@@ -1622,15 +1445,21 @@ public final class DisplayManagerService extends SystemService {
viewport.isActive = Display.isActiveState(info.state);
}
- private LogicalDisplay findLogicalDisplayForDeviceLocked(DisplayDevice device) {
- final int count = mLogicalDisplays.size();
- for (int i = 0; i < count; i++) {
- LogicalDisplay display = mLogicalDisplays.valueAt(i);
- if (display.getPrimaryDisplayDeviceLocked() == device) {
- return display;
+ private void updateViewportPowerStateLocked(LogicalDisplay display) {
+ final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
+ final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
+ final Optional<Integer> viewportType = getViewportType(info);
+ if (viewportType.isPresent()) {
+ for (DisplayViewport d : mViewports) {
+ if (d.type == viewportType.get() && info.uniqueId.equals(d.uniqueId)) {
+ // Update display view port power state
+ d.isActive = Display.isActiveState(info.state);
+ }
+ }
+ if (mInputManagerInternal != null) {
+ mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
}
}
- return null;
}
private void sendDisplayEventLocked(int displayId, int event) {
@@ -1694,10 +1523,8 @@ public final class DisplayManagerService extends SystemService {
pw.println(" mSafeMode=" + mSafeMode);
pw.println(" mPendingTraversal=" + mPendingTraversal);
pw.println(" mGlobalDisplayState=" + Display.stateToString(mGlobalDisplayState));
- pw.println(" mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId);
pw.println(" mViewports=" + mViewports);
pw.println(" mDefaultDisplayDefaultColorMode=" + mDefaultDisplayDefaultColorMode);
- pw.println(" mSingleDisplayDemoMode=" + mSingleDisplayDemoMode);
pw.println(" mWifiDisplayScanRequestCount=" + mWifiDisplayScanRequestCount);
pw.println(" mStableDisplaySize=" + mStableDisplaySize);
pw.println(" mMinimumBrightnessCurve=" + mMinimumBrightnessCurve);
@@ -1719,15 +1546,8 @@ public final class DisplayManagerService extends SystemService {
device.dumpLocked(ipw);
});
- final int logicalDisplayCount = mLogicalDisplays.size();
pw.println();
- pw.println("Logical Displays: size=" + logicalDisplayCount);
- for (int i = 0; i < logicalDisplayCount; i++) {
- int displayId = mLogicalDisplays.keyAt(i);
- LogicalDisplay display = mLogicalDisplays.valueAt(i);
- pw.println(" Display " + displayId + ":");
- display.dumpLocked(ipw);
- }
+ mLogicalDisplayMapper.dumpLocked(pw);
pw.println();
mDisplayModeDirector.dump(pw);
@@ -1784,7 +1604,7 @@ public final class DisplayManagerService extends SystemService {
@VisibleForTesting
DisplayDeviceInfo getDisplayDeviceInfoInternal(int displayId) {
synchronized (mSyncRoot) {
- LogicalDisplay display = mLogicalDisplays.get(displayId);
+ LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
if (display != null) {
DisplayDevice displayDevice = display.getPrimaryDisplayDeviceLocked();
return displayDevice.getDisplayDeviceInfoLocked();
@@ -1796,7 +1616,7 @@ public final class DisplayManagerService extends SystemService {
@VisibleForTesting
int getDisplayIdToMirrorInternal(int displayId) {
synchronized (mSyncRoot) {
- LogicalDisplay display = mLogicalDisplays.get(displayId);
+ LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
if (display != null) {
DisplayDevice displayDevice = display.getPrimaryDisplayDeviceLocked();
return displayDevice.getDisplayIdToMirrorLocked();
@@ -1863,20 +1683,20 @@ public final class DisplayManagerService extends SystemService {
}
}
- private final class DisplayDeviceListener implements DisplayDeviceRepository.Listener {
+ private final class LogicalDisplayListener implements LogicalDisplayMapper.Listener {
@Override
- public void onDisplayDeviceEventLocked(DisplayDevice device, int event) {
+ public void onLogicalDisplayEventLocked(LogicalDisplay display, int event) {
switch (event) {
- case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_ADDED:
- handleDisplayDeviceAddedLocked(device);
+ case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_ADDED:
+ handleLogicalDisplayAddedLocked(display);
break;
- case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_CHANGED:
- handleDisplayDeviceChangedLocked(device);
+ case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_CHANGED:
+ handleLogicalDisplayChangedLocked(display);
break;
- case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_REMOVED:
- handleDisplayDeviceRemovedLocked(device);
+ case LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REMOVED:
+ handleLogicalDisplayRemovedLocked(display);
break;
}
}
@@ -1948,7 +1768,7 @@ public final class DisplayManagerService extends SystemService {
final int callingUid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
try {
- return getDisplayIdsInternal(callingUid);
+ return mLogicalDisplayMapper.getDisplayIdsLocked(callingUid);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -2409,7 +2229,8 @@ public final class DisplayManagerService extends SystemService {
@Override // Binder call
public boolean isMinimalPostProcessingRequested(int displayId) {
synchronized (mSyncRoot) {
- return mLogicalDisplays.get(displayId).getRequestedMinimalPostProcessingLocked();
+ return mLogicalDisplayMapper.getLocked(displayId)
+ .getRequestedMinimalPostProcessingLocked();
}
}
@@ -2572,7 +2393,8 @@ public final class DisplayManagerService extends SystemService {
}
}
};
- LogicalDisplay defaultDisplay = mLogicalDisplays.get(Display.DEFAULT_DISPLAY);
+ LogicalDisplay defaultDisplay =
+ mLogicalDisplayMapper.getLocked(Display.DEFAULT_DISPLAY);
DisplayDevice defaultDevice = defaultDisplay.getPrimaryDisplayDeviceLocked();
mDisplayPowerController = new DisplayPowerController(
mContext, callbacks, handler, sensorManager, blanker, defaultDevice);
@@ -2615,7 +2437,7 @@ public final class DisplayManagerService extends SystemService {
@Override
public Point getDisplayPosition(int displayId) {
synchronized (mSyncRoot) {
- LogicalDisplay display = mLogicalDisplays.get(displayId);
+ LogicalDisplay display = mLogicalDisplayMapper.getLocked(displayId);
if (display != null) {
return display.getDisplayPosition();
}
@@ -2720,8 +2542,36 @@ public final class DisplayManagerService extends SystemService {
class DesiredDisplayModeSpecsObserver
implements DisplayModeDirector.DesiredDisplayModeSpecsListener {
+
+ private final Consumer<LogicalDisplay> mSpecsChangedConsumer = display -> {
+ int displayId = display.getDisplayIdLocked();
+ DisplayModeDirector.DesiredDisplayModeSpecs desiredDisplayModeSpecs =
+ mDisplayModeDirector.getDesiredDisplayModeSpecs(displayId);
+ DisplayModeDirector.DesiredDisplayModeSpecs existingDesiredDisplayModeSpecs =
+ display.getDesiredDisplayModeSpecsLocked();
+ if (DEBUG) {
+ Slog.i(TAG,
+ "Comparing display specs: " + desiredDisplayModeSpecs
+ + ", existing: " + existingDesiredDisplayModeSpecs);
+ }
+ if (!desiredDisplayModeSpecs.equals(existingDesiredDisplayModeSpecs)) {
+ display.setDesiredDisplayModeSpecsLocked(desiredDisplayModeSpecs);
+ mChanged = true;
+ }
+ };
+
+ @GuardedBy("mSyncRoot")
+ private boolean mChanged = false;
+
public void onDesiredDisplayModeSpecsChanged() {
- onDesiredDisplayModeSpecsChangedInternal();
+ synchronized (mSyncRoot) {
+ mChanged = false;
+ mLogicalDisplayMapper.forEachLocked(mSpecsChangedConsumer);
+ if (mChanged) {
+ scheduleTraversalLocked(false);
+ mChanged = false;
+ }
+ }
}
}
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
new file mode 100644
index 000000000000..8a90a142a765
--- /dev/null
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display;
+
+import android.os.SystemProperties;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.view.Display;
+import android.view.DisplayInfo;
+
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.function.Consumer;
+
+/**
+ * Responsible for creating {@link LogicalDisplay}s and associating them to the
+ * {@link DisplayDevice} objects supplied through {@link DisplayAdapter.Listener}.
+ *
+ * For devices with a single internal display, the mapping is done once and left
+ * alone. For devices with multiple built-in displays, such as foldable devices,
+ * {@link LogicalDisplay}s can be remapped to different {@link DisplayDevice}s.
+ */
+class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
+ private static final String TAG = "LogicalDisplayMapper";
+
+ public static final int LOGICAL_DISPLAY_EVENT_ADDED = 1;
+ public static final int LOGICAL_DISPLAY_EVENT_CHANGED = 2;
+ public static final int LOGICAL_DISPLAY_EVENT_REMOVED = 3;
+
+ /**
+ * Temporary display info, used for comparing display configurations.
+ */
+ private final DisplayInfo mTempDisplayInfo = new DisplayInfo();
+ private final DisplayInfo mTempNonOverrideDisplayInfo = new DisplayInfo();
+
+ /**
+ * True if the display mapper service should pretend there is only one display
+ * and only tell applications about the existence of the default logical display.
+ * The display manager can still mirror content to secondary displays but applications
+ * cannot present unique content on those displays.
+ * Used for demonstration purposes only.
+ */
+ private final boolean mSingleDisplayDemoMode;
+
+ /**
+ * List of all logical displays indexed by logical display id.
+ * Any modification to mLogicalDisplays must invalidate the DisplayManagerGlobal cache.
+ * TODO: multi-display - Move the aforementioned comment?
+ */
+ private final SparseArray<LogicalDisplay> mLogicalDisplays =
+ new SparseArray<LogicalDisplay>();
+ private int mNextNonDefaultDisplayId = Display.DEFAULT_DISPLAY + 1;
+
+ private final DisplayDeviceRepository mDisplayDeviceRepo;
+ private final PersistentDataStore mPersistentDataStore;
+ private final Listener mListener;
+
+ LogicalDisplayMapper(DisplayDeviceRepository repo, Listener listener,
+ PersistentDataStore persistentDataStore) {
+ mDisplayDeviceRepo = repo;
+ mPersistentDataStore = persistentDataStore;
+ mListener = listener;
+ mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
+ mDisplayDeviceRepo.addListener(this);
+ }
+
+ @Override
+ public void onDisplayDeviceEventLocked(DisplayDevice device, int event) {
+ switch (event) {
+ case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_ADDED:
+ handleDisplayDeviceAddedLocked(device);
+ break;
+
+ case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_CHANGED:
+ updateLogicalDisplaysLocked();
+ break;
+
+ case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_REMOVED:
+ updateLogicalDisplaysLocked();
+ break;
+ }
+ }
+
+ @Override
+ public void onTraversalRequested() {
+ mListener.onTraversalRequested();
+ }
+
+ public LogicalDisplay getLocked(int displayId) {
+ return mLogicalDisplays.get(displayId);
+ }
+
+ public LogicalDisplay getLocked(DisplayDevice device) {
+ final int count = mLogicalDisplays.size();
+ for (int i = 0; i < count; i++) {
+ LogicalDisplay display = mLogicalDisplays.valueAt(i);
+ if (display.getPrimaryDisplayDeviceLocked() == device) {
+ return display;
+ }
+ }
+ return null;
+ }
+
+ public int[] getDisplayIdsLocked(int callingUid) {
+ final int count = mLogicalDisplays.size();
+ int[] displayIds = new int[count];
+ int n = 0;
+ for (int i = 0; i < count; i++) {
+ LogicalDisplay display = mLogicalDisplays.valueAt(i);
+ DisplayInfo info = display.getDisplayInfoLocked();
+ if (info.hasAccess(callingUid)) {
+ displayIds[n++] = mLogicalDisplays.keyAt(i);
+ }
+ }
+ if (n != count) {
+ displayIds = Arrays.copyOfRange(displayIds, 0, n);
+ }
+ return displayIds;
+ }
+
+ public void forEachLocked(Consumer<LogicalDisplay> consumer) {
+ final int count = mLogicalDisplays.size();
+ for (int i = 0; i < count; i++) {
+ consumer.accept(mLogicalDisplays.valueAt(i));
+ }
+ }
+
+ public void dumpLocked(PrintWriter pw) {
+ pw.println("LogicalDisplayMapper:");
+ pw.println(" mSingleDisplayDemoMode=" + mSingleDisplayDemoMode);
+ pw.println(" mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId);
+
+ final int logicalDisplayCount = mLogicalDisplays.size();
+ pw.println();
+ pw.println(" Logical Displays: size=" + logicalDisplayCount);
+
+ IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ ipw.increaseIndent();
+
+ for (int i = 0; i < logicalDisplayCount; i++) {
+ int displayId = mLogicalDisplays.keyAt(i);
+ LogicalDisplay display = mLogicalDisplays.valueAt(i);
+ pw.println(" Display " + displayId + ":");
+ display.dumpLocked(ipw);
+ }
+ }
+
+ private void handleDisplayDeviceAddedLocked(DisplayDevice device) {
+ DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
+ boolean isDefault = (deviceInfo.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
+ if (isDefault && mLogicalDisplays.get(Display.DEFAULT_DISPLAY) != null) {
+ Slog.w(TAG, "Ignoring attempt to add a second default display: " + deviceInfo);
+ isDefault = false;
+ }
+
+ if (!isDefault && mSingleDisplayDemoMode) {
+ Slog.i(TAG, "Not creating a logical display for a secondary display "
+ + " because single display demo mode is enabled: " + deviceInfo);
+ return;
+ }
+
+ final int displayId = assignDisplayIdLocked(isDefault);
+ final int layerStack = assignLayerStackLocked(displayId);
+
+ LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
+ display.updateLocked(mDisplayDeviceRepo);
+ if (!display.isValidLocked()) {
+ // This should never happen currently.
+ Slog.w(TAG, "Ignoring display device because the logical display "
+ + "created from it was not considered valid: " + deviceInfo);
+ return;
+ }
+
+ mLogicalDisplays.put(displayId, display);
+
+ mListener.onLogicalDisplayEventLocked(display,
+ LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_ADDED);
+ }
+
+ /**
+ * Updates all existing logical displays given the current set of display devices.
+ * Removes invalid logical displays. Sends notifications if needed.
+ */
+ private void updateLogicalDisplaysLocked() {
+ for (int i = mLogicalDisplays.size() - 1; i >= 0; i--) {
+ final int displayId = mLogicalDisplays.keyAt(i);
+ LogicalDisplay display = mLogicalDisplays.valueAt(i);
+
+ mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked());
+ display.getNonOverrideDisplayInfoLocked(mTempNonOverrideDisplayInfo);
+ display.updateLocked(mDisplayDeviceRepo);
+ if (!display.isValidLocked()) {
+ mLogicalDisplays.removeAt(i);
+
+ mListener.onLogicalDisplayEventLocked(display,
+ LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REMOVED);
+ } else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) {
+ mListener.onLogicalDisplayEventLocked(display,
+ LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_CHANGED);
+ } else {
+ // While applications shouldn't know nor care about the non-overridden info, we
+ // still need to let WindowManager know so it can update its own internal state for
+ // things like display cutouts.
+ display.getNonOverrideDisplayInfoLocked(mTempDisplayInfo);
+ if (!mTempNonOverrideDisplayInfo.equals(mTempDisplayInfo)) {
+ mListener.onLogicalDisplayEventLocked(display,
+ LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_CHANGED);
+ }
+ }
+ }
+ }
+
+ private int assignDisplayIdLocked(boolean isDefault) {
+ return isDefault ? Display.DEFAULT_DISPLAY : mNextNonDefaultDisplayId++;
+ }
+
+ private int assignLayerStackLocked(int displayId) {
+ // Currently layer stacks and display ids are the same.
+ // This need not be the case.
+ return displayId;
+ }
+
+ public interface Listener {
+ void onLogicalDisplayEventLocked(LogicalDisplay display, int event);
+ void onTraversalRequested();
+ }
+}
diff --git a/services/core/java/com/android/server/display/PersistentDataStore.java b/services/core/java/com/android/server/display/PersistentDataStore.java
index 9aec43b6eaed..09b0b3a8dee2 100644
--- a/services/core/java/com/android/server/display/PersistentDataStore.java
+++ b/services/core/java/com/android/server/display/PersistentDataStore.java
@@ -216,7 +216,7 @@ final class PersistentDataStore {
}
public boolean forgetWifiDisplay(String deviceAddress) {
- loadIfNeeded();
+ loadIfNeeded();
int index = findRememberedWifiDisplay(deviceAddress);
if (index >= 0) {
mRememberedWifiDisplays.remove(index);
@@ -259,17 +259,17 @@ final class PersistentDataStore {
return false;
}
- public Point getStableDisplaySize() {
- loadIfNeeded();
- return mStableDeviceValues.getDisplaySize();
- }
-
- public void setStableDisplaySize(Point size) {
- loadIfNeeded();
- if (mStableDeviceValues.setDisplaySize(size)) {
- setDirty();
- }
- }
+ public Point getStableDisplaySize() {
+ loadIfNeeded();
+ return mStableDeviceValues.getDisplaySize();
+ }
+
+ public void setStableDisplaySize(Point size) {
+ loadIfNeeded();
+ if (mStableDeviceValues.setDisplaySize(size)) {
+ setDirty();
+ }
+ }
public void setBrightnessConfigurationForUser(BrightnessConfiguration c, int userSerial,
@Nullable String packageName) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index a60a676cfa95..27bd0563cea5 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -2240,7 +2240,7 @@ public class HdmiControlService extends SystemService {
@Override
public void setHdmiCecVolumeControlEnabled(final boolean isHdmiCecVolumeControlEnabled) {
enforceAccessPermission();
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
HdmiControlService.this.setHdmiCecVolumeControlEnabled(
isHdmiCecVolumeControlEnabled);
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index a2304f4ad158..653645794f95 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -55,6 +55,8 @@ import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
+import android.os.InputEventInjectionResult;
+import android.os.InputEventInjectionSync;
import android.os.LocaleList;
import android.os.Looper;
import android.os.Message;
@@ -268,12 +270,6 @@ public class InputManagerService extends IInputManager.Stub
private static native void nativeNotifyPortAssociationsChanged(long ptr);
private static native void nativeSetMotionClassifierEnabled(long ptr, boolean enabled);
- // Input event injection constants defined in InputDispatcher.h.
- private static final int INPUT_EVENT_INJECTION_SUCCEEDED = 0;
- private static final int INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1;
- private static final int INPUT_EVENT_INJECTION_FAILED = 2;
- private static final int INPUT_EVENT_INJECTION_TIMED_OUT = 3;
-
// Maximum number of milliseconds to wait for input event injection.
private static final int INJECTION_TIMEOUT_MILLIS = 30 * 1000;
@@ -691,9 +687,9 @@ public class InputManagerService extends IInputManager.Stub
if (event == null) {
throw new IllegalArgumentException("event must not be null");
}
- if (mode != InputManager.INJECT_INPUT_EVENT_MODE_ASYNC
- && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH
- && mode != InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT) {
+ if (mode != InputEventInjectionSync.NONE
+ && mode != InputEventInjectionSync.WAIT_FOR_FINISHED
+ && mode != InputEventInjectionSync.WAIT_FOR_RESULT) {
throw new IllegalArgumentException("mode is invalid");
}
@@ -708,16 +704,16 @@ public class InputManagerService extends IInputManager.Stub
Binder.restoreCallingIdentity(ident);
}
switch (result) {
- case INPUT_EVENT_INJECTION_PERMISSION_DENIED:
+ case InputEventInjectionResult.PERMISSION_DENIED:
Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
throw new SecurityException(
"Injecting to another application requires INJECT_EVENTS permission");
- case INPUT_EVENT_INJECTION_SUCCEEDED:
+ case InputEventInjectionResult.SUCCEEDED:
return true;
- case INPUT_EVENT_INJECTION_TIMED_OUT:
+ case InputEventInjectionResult.TIMED_OUT:
Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
return false;
- case INPUT_EVENT_INJECTION_FAILED:
+ case InputEventInjectionResult.FAILED:
default:
Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
return false;
diff --git a/services/core/java/com/android/server/inputmethod/InputContentUriTokenHandler.java b/services/core/java/com/android/server/inputmethod/InputContentUriTokenHandler.java
index 845fca1127dd..78c414452ddd 100644
--- a/services/core/java/com/android/server/inputmethod/InputContentUriTokenHandler.java
+++ b/services/core/java/com/android/server/inputmethod/InputContentUriTokenHandler.java
@@ -73,7 +73,7 @@ final class InputContentUriTokenHandler extends IInputContentUriToken.Stub {
}
private void doTakeLocked(@NonNull IBinder permissionOwner) {
- long origId = Binder.clearCallingIdentity();
+ final long origId = Binder.clearCallingIdentity();
try {
try {
UriGrantsManager.getService().grantUriPermissionFromOwner(
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 2eccaf1434b4..9947ecd42e31 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -15,10 +15,36 @@
package com.android.server.inputmethod;
+import static android.server.inputmethod.InputMethodManagerServiceProto.ACCESSIBILITY_REQUESTING_NO_SOFT_KEYBOARD;
+import static android.server.inputmethod.InputMethodManagerServiceProto.BACK_DISPOSITION;
+import static android.server.inputmethod.InputMethodManagerServiceProto.BOUND_TO_METHOD;
+import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_ATTRIBUTE;
+import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_CLIENT;
+import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_FOCUSED_WINDOW_NAME;
+import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_FOCUSED_WINDOW_SOFT_INPUT_MODE;
+import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_ID;
+import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_METHOD_ID;
+import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_SEQ;
+import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_TOKEN;
+import static android.server.inputmethod.InputMethodManagerServiceProto.CUR_TOKEN_DISPLAY_ID;
+import static android.server.inputmethod.InputMethodManagerServiceProto.HAVE_CONNECTION;
+import static android.server.inputmethod.InputMethodManagerServiceProto.IME_WINDOW_VISIBILITY;
+import static android.server.inputmethod.InputMethodManagerServiceProto.INPUT_SHOWN;
+import static android.server.inputmethod.InputMethodManagerServiceProto.IN_FULLSCREEN_MODE;
+import static android.server.inputmethod.InputMethodManagerServiceProto.IS_INTERACTIVE;
+import static android.server.inputmethod.InputMethodManagerServiceProto.LAST_IME_TARGET_WINDOW_NAME;
+import static android.server.inputmethod.InputMethodManagerServiceProto.LAST_SWITCH_USER_ID;
+import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_EXPLICITLY_REQUESTED;
+import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_FORCED;
+import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_IME_WITH_HARD_KEYBOARD;
+import static android.server.inputmethod.InputMethodManagerServiceProto.SHOW_REQUESTED;
+import static android.server.inputmethod.InputMethodManagerServiceProto.SYSTEM_READY;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.CLIENTS;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.ELAPSED_REALTIME_NANOS;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.INPUT_METHOD_MANAGER_SERVICE;
+import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorProto.INPUT_METHOD_SERVICE;
import static android.view.inputmethod.InputMethodEditorTraceProto.InputMethodEditorTraceFileProto.ENTRY;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -37,8 +63,6 @@ import android.annotation.RequiresPermission;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityThread;
-import android.app.AlertDialog;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.KeyguardManager;
@@ -50,9 +74,6 @@ import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnCancelListener;
-import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
@@ -64,10 +85,8 @@ import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.Matrix;
-import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.input.InputManagerInternal;
import android.inputmethodservice.InputMethodService;
@@ -77,6 +96,7 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.IInterface;
import android.os.LocaleList;
@@ -108,14 +128,10 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.imetracing.ImeTracing;
import android.util.proto.ProtoOutputStream;
-import android.view.ContextThemeWrapper;
import android.view.DisplayInfo;
import android.view.IWindowManager;
import android.view.InputChannel;
-import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
import android.view.WindowManager.LayoutParams;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import android.view.autofill.AutofillId;
@@ -129,12 +145,6 @@ import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
-import android.widget.ArrayAdapter;
-import android.widget.CompoundButton;
-import android.widget.CompoundButton.OnCheckedChangeListener;
-import android.widget.RadioButton;
-import android.widget.Switch;
-import android.widget.TextView;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
@@ -165,7 +175,6 @@ import com.android.internal.view.InputBindResult;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.SystemService;
-import com.android.server.SystemService.TargetUser;
import com.android.server.inputmethod.InputMethodManagerInternal.InputMethodListListener;
import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
import com.android.server.inputmethod.InputMethodUtils.InputMethodSettings;
@@ -330,10 +339,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypeMap =
new ArrayMap<>();
private final boolean mIsLowRam;
- private final HardKeyboardListener mHardKeyboardListener;
private final AppOpsManager mAppOpsManager;
private final UserManager mUserManager;
private final UserManagerInternal mUserManagerInternal;
+ private final InputMethodMenuController mMenuController;
/**
* Cache the result of {@code LocalServices.getService(AudioManagerInternal.class)}.
@@ -351,7 +360,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
final ArrayMap<String, InputMethodInfo> mMethodMap = new ArrayMap<>();
private final LruCache<SuggestionSpan, InputMethodInfo> mSecureSuggestionSpans =
new LruCache<>(SECURE_SUGGESTION_SPANS_MAX_SIZE);
- private final InputMethodSubtypeSwitchingController mSwitchingController;
+ final InputMethodSubtypeSwitchingController mSwitchingController;
/**
* Tracks how many times {@link #mMethodMap} was updated.
@@ -380,7 +389,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// Ongoing notification
private NotificationManager mNotificationManager;
- private KeyguardManager mKeyguardManager;
+ KeyguardManager mKeyguardManager;
private @Nullable StatusBarManagerService mStatusBar;
private Notification.Builder mImeSwitcherNotification;
private PendingIntent mImeSwitchPendingIntent;
@@ -724,21 +733,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
*/
int mImeWindowVis;
- private AlertDialog.Builder mDialogBuilder;
- private AlertDialog mSwitchingDialog;
- private IBinder mSwitchingDialogToken = new Binder();
- private View mSwitchingDialogTitleView;
- private InputMethodInfo[] mIms;
- private int[] mSubtypeIds;
private LocaleList mLastSystemLocales;
- private boolean mShowImeWithHardKeyboard;
private boolean mAccessibilityRequestingNoSoftKeyboard;
private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
private final IPackageManager mIPackageManager;
private final String mSlotIme;
+ private HandlerThread mTracingThread;
+
/**
- * Registered {@link InputMethodListListeners}.
+ * Registered {@link InputMethodListListener}.
* This variable can be accessed from both of MainThread and BinderThread.
*/
private final CopyOnWriteArrayList<InputMethodListListener> mInputMethodListListeners =
@@ -1138,7 +1142,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
synchronized (mMethodMap) {
if (showImeUri.equals(uri)) {
- updateKeyboardFromSettingsLocked();
+ mMenuController.updateKeyboardFromSettingsLocked();
} else if (accessibilityRequestingNoImeUri.equals(uri)) {
final int accessibilitySoftKeyboardSetting = Settings.Secure.getIntForUser(
mContext.getContentResolver(),
@@ -1226,7 +1230,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return;
}
}
- hideInputMethodMenu();
+ mMenuController.hideInputMethodMenu();
} else {
Slog.w(TAG, "Unexpected intent " + intent);
}
@@ -1517,7 +1521,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
@Override
public void sessionCreated(IInputMethodSession session) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
mParentIMMS.onSessionCreated(mMethod, session, mChannel);
} finally {
@@ -1526,29 +1530,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- private class HardKeyboardListener
- implements WindowManagerInternal.OnHardKeyboardStatusChangeListener {
- @Override
- public void onHardKeyboardStatusChange(boolean available) {
- mHandler.sendMessage(mHandler.obtainMessage(MSG_HARD_KEYBOARD_SWITCH_CHANGED,
- available ? 1 : 0));
- }
-
- public void handleHardKeyboardStatusChange(boolean available) {
- if (DEBUG) {
- Slog.w(TAG, "HardKeyboardStatusChanged: available=" + available);
- }
- synchronized(mMethodMap) {
- if (mSwitchingDialog != null && mSwitchingDialogTitleView != null
- && mSwitchingDialog.isShowing()) {
- mSwitchingDialogTitleView.findViewById(
- com.android.internal.R.id.hard_keyboard_section).setVisibility(
- available ? View.VISIBLE : View.GONE);
- }
- }
- }
- }
-
private static final class UserSwitchHandlerTask implements Runnable {
final InputMethodManagerService mService;
@@ -1687,7 +1668,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
mUserManager = mContext.getSystemService(UserManager.class);
mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
- mHardKeyboardListener = new HardKeyboardListener();
mHasFeature = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_INPUT_METHODS);
mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);
@@ -1731,6 +1711,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, userId);
mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
mSettings, context);
+ mMenuController = new InputMethodMenuController(this);
+
+ mTracingThread = new HandlerThread("android.tracing", Process.THREAD_PRIORITY_BACKGROUND);
+ mTracingThread.start();
}
private void resetDefaultImeLocked(Context context) {
@@ -1861,8 +1845,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
com.android.internal.R.bool.show_ongoing_ime_switcher);
if (mShowOngoingImeSwitcherForPhones) {
+ final InputMethodMenuController.HardKeyboardListener hardKeyboardListener =
+ mMenuController.getHardKeyboardListener();
mWindowManagerInternal.setOnHardKeyboardStatusChangeListener(
- mHardKeyboardListener);
+ hardKeyboardListener);
}
mMyPackageMonitor.register(mContext, null, UserHandle.ALL, true);
@@ -2331,7 +2317,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mCurClient = null;
mCurActivityViewToScreenMatrix = null;
- hideInputMethodMenuLocked();
+ mMenuController.hideInputMethodMenuLocked();
}
}
@@ -2813,7 +2799,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
private boolean shouldShowImeSwitcherLocked(int visibility) {
if (!mShowOngoingImeSwitcherForPhones) return false;
- if (mSwitchingDialog != null) return false;
+ if (mMenuController.getSwitchingDialogLocked() != null) return false;
if (mWindowManagerInternal.isKeyguardShowingAndNotOccluded()
&& mKeyguardManager != null && mKeyguardManager.isKeyguardSecure()) return false;
if ((visibility & InputMethodService.IME_ACTIVE) == 0
@@ -2930,6 +2916,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
+ void updateSystemUiLocked() {
+ updateSystemUiLocked(mImeWindowVis, mBackDisposition);
+ }
+
// Caution! This method is called in this class. Handle multi-user carefully
private void updateSystemUiLocked(int vis, int backDisposition) {
if (mCurToken == null) {
@@ -3000,7 +2990,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
void updateFromSettingsLocked(boolean enabledMayChange) {
updateInputMethodsFromSettingsLocked(enabledMayChange);
- updateKeyboardFromSettingsLocked();
+ mMenuController.updateKeyboardFromSettingsLocked();
}
void updateInputMethodsFromSettingsLocked(boolean enabledMayChange) {
@@ -3057,17 +3047,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
- public void updateKeyboardFromSettingsLocked() {
- mShowImeWithHardKeyboard = mSettings.isShowImeWithHardKeyboardEnabled();
- if (mSwitchingDialog != null
- && mSwitchingDialogTitleView != null
- && mSwitchingDialog.isShowing()) {
- final Switch hardKeySwitch = (Switch)mSwitchingDialogTitleView.findViewById(
- com.android.internal.R.id.hard_keyboard_switch);
- hardKeySwitch.setChecked(mShowImeWithHardKeyboard);
- }
- }
-
/* package */ void setInputMethodLocked(String id, int subtypeId) {
InputMethodInfo info = mMethodMap.get(id);
if (info == null) {
@@ -3697,10 +3676,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
public boolean isInputMethodPickerShownForTest() {
synchronized(mMethodMap) {
- if (mSwitchingDialog == null) {
- return false;
- }
- return mSwitchingDialog.isShowing();
+ return mMenuController.isisInputMethodPickerShownForTestLocked();
}
}
@@ -3935,7 +3911,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
* {@link InputMethodService#onCreate()}.
*
* <p>TODO(Bug 113914148): Check if we can remove this.</p>
- * @return {@link WindowManagerInternal#getInputMethodWindowVisibleHeight()}
+ * @return {@link WindowManagerInternal#getInputMethodWindowVisibleHeight(int)}
*/
@Override
public int getInputMethodWindowVisibleHeight() {
@@ -4045,40 +4021,59 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
*/
@BinderThread
@Override
+ @GuardedBy("mMethodMap")
public void startProtoDump(byte[] clientProtoDump) {
- if (!ImeTracing.getInstance().isAvailable() || !ImeTracing.getInstance().isEnabled()) {
- return;
- }
- if (clientProtoDump == null && mCurClient == null) {
- return;
- }
+ mTracingThread.getThreadHandler().post(() -> {
+ if (!ImeTracing.getInstance().isAvailable() || !ImeTracing.getInstance().isEnabled()) {
+ return;
+ }
+ if (clientProtoDump == null && mCurClient == null) {
+ return;
+ }
- ProtoOutputStream proto = new ProtoOutputStream();
- final long token = proto.start(ENTRY);
- proto.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
- // TODO: get server side dump
- if (clientProtoDump != null) {
- proto.write(CLIENTS, clientProtoDump);
- } else {
- IBinder client = null;
+ ProtoOutputStream proto = new ProtoOutputStream();
+ final long token = proto.start(ENTRY);
+ proto.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
+ dumpDebug(proto, INPUT_METHOD_MANAGER_SERVICE);
+ IBinder service = null;
synchronized (mMethodMap) {
- if (mCurClient != null && mCurClient.client != null) {
- client = mCurClient.client.asBinder();
+ if (mCurMethod != null) {
+ service = mCurMethod.asBinder();
}
}
- if (client != null) {
+ if (service != null) {
try {
- proto.write(CLIENTS,
- TransferPipe.dumpAsync(client, ImeTracing.PROTO_ARG));
+ proto.write(INPUT_METHOD_SERVICE,
+ TransferPipe.dumpAsync(service, ImeTracing.PROTO_ARG));
} catch (IOException | RemoteException e) {
- Log.e(TAG, "Exception while collecting client side ime dump", e);
+ Log.e(TAG, "Exception while collecting ime process dump", e);
}
}
- }
- proto.end(token);
- ImeTracing.getInstance().addToBuffer(proto);
+
+ if (clientProtoDump != null) {
+ proto.write(CLIENTS, clientProtoDump);
+ } else {
+ IBinder client = null;
+ synchronized (mMethodMap) {
+ if (mCurClient != null && mCurClient.client != null) {
+ client = mCurClient.client.asBinder();
+ }
+ }
+
+ if (client != null) {
+ try {
+ proto.write(CLIENTS,
+ TransferPipe.dumpAsync(client, ImeTracing.PROTO_ARG));
+ } catch (IOException | RemoteException e) {
+ Log.e(TAG, "Exception while collecting client side ime dump", e);
+ }
+ }
+ }
+ proto.end(token);
+ ImeTracing.getInstance().addToBuffer(proto);
+ });
}
@BinderThread
@@ -4087,6 +4082,44 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return ImeTracing.getInstance().isEnabled();
}
+ @GuardedBy("mMethodMap")
+ private void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ synchronized (mMethodMap) {
+ final long token = proto.start(fieldId);
+ proto.write(CUR_METHOD_ID, mCurMethodId);
+ proto.write(CUR_SEQ, mCurSeq);
+ proto.write(CUR_CLIENT, Objects.toString(mCurClient));
+ proto.write(CUR_FOCUSED_WINDOW_NAME,
+ mWindowManagerInternal.getWindowName(mCurFocusedWindow));
+ proto.write(LAST_IME_TARGET_WINDOW_NAME,
+ mWindowManagerInternal.getWindowName(mLastImeTargetWindow));
+ proto.write(CUR_FOCUSED_WINDOW_SOFT_INPUT_MODE,
+ InputMethodDebug.softInputModeToString(mCurFocusedWindowSoftInputMode));
+ if (mCurAttribute != null) {
+ mCurAttribute.dumpDebug(proto, CUR_ATTRIBUTE);
+ }
+ proto.write(CUR_ID, mCurId);
+ proto.write(SHOW_REQUESTED, mShowRequested);
+ proto.write(SHOW_EXPLICITLY_REQUESTED, mShowExplicitlyRequested);
+ proto.write(SHOW_FORCED, mShowForced);
+ proto.write(INPUT_SHOWN, mInputShown);
+ proto.write(IN_FULLSCREEN_MODE, mInFullscreenMode);
+ proto.write(CUR_TOKEN, Objects.toString(mCurToken));
+ proto.write(CUR_TOKEN_DISPLAY_ID, mCurTokenDisplayId);
+ proto.write(SYSTEM_READY, mSystemReady);
+ proto.write(LAST_SWITCH_USER_ID, mLastSwitchUserId);
+ proto.write(HAVE_CONNECTION, mHaveConnection);
+ proto.write(BOUND_TO_METHOD, mBoundToMethod);
+ proto.write(IS_INTERACTIVE, mIsInteractive);
+ proto.write(BACK_DISPOSITION, mBackDisposition);
+ proto.write(IME_WINDOW_VISIBILITY, mImeWindowVis);
+ proto.write(SHOW_IME_WITH_HARD_KEYBOARD, mMenuController.getShowImeWithHardKeyboard());
+ proto.write(ACCESSIBILITY_REQUESTING_NO_SOFT_KEYBOARD,
+ mAccessibilityRequestingNoSoftKeyboard);
+ proto.end(token);
+ }
+ }
+
@BinderThread
private void notifyUserAction(@NonNull IBinder token) {
if (DEBUG) {
@@ -4174,7 +4207,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (!calledWithValidTokenLocked(token)) {
return;
}
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
hideCurrentInputLocked(
mLastImeTargetWindow, flags, null,
@@ -4192,7 +4225,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (!calledWithValidTokenLocked(token)) {
return;
}
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
showCurrentInputLocked(mLastImeTargetWindow, flags, null,
SoftInputShowHideReason.SHOW_MY_SOFT_INPUT);
@@ -4247,7 +4280,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
Slog.e(TAG, "Unknown subtype picker mode = " + msg.arg1);
return false;
}
- showInputMethodMenu(showAuxSubtypes, displayId);
+ mMenuController.showInputMethodMenu(showAuxSubtypes, displayId);
return true;
case MSG_SHOW_IM_SUBTYPE_ENABLER:
@@ -4484,7 +4517,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// --------------------------------------------------------------
case MSG_HARD_KEYBOARD_SWITCH_CHANGED:
- mHardKeyboardListener.handleHardKeyboardStatusChange(msg.arg1 == 1);
+ final InputMethodMenuController.HardKeyboardListener hardKeyboardListener =
+ mMenuController.getHardKeyboardListener();
+ hardKeyboardListener.handleHardKeyboardStatusChange(msg.arg1 == 1);
return true;
case MSG_SYSTEM_UNLOCK_USER: {
final int userId = msg.arg1;
@@ -4735,208 +4770,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mContext.startActivityAsUser(intent, null, UserHandle.CURRENT);
}
- private boolean isScreenLocked() {
- return mKeyguardManager != null
- && mKeyguardManager.isKeyguardLocked() && mKeyguardManager.isKeyguardSecure();
- }
-
- private void showInputMethodMenu(boolean showAuxSubtypes, int displayId) {
- if (DEBUG) Slog.v(TAG, "Show switching menu. showAuxSubtypes=" + showAuxSubtypes);
-
- final boolean isScreenLocked = isScreenLocked();
-
- final String lastInputMethodId = mSettings.getSelectedInputMethod();
- int lastInputMethodSubtypeId = mSettings.getSelectedInputMethodSubtypeId(lastInputMethodId);
- if (DEBUG) Slog.v(TAG, "Current IME: " + lastInputMethodId);
-
- synchronized (mMethodMap) {
- final List<ImeSubtypeListItem> imList =
- mSwitchingController.getSortedInputMethodAndSubtypeListLocked(
- showAuxSubtypes, isScreenLocked);
- if (imList.isEmpty()) {
- return;
- }
-
- hideInputMethodMenuLocked();
-
- if (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID) {
- final InputMethodSubtype currentSubtype = getCurrentInputMethodSubtypeLocked();
- if (currentSubtype != null) {
- final InputMethodInfo currentImi = mMethodMap.get(mCurMethodId);
- lastInputMethodSubtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
- currentImi, currentSubtype.hashCode());
- }
- }
-
- final int N = imList.size();
- mIms = new InputMethodInfo[N];
- mSubtypeIds = new int[N];
- int checkedItem = 0;
- for (int i = 0; i < N; ++i) {
- final ImeSubtypeListItem item = imList.get(i);
- mIms[i] = item.mImi;
- mSubtypeIds[i] = item.mSubtypeId;
- if (mIms[i].getId().equals(lastInputMethodId)) {
- int subtypeId = mSubtypeIds[i];
- if ((subtypeId == NOT_A_SUBTYPE_ID)
- || (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID && subtypeId == 0)
- || (subtypeId == lastInputMethodSubtypeId)) {
- checkedItem = i;
- }
- }
- }
-
- final ActivityThread currentThread = ActivityThread.currentActivityThread();
- final Context settingsContext = new ContextThemeWrapper(
- displayId == DEFAULT_DISPLAY ? currentThread.getSystemUiContext()
- : currentThread.createSystemUiContext(displayId),
- com.android.internal.R.style.Theme_DeviceDefault_Settings);
-
- mDialogBuilder = new AlertDialog.Builder(settingsContext);
- mDialogBuilder.setOnCancelListener(new OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialog) {
- hideInputMethodMenu();
- }
- });
-
- final Context dialogContext = mDialogBuilder.getContext();
- final TypedArray a = dialogContext.obtainStyledAttributes(null,
- com.android.internal.R.styleable.DialogPreference,
- com.android.internal.R.attr.alertDialogStyle, 0);
- final Drawable dialogIcon = a.getDrawable(
- com.android.internal.R.styleable.DialogPreference_dialogIcon);
- a.recycle();
-
- mDialogBuilder.setIcon(dialogIcon);
-
- final LayoutInflater inflater = dialogContext.getSystemService(LayoutInflater.class);
- final View tv = inflater.inflate(
- com.android.internal.R.layout.input_method_switch_dialog_title, null);
- mDialogBuilder.setCustomTitle(tv);
-
- // Setup layout for a toggle switch of the hardware keyboard
- mSwitchingDialogTitleView = tv;
- mSwitchingDialogTitleView
- .findViewById(com.android.internal.R.id.hard_keyboard_section)
- .setVisibility(mWindowManagerInternal.isHardKeyboardAvailable()
- ? View.VISIBLE : View.GONE);
- final Switch hardKeySwitch = (Switch) mSwitchingDialogTitleView.findViewById(
- com.android.internal.R.id.hard_keyboard_switch);
- hardKeySwitch.setChecked(mShowImeWithHardKeyboard);
- hardKeySwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- mSettings.setShowImeWithHardKeyboard(isChecked);
- // Ensure that the input method dialog is dismissed when changing
- // the hardware keyboard state.
- hideInputMethodMenu();
- }
- });
-
- final ImeSubtypeListAdapter adapter = new ImeSubtypeListAdapter(dialogContext,
- com.android.internal.R.layout.input_method_switch_item, imList, checkedItem);
- final OnClickListener choiceListener = new OnClickListener() {
- @Override
- public void onClick(final DialogInterface dialog, final int which) {
- synchronized (mMethodMap) {
- if (mIms == null || mIms.length <= which || mSubtypeIds == null
- || mSubtypeIds.length <= which) {
- return;
- }
- final InputMethodInfo im = mIms[which];
- int subtypeId = mSubtypeIds[which];
- adapter.mCheckedItem = which;
- adapter.notifyDataSetChanged();
- hideInputMethodMenu();
- if (im != null) {
- if (subtypeId < 0 || subtypeId >= im.getSubtypeCount()) {
- subtypeId = NOT_A_SUBTYPE_ID;
- }
- setInputMethodLocked(im.getId(), subtypeId);
- }
- }
- }
- };
- mDialogBuilder.setSingleChoiceItems(adapter, checkedItem, choiceListener);
-
- mSwitchingDialog = mDialogBuilder.create();
- mSwitchingDialog.setCanceledOnTouchOutside(true);
- final Window w = mSwitchingDialog.getWindow();
- final LayoutParams attrs = w.getAttributes();
- w.setType(LayoutParams.TYPE_INPUT_METHOD_DIALOG);
- // Use an alternate token for the dialog for that window manager can group the token
- // with other IME windows based on type vs. grouping based on whichever token happens
- // to get selected by the system later on.
- attrs.token = mSwitchingDialogToken;
- attrs.privateFlags |= LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
- attrs.setTitle("Select input method");
- w.setAttributes(attrs);
- updateSystemUiLocked(mImeWindowVis, mBackDisposition);
- mSwitchingDialog.show();
- }
- }
-
- private static class ImeSubtypeListAdapter extends ArrayAdapter<ImeSubtypeListItem> {
- private final LayoutInflater mInflater;
- private final int mTextViewResourceId;
- private final List<ImeSubtypeListItem> mItemsList;
- public int mCheckedItem;
- public ImeSubtypeListAdapter(Context context, int textViewResourceId,
- List<ImeSubtypeListItem> itemsList, int checkedItem) {
- super(context, textViewResourceId, itemsList);
-
- mTextViewResourceId = textViewResourceId;
- mItemsList = itemsList;
- mCheckedItem = checkedItem;
- mInflater = context.getSystemService(LayoutInflater.class);
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- final View view = convertView != null ? convertView
- : mInflater.inflate(mTextViewResourceId, null);
- if (position < 0 || position >= mItemsList.size()) return view;
- final ImeSubtypeListItem item = mItemsList.get(position);
- final CharSequence imeName = item.mImeName;
- final CharSequence subtypeName = item.mSubtypeName;
- final TextView firstTextView = (TextView)view.findViewById(android.R.id.text1);
- final TextView secondTextView = (TextView)view.findViewById(android.R.id.text2);
- if (TextUtils.isEmpty(subtypeName)) {
- firstTextView.setText(imeName);
- secondTextView.setVisibility(View.GONE);
- } else {
- firstTextView.setText(subtypeName);
- secondTextView.setText(imeName);
- secondTextView.setVisibility(View.VISIBLE);
- }
- final RadioButton radioButton =
- (RadioButton)view.findViewById(com.android.internal.R.id.radio);
- radioButton.setChecked(position == mCheckedItem);
- return view;
- }
- }
-
- void hideInputMethodMenu() {
- synchronized (mMethodMap) {
- hideInputMethodMenuLocked();
- }
- }
-
- void hideInputMethodMenuLocked() {
- if (DEBUG) Slog.v(TAG, "Hide switching menu");
-
- if (mSwitchingDialog != null) {
- mSwitchingDialog.dismiss();
- mSwitchingDialog = null;
- mSwitchingDialogTitleView = null;
- }
-
- updateSystemUiLocked(mImeWindowVis, mBackDisposition);
- mDialogBuilder = null;
- mIms = null;
- }
-
// ----------------------------------------------------------------------
/**
@@ -5040,7 +4873,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- private InputMethodSubtype getCurrentInputMethodSubtypeLocked() {
+ InputMethodSubtype getCurrentInputMethodSubtypeLocked() {
if (mCurMethodId == null) {
return null;
}
@@ -5079,6 +4912,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return mCurrentSubtype;
}
+ @Nullable
+ String getCurrentMethodId() {
+ return mCurMethodId;
+ }
+
private List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
synchronized (mMethodMap) {
return getInputMethodListLocked(userId);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
new file mode 100644
index 000000000000..7b29e5bcebb8
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.inputmethod;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+import static com.android.server.inputmethod.InputMethodManagerService.DEBUG;
+import static com.android.server.inputmethod.InputMethodManagerService.MSG_HARD_KEYBOARD_SWITCH_CHANGED;
+import static com.android.server.inputmethod.InputMethodUtils.NOT_A_SUBTYPE_ID;
+
+import android.app.ActivityThread;
+import android.app.AlertDialog;
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.IBinder;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Slog;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
+import android.widget.ArrayAdapter;
+import android.widget.RadioButton;
+import android.widget.Switch;
+import android.widget.TextView;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
+import com.android.server.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
+import com.android.server.wm.WindowManagerInternal;
+
+import java.util.List;
+
+/** A controller to show/hide the input method menu */
+@VisibleForTesting(visibility = PACKAGE)
+public class InputMethodMenuController {
+ private static final String TAG = InputMethodMenuController.class.getSimpleName();
+
+ private final InputMethodManagerService mService;
+ private final InputMethodUtils.InputMethodSettings mSettings;
+ private final InputMethodSubtypeSwitchingController mSwitchingController;
+ private final Handler mHandler;
+ private final ArrayMap<String, InputMethodInfo> mMethodMap;
+ private final KeyguardManager mKeyguardManager;
+ private final HardKeyboardListener mHardKeyboardListener;
+ private final WindowManagerInternal mWindowManagerInternal;
+
+ private Context mSettingsContext;
+ private AlertDialog.Builder mDialogBuilder;
+ private AlertDialog mSwitchingDialog;
+ private IBinder mSwitchingDialogToken;
+ private View mSwitchingDialogTitleView;
+ private InputMethodInfo[] mIms;
+ private int[] mSubtypeIds;
+
+ private boolean mShowImeWithHardKeyboard;
+
+ @VisibleForTesting(visibility = PACKAGE)
+ public InputMethodMenuController(InputMethodManagerService service) {
+ mService = service;
+ mSettings = mService.mSettings;
+ mSwitchingController = mService.mSwitchingController;
+ mHandler = mService.mHandler;
+ mMethodMap = mService.mMethodMap;
+ mKeyguardManager = mService.mKeyguardManager;
+ mHardKeyboardListener = new HardKeyboardListener();
+ mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
+ }
+
+ void showInputMethodMenu(boolean showAuxSubtypes, int displayId) {
+ if (DEBUG) Slog.v(TAG, "Show switching menu. showAuxSubtypes=" + showAuxSubtypes);
+
+ final boolean isScreenLocked = isScreenLocked();
+
+ final String lastInputMethodId = mSettings.getSelectedInputMethod();
+ int lastInputMethodSubtypeId = mSettings.getSelectedInputMethodSubtypeId(lastInputMethodId);
+ if (DEBUG) Slog.v(TAG, "Current IME: " + lastInputMethodId);
+
+ synchronized (mMethodMap) {
+ final List<ImeSubtypeListItem> imList = mSwitchingController
+ .getSortedInputMethodAndSubtypeListLocked(showAuxSubtypes, isScreenLocked);
+ if (imList.isEmpty()) {
+ return;
+ }
+
+ hideInputMethodMenuLocked();
+
+ if (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID) {
+ final InputMethodSubtype currentSubtype =
+ mService.getCurrentInputMethodSubtypeLocked();
+ if (currentSubtype != null) {
+ final String curMethodId = mService.getCurrentMethodId();
+ final InputMethodInfo currentImi = mMethodMap.get(curMethodId);
+ lastInputMethodSubtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
+ currentImi, currentSubtype.hashCode());
+ }
+ }
+
+ final int size = imList.size();
+ mIms = new InputMethodInfo[size];
+ mSubtypeIds = new int[size];
+ int checkedItem = 0;
+ for (int i = 0; i < size; ++i) {
+ final ImeSubtypeListItem item = imList.get(i);
+ mIms[i] = item.mImi;
+ mSubtypeIds[i] = item.mSubtypeId;
+ if (mIms[i].getId().equals(lastInputMethodId)) {
+ int subtypeId = mSubtypeIds[i];
+ if ((subtypeId == NOT_A_SUBTYPE_ID)
+ || (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID && subtypeId == 0)
+ || (subtypeId == lastInputMethodSubtypeId)) {
+ checkedItem = i;
+ }
+ }
+ }
+
+ final Context settingsContext = getSettingsContext(displayId);
+ mDialogBuilder = new AlertDialog.Builder(settingsContext);
+ mDialogBuilder.setOnCancelListener(dialog -> hideInputMethodMenu());
+
+ final Context dialogContext = mDialogBuilder.getContext();
+ final TypedArray a = dialogContext.obtainStyledAttributes(null,
+ com.android.internal.R.styleable.DialogPreference,
+ com.android.internal.R.attr.alertDialogStyle, 0);
+ final Drawable dialogIcon = a.getDrawable(
+ com.android.internal.R.styleable.DialogPreference_dialogIcon);
+ a.recycle();
+
+ mDialogBuilder.setIcon(dialogIcon);
+
+ final LayoutInflater inflater = dialogContext.getSystemService(LayoutInflater.class);
+ final View tv = inflater.inflate(
+ com.android.internal.R.layout.input_method_switch_dialog_title, null);
+ mDialogBuilder.setCustomTitle(tv);
+
+ // Setup layout for a toggle switch of the hardware keyboard
+ mSwitchingDialogTitleView = tv;
+ mSwitchingDialogTitleView
+ .findViewById(com.android.internal.R.id.hard_keyboard_section)
+ .setVisibility(mWindowManagerInternal.isHardKeyboardAvailable()
+ ? View.VISIBLE : View.GONE);
+ final Switch hardKeySwitch = mSwitchingDialogTitleView.findViewById(
+ com.android.internal.R.id.hard_keyboard_switch);
+ hardKeySwitch.setChecked(mShowImeWithHardKeyboard);
+ hardKeySwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
+ mSettings.setShowImeWithHardKeyboard(isChecked);
+ // Ensure that the input method dialog is dismissed when changing
+ // the hardware keyboard state.
+ hideInputMethodMenu();
+ });
+
+ final ImeSubtypeListAdapter adapter = new ImeSubtypeListAdapter(dialogContext,
+ com.android.internal.R.layout.input_method_switch_item, imList, checkedItem);
+ final DialogInterface.OnClickListener choiceListener = (dialog, which) -> {
+ synchronized (mMethodMap) {
+ if (mIms == null || mIms.length <= which || mSubtypeIds == null
+ || mSubtypeIds.length <= which) {
+ return;
+ }
+ final InputMethodInfo im = mIms[which];
+ int subtypeId = mSubtypeIds[which];
+ adapter.mCheckedItem = which;
+ adapter.notifyDataSetChanged();
+ hideInputMethodMenu();
+ if (im != null) {
+ if (subtypeId < 0 || subtypeId >= im.getSubtypeCount()) {
+ subtypeId = NOT_A_SUBTYPE_ID;
+ }
+ mService.setInputMethodLocked(im.getId(), subtypeId);
+ }
+ }
+ };
+ mDialogBuilder.setSingleChoiceItems(adapter, checkedItem, choiceListener);
+
+ mSwitchingDialog = mDialogBuilder.create();
+ mSwitchingDialog.setCanceledOnTouchOutside(true);
+ final Window w = mSwitchingDialog.getWindow();
+ final WindowManager.LayoutParams attrs = w.getAttributes();
+ w.setType(WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG);
+ // Use an alternate token for the dialog for that window manager can group the token
+ // with other IME windows based on type vs. grouping based on whichever token happens
+ // to get selected by the system later on.
+ attrs.token = mSwitchingDialogToken;
+ attrs.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
+ attrs.setTitle("Select input method");
+ w.setAttributes(attrs);
+ mService.updateSystemUiLocked();
+ mSwitchingDialog.show();
+ }
+ }
+
+ /**
+ * Returns the window context for IME switch dialogs to receive configuration changes.
+ *
+ * This method initializes the window context if it was not initialized. This method also moves
+ * the context to the targeted display if the current display of context is different than
+ * the display specified by {@code displayId}.
+ */
+ @VisibleForTesting
+ public Context getSettingsContext(int displayId) {
+ if (mSettingsContext == null) {
+ final Context systemUiContext = ActivityThread.currentActivityThread()
+ .createSystemUiContext(displayId);
+ final Context windowContext = systemUiContext.createWindowContext(
+ WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG, null /* options */);
+ mSettingsContext = new ContextThemeWrapper(
+ windowContext, com.android.internal.R.style.Theme_DeviceDefault_Settings);
+ mSwitchingDialogToken = mSettingsContext.getActivityToken();
+ }
+ // TODO(b/159767464): register the listener to another display again if window token is not
+ // yet created.
+ if (mSettingsContext.getDisplayId() != displayId) {
+ mWindowManagerInternal.moveWindowTokenToDisplay(mSwitchingDialogToken, displayId);
+ }
+ return mSettingsContext;
+ }
+
+ private boolean isScreenLocked() {
+ return mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()
+ && mKeyguardManager.isKeyguardSecure();
+ }
+
+ void updateKeyboardFromSettingsLocked() {
+ mShowImeWithHardKeyboard = mSettings.isShowImeWithHardKeyboardEnabled();
+ if (mSwitchingDialog != null && mSwitchingDialogTitleView != null
+ && mSwitchingDialog.isShowing()) {
+ final Switch hardKeySwitch = mSwitchingDialogTitleView.findViewById(
+ com.android.internal.R.id.hard_keyboard_switch);
+ hardKeySwitch.setChecked(mShowImeWithHardKeyboard);
+ }
+ }
+
+ void hideInputMethodMenu() {
+ synchronized (mMethodMap) {
+ hideInputMethodMenuLocked();
+ }
+ }
+
+ void hideInputMethodMenuLocked() {
+ if (DEBUG) Slog.v(TAG, "Hide switching menu");
+
+ if (mSwitchingDialog != null) {
+ mSwitchingDialog.dismiss();
+ mSwitchingDialog = null;
+ mSwitchingDialogTitleView = null;
+ }
+
+ mService.updateSystemUiLocked();
+ mDialogBuilder = null;
+ mIms = null;
+ }
+
+ HardKeyboardListener getHardKeyboardListener() {
+ return mHardKeyboardListener;
+ }
+
+ AlertDialog getSwitchingDialogLocked() {
+ return mSwitchingDialog;
+ }
+
+ boolean getShowImeWithHardKeyboard() {
+ return mShowImeWithHardKeyboard;
+ }
+
+ boolean isisInputMethodPickerShownForTestLocked() {
+ if (mSwitchingDialog == null) {
+ return false;
+ }
+ return mSwitchingDialog.isShowing();
+ }
+
+ class HardKeyboardListener implements WindowManagerInternal.OnHardKeyboardStatusChangeListener {
+ @Override
+ public void onHardKeyboardStatusChange(boolean available) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_HARD_KEYBOARD_SWITCH_CHANGED,
+ available ? 1 : 0));
+ }
+
+ public void handleHardKeyboardStatusChange(boolean available) {
+ if (DEBUG) {
+ Slog.w(TAG, "HardKeyboardStatusChanged: available=" + available);
+ }
+ synchronized (mMethodMap) {
+ if (mSwitchingDialog != null && mSwitchingDialogTitleView != null
+ && mSwitchingDialog.isShowing()) {
+ mSwitchingDialogTitleView.findViewById(
+ com.android.internal.R.id.hard_keyboard_section).setVisibility(
+ available ? View.VISIBLE : View.GONE);
+ }
+ }
+ }
+ }
+
+ private static class ImeSubtypeListAdapter extends ArrayAdapter<ImeSubtypeListItem> {
+ private final LayoutInflater mInflater;
+ private final int mTextViewResourceId;
+ private final List<ImeSubtypeListItem> mItemsList;
+ public int mCheckedItem;
+ private ImeSubtypeListAdapter(Context context, int textViewResourceId,
+ List<ImeSubtypeListItem> itemsList, int checkedItem) {
+ super(context, textViewResourceId, itemsList);
+
+ mTextViewResourceId = textViewResourceId;
+ mItemsList = itemsList;
+ mCheckedItem = checkedItem;
+ mInflater = LayoutInflater.from(context);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ final View view = convertView != null ? convertView
+ : mInflater.inflate(mTextViewResourceId, null);
+ if (position < 0 || position >= mItemsList.size()) return view;
+ final ImeSubtypeListItem item = mItemsList.get(position);
+ final CharSequence imeName = item.mImeName;
+ final CharSequence subtypeName = item.mSubtypeName;
+ final TextView firstTextView = view.findViewById(android.R.id.text1);
+ final TextView secondTextView = view.findViewById(android.R.id.text2);
+ if (TextUtils.isEmpty(subtypeName)) {
+ firstTextView.setText(imeName);
+ secondTextView.setVisibility(View.GONE);
+ } else {
+ firstTextView.setText(subtypeName);
+ secondTextView.setText(imeName);
+ secondTextView.setVisibility(View.VISIBLE);
+ }
+ final RadioButton radioButton = view.findViewById(com.android.internal.R.id.radio);
+ radioButton.setChecked(position == mCheckedItem);
+ return view;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/location/AbstractLocationProvider.java b/services/core/java/com/android/server/location/AbstractLocationProvider.java
index 56982a81f83b..bd2676e60825 100644
--- a/services/core/java/com/android/server/location/AbstractLocationProvider.java
+++ b/services/core/java/com/android/server/location/AbstractLocationProvider.java
@@ -222,7 +222,7 @@ public abstract class AbstractLocationProvider {
// we know that we only updated the state, so the listener for the old state is the same as
// the listener for the new state.
if (oldInternalState.listener != null) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
oldInternalState.listener.onStateChanged(oldInternalState.state, newState);
} finally {
@@ -246,7 +246,7 @@ public abstract class AbstractLocationProvider {
// we know that we only updated the state, so the listener for the old state is the same as
// the listener for the new state.
if (oldInternalState.listener != null) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
oldInternalState.listener.onStateChanged(oldInternalState.state, newState);
} finally {
@@ -305,7 +305,7 @@ public abstract class AbstractLocationProvider {
protected void reportLocation(Location location) {
Listener listener = mInternalState.get().listener;
if (listener != null) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
// copy location so if provider makes further changes they do not propagate
listener.onReportLocation(new Location(location));
@@ -321,7 +321,7 @@ public abstract class AbstractLocationProvider {
protected void reportLocation(List<Location> locations) {
Listener listener = mInternalState.get().listener;
if (listener != null) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
// copy location so if provider makes further changes they do not propagate
ArrayList<Location> copy = new ArrayList<>(locations.size());
diff --git a/services/core/java/com/android/server/location/LocationProviderManager.java b/services/core/java/com/android/server/location/LocationProviderManager.java
index ecf82e8f8bd6..3b3c6f0c6cf9 100644
--- a/services/core/java/com/android/server/location/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/LocationProviderManager.java
@@ -1232,7 +1232,7 @@ class LocationProviderManager extends
mUserHelper.addListener(mUserChangedListener);
mSettingsHelper.addOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
// initialize enabled state
onUserStarted(UserHandle.USER_ALL);
@@ -1249,7 +1249,7 @@ class LocationProviderManager extends
mStarted = false;
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
onEnabledChanged(UserHandle.USER_ALL);
removeRegistrationIf(key -> true);
@@ -1317,7 +1317,7 @@ class LocationProviderManager extends
synchronized (mLock) {
Preconditions.checkState(mStarted);
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mProvider.setRealProvider(provider);
} finally {
@@ -1332,7 +1332,7 @@ class LocationProviderManager extends
mLocationEventLog.logProviderMocked(mName, provider != null);
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mProvider.setMockProvider(provider);
} finally {
@@ -1359,7 +1359,7 @@ class LocationProviderManager extends
throw new IllegalArgumentException(mName + " provider is not a test provider");
}
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mProvider.setMockProviderAllowed(enabled);
} finally {
@@ -1374,7 +1374,7 @@ class LocationProviderManager extends
throw new IllegalArgumentException(mName + " provider is not a test provider");
}
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
String locationProvider = location.getProvider();
if (!TextUtils.isEmpty(locationProvider) && !mName.equals(locationProvider)) {
@@ -1537,7 +1537,7 @@ class LocationProviderManager extends
permissionLevel);
synchronized (mLock) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
addRegistration(callback.asBinder(), registration);
if (!registration.isActive()) {
@@ -1561,7 +1561,7 @@ class LocationProviderManager extends
}
public void sendExtraCommand(int uid, int pid, String command, Bundle extras) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mProvider.sendExtraCommand(uid, pid, command, extras);
} finally {
@@ -1578,7 +1578,7 @@ class LocationProviderManager extends
permissionLevel);
synchronized (mLock) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
addRegistration(listener.asBinder(), registration);
} finally {
@@ -1596,7 +1596,7 @@ class LocationProviderManager extends
permissionLevel);
synchronized (mLock) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
addRegistration(pendingIntent, registration);
} finally {
@@ -1607,7 +1607,7 @@ class LocationProviderManager extends
public void unregisterLocationRequest(ILocationListener listener) {
synchronized (mLock) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
removeRegistration(listener.asBinder());
} finally {
@@ -1618,7 +1618,7 @@ class LocationProviderManager extends
public void unregisterLocationRequest(PendingIntent pendingIntent) {
synchronized (mLock) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
removeRegistration(pendingIntent);
} finally {
@@ -2394,7 +2394,7 @@ class LocationProviderManager extends
return;
}
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
callback.run();
} catch (RuntimeException e) {
diff --git a/services/core/java/com/android/server/location/PassiveLocationProviderManager.java b/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
index 2870d41e5248..fc10d5fcf1b7 100644
--- a/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
+++ b/services/core/java/com/android/server/location/PassiveLocationProviderManager.java
@@ -52,7 +52,7 @@ class PassiveLocationProviderManager extends LocationProviderManager {
PassiveProvider passiveProvider = (PassiveProvider) mProvider.getProvider();
Preconditions.checkState(passiveProvider != null);
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
passiveProvider.updateLocation(location);
} finally {
diff --git a/services/core/java/com/android/server/location/geofence/GeofenceManager.java b/services/core/java/com/android/server/location/geofence/GeofenceManager.java
index baa01b1506af..c91ee824ff61 100644
--- a/services/core/java/com/android/server/location/geofence/GeofenceManager.java
+++ b/services/core/java/com/android/server/location/geofence/GeofenceManager.java
@@ -302,7 +302,7 @@ public class GeofenceManager extends
CallerIdentity callerIdentity = CallerIdentity.fromBinder(mContext, packageName,
attributionTag, AppOpsManager.toReceiverId(pendingIntent));
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
addRegistration(new GeofenceKey(pendingIntent, geofence),
new GeofenceRegistration(geofence, callerIdentity, pendingIntent));
@@ -315,7 +315,7 @@ public class GeofenceManager extends
* Removes the geofence associated with the PendingIntent.
*/
public void removeGeofence(PendingIntent pendingIntent) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
removeRegistrationIf(key -> key.getPendingIntent().equals(pendingIntent));
} finally {
diff --git a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
index 1cdb118f5787..b94f1555cfaa 100644
--- a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
@@ -229,7 +229,7 @@ public abstract class GnssListenerMultiplexer<TRequest, TListener extends IInter
*/
protected void addListener(TRequest request, CallerIdentity callerIdentity,
TListener listener) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
addRegistration(listener.asBinder(),
new GnssListenerRegistration(request, callerIdentity, listener));
@@ -242,7 +242,7 @@ public abstract class GnssListenerMultiplexer<TRequest, TListener extends IInter
* Removes the given listener.
*/
public void removeListener(TListener listener) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
removeRegistration(listener.asBinder());
} finally {
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index f879b1929236..e144b403240c 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -1120,7 +1120,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
@Override
public void onExtraCommand(int uid, int pid, String command, Bundle extras) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
if ("delete_aiding_data".equals(command)) {
deleteAidingData(extras);
diff --git a/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java b/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
index 5dc4318e5803..43eb3ca128c6 100644
--- a/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/location/timezone/BinderLocationTimeZoneProvider.java
@@ -200,8 +200,8 @@ class BinderLocationTimeZoneProvider extends LocationTimeZoneProvider {
synchronized (mSharedLock) {
return "BinderLocationTimeZoneProvider{"
+ "mProviderName=" + mProviderName
- + "mCurrentState=" + mCurrentState
- + "mProxy=" + mProxy
+ + ", mCurrentState=" + mCurrentState
+ + ", mProxy=" + mProxy
+ '}';
}
}
diff --git a/services/core/java/com/android/server/location/timezone/NullLocationTimeZoneProvider.java b/services/core/java/com/android/server/location/timezone/NullLocationTimeZoneProvider.java
index 53afaf06f298..2bbae56e40c8 100644
--- a/services/core/java/com/android/server/location/timezone/NullLocationTimeZoneProvider.java
+++ b/services/core/java/com/android/server/location/timezone/NullLocationTimeZoneProvider.java
@@ -92,7 +92,7 @@ class NullLocationTimeZoneProvider extends LocationTimeZoneProvider {
synchronized (mSharedLock) {
return "NullLocationTimeZoneProvider{"
+ "mProviderName='" + mProviderName + '\''
- + "mCurrentState='" + mCurrentState + '\''
+ + ", mCurrentState='" + mCurrentState + '\''
+ '}';
}
}
diff --git a/services/core/java/com/android/server/location/util/SystemAppForegroundHelper.java b/services/core/java/com/android/server/location/util/SystemAppForegroundHelper.java
index d8b1d5b88260..3ff572b0a8e6 100644
--- a/services/core/java/com/android/server/location/util/SystemAppForegroundHelper.java
+++ b/services/core/java/com/android/server/location/util/SystemAppForegroundHelper.java
@@ -63,7 +63,7 @@ public class SystemAppForegroundHelper extends AppForegroundHelper {
public boolean isAppForeground(int uid) {
Preconditions.checkState(mActivityManager != null);
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
return isForeground(mActivityManager.getUidImportance(uid));
} finally {
diff --git a/services/core/java/com/android/server/location/util/SystemAppOpsHelper.java b/services/core/java/com/android/server/location/util/SystemAppOpsHelper.java
index cfb7697a8dfc..8742d65df97c 100644
--- a/services/core/java/com/android/server/location/util/SystemAppOpsHelper.java
+++ b/services/core/java/com/android/server/location/util/SystemAppOpsHelper.java
@@ -60,7 +60,7 @@ public class SystemAppOpsHelper extends AppOpsHelper {
public boolean startOpNoThrow(int appOp, CallerIdentity callerIdentity) {
Preconditions.checkState(mAppOps != null);
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
return mAppOps.startOpNoThrow(
appOp,
@@ -78,7 +78,7 @@ public class SystemAppOpsHelper extends AppOpsHelper {
public void finishOp(int appOp, CallerIdentity callerIdentity) {
Preconditions.checkState(mAppOps != null);
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mAppOps.finishOp(
appOp,
@@ -94,7 +94,7 @@ public class SystemAppOpsHelper extends AppOpsHelper {
public boolean checkOpNoThrow(int appOp, CallerIdentity callerIdentity) {
Preconditions.checkState(mAppOps != null);
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
return mAppOps.checkOpNoThrow(
appOp,
@@ -109,7 +109,7 @@ public class SystemAppOpsHelper extends AppOpsHelper {
public boolean noteOp(int appOp, CallerIdentity callerIdentity) {
Preconditions.checkState(mAppOps != null);
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
return mAppOps.noteOp(
appOp,
@@ -126,7 +126,7 @@ public class SystemAppOpsHelper extends AppOpsHelper {
public boolean noteOpNoThrow(int appOp, CallerIdentity callerIdentity) {
Preconditions.checkState(mAppOps != null);
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
return mAppOps.noteOpNoThrow(
appOp,
diff --git a/services/core/java/com/android/server/location/util/SystemLocationPermissionsHelper.java b/services/core/java/com/android/server/location/util/SystemLocationPermissionsHelper.java
index b9c0ddef04ab..4f1f7a0038d2 100644
--- a/services/core/java/com/android/server/location/util/SystemLocationPermissionsHelper.java
+++ b/services/core/java/com/android/server/location/util/SystemLocationPermissionsHelper.java
@@ -54,7 +54,7 @@ public class SystemLocationPermissionsHelper extends LocationPermissionsHelper {
@Override
protected boolean hasPermission(String permission, CallerIdentity callerIdentity) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
return mContext.checkPermission(permission, callerIdentity.getPid(),
callerIdentity.getUid()) == PERMISSION_GRANTED;
diff --git a/services/core/java/com/android/server/location/util/SystemSettingsHelper.java b/services/core/java/com/android/server/location/util/SystemSettingsHelper.java
index 39aeaba16579..560cd3c719d7 100644
--- a/services/core/java/com/android/server/location/util/SystemSettingsHelper.java
+++ b/services/core/java/com/android/server/location/util/SystemSettingsHelper.java
@@ -123,7 +123,7 @@ public class SystemSettingsHelper extends SettingsHelper {
*/
@Override
public void setLocationEnabled(boolean enabled, int userId) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
Settings.Secure.putIntForUser(
mContext.getContentResolver(),
@@ -314,7 +314,7 @@ public class SystemSettingsHelper extends SettingsHelper {
*/
@Override
public long getBackgroundThrottleProximityAlertIntervalMs() {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
return Settings.Global.getLong(mContext.getContentResolver(),
LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS,
@@ -330,7 +330,7 @@ public class SystemSettingsHelper extends SettingsHelper {
*/
@Override
public float getCoarseLocationAccuracyM() {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
final ContentResolver cr = mContext.getContentResolver();
try {
return Settings.Secure.getFloatForUser(
@@ -458,7 +458,7 @@ public class SystemSettingsHelper extends SettingsHelper {
}
public int getValueForUser(int defaultValue, int userId) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
return Settings.Secure.getIntForUser(mContext.getContentResolver(), mSettingName,
defaultValue, userId);
@@ -496,7 +496,7 @@ public class SystemSettingsHelper extends SettingsHelper {
List<String> value = mCachedValue;
if (userId != mCachedUserId) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
mSettingName, userId);
@@ -548,7 +548,7 @@ public class SystemSettingsHelper extends SettingsHelper {
}
public boolean getValue(boolean defaultValue) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
return Settings.Global.getInt(mContext.getContentResolver(), mSettingName,
defaultValue ? 1 : 0) != 0;
@@ -574,7 +574,7 @@ public class SystemSettingsHelper extends SettingsHelper {
}
public long getValue(long defaultValue) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
return Settings.Global.getLong(mContext.getContentResolver(), mSettingName,
defaultValue);
@@ -612,7 +612,7 @@ public class SystemSettingsHelper extends SettingsHelper {
public synchronized Set<String> getValue() {
ArraySet<String> value = mCachedValue;
if (!mValid) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
value = new ArraySet<>(mBaseValuesSupplier.get());
String setting = Settings.Global.getString(mContext.getContentResolver(),
diff --git a/services/core/java/com/android/server/location/util/SystemUserInfoHelper.java b/services/core/java/com/android/server/location/util/SystemUserInfoHelper.java
index e9836aad0472..141afa7eef4c 100644
--- a/services/core/java/com/android/server/location/util/SystemUserInfoHelper.java
+++ b/services/core/java/com/android/server/location/util/SystemUserInfoHelper.java
@@ -97,7 +97,7 @@ public class SystemUserInfoHelper extends UserInfoHelper {
public int[] getRunningUserIds() {
IActivityManager activityManager = getActivityManager();
if (activityManager != null) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
return activityManager.getRunningUserIds();
} catch (RemoteException e) {
@@ -118,7 +118,7 @@ public class SystemUserInfoHelper extends UserInfoHelper {
public boolean isCurrentUserId(@UserIdInt int userId) {
ActivityManagerInternal activityManagerInternal = getActivityManagerInternal();
if (activityManagerInternal != null) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
return activityManagerInternal.isCurrentProfile(userId);
} finally {
@@ -136,7 +136,7 @@ public class SystemUserInfoHelper extends UserInfoHelper {
// if you're hitting this precondition then you are invoking this before the system is ready
Preconditions.checkState(userManager != null);
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
return userManager.getEnabledProfileIds(userId);
} finally {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 7e53e6f3e2c3..c42c84f75051 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -1388,7 +1388,7 @@ public class LockSettingsService extends ILockSettings.Stub {
// Now we have unlocked the parent user and attempted to unlock the profile we should
// show notifications if the profile is still locked.
if (!alreadyUnlocked) {
- long ident = clearCallingIdentity();
+ final long ident = clearCallingIdentity();
try {
maybeShowEncryptionNotificationForUser(profile.id);
} finally {
@@ -2227,7 +2227,7 @@ public class LockSettingsService extends ILockSettings.Stub {
final IStorageManager service = mInjector.getStorageManager();
// TODO(b/120484642): Update vold to return a password as a byte array
String password;
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
password = service.getPassword();
service.clearPassword();
@@ -3447,7 +3447,7 @@ public class LockSettingsService extends ILockSettings.Stub {
@Override
public PasswordMetrics getUserPasswordMetrics(int userHandle) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
if (isManagedProfileWithUnifiedLock(userHandle)) {
// A managed profile with unified challenge is supposed to be protected by the
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 8e932155d8a7..828a0ac94c0c 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -1397,7 +1397,7 @@ public class MediaSessionService extends SystemService implements Monitor {
*/
@Override
public boolean dispatchMediaKeyEventToSessionAsSystemService(String packageName,
- MediaSession.Token sessionToken, KeyEvent keyEvent) {
+ KeyEvent keyEvent, MediaSession.Token sessionToken) {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
@@ -1772,7 +1772,7 @@ public class MediaSessionService extends SystemService implements Monitor {
*/
@Override
public void dispatchVolumeKeyEventToSessionAsSystemService(String packageName,
- String opPackageName, MediaSession.Token sessionToken, KeyEvent keyEvent) {
+ String opPackageName, KeyEvent keyEvent, MediaSession.Token sessionToken) {
int pid = Binder.getCallingPid();
int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 94776f8c7cb4..3ce8e4659737 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -261,7 +261,7 @@ public final class MediaProjectionManagerService extends SystemService
@Override // Binder call
public boolean hasProjectionPermission(int uid, String packageName) {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
boolean hasPermission = false;
try {
hasPermission |= checkPermission(packageName,
@@ -288,7 +288,7 @@ public final class MediaProjectionManagerService extends SystemService
}
final UserHandle callingUser = Binder.getCallingUserHandle();
- long callingToken = Binder.clearCallingIdentity();
+ final long callingToken = Binder.clearCallingIdentity();
MediaProjection projection;
try {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 29928771e73d..dcfd3f20b953 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -3472,10 +3472,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
fout.println();
- fout.print("mRestrictBackgroundLowPowerMode: " + mRestrictBackgroundLowPowerMode);
- fout.print("mRestrictBackgroundBeforeBsm: " + mRestrictBackgroundBeforeBsm);
- fout.print("mLoadedRestrictBackground: " + mLoadedRestrictBackground);
- fout.print("mRestrictBackgroundChangedInBsm: " + mRestrictBackgroundChangedInBsm);
+ fout.println("mRestrictBackgroundLowPowerMode: " + mRestrictBackgroundLowPowerMode);
+ fout.println("mRestrictBackgroundBeforeBsm: " + mRestrictBackgroundBeforeBsm);
+ fout.println("mLoadedRestrictBackground: " + mLoadedRestrictBackground);
+ fout.println("mRestrictBackgroundChangedInBsm: " + mRestrictBackgroundChangedInBsm);
fout.println();
fout.println("Network policies:");
diff --git a/services/core/java/com/android/server/net/TEST_MAPPING b/services/core/java/com/android/server/net/TEST_MAPPING
index 9f04260242d9..f70759761304 100644
--- a/services/core/java/com/android/server/net/TEST_MAPPING
+++ b/services/core/java/com/android/server/net/TEST_MAPPING
@@ -9,6 +9,9 @@
},
{
"exclude-annotation": "androidx.test.filters.FlakyTest"
+ },
+ {
+ "exclude-annotation": "android.platform.test.annotations.FlakyTest"
}
]
},
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index cab33770c0fc..67ef029c3947 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -868,7 +868,7 @@ public class NotificationManagerService extends SystemService {
(status & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
if (disableNotificationEffects(null) != null) {
// cancel whatever's going on
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
if (player != null) {
@@ -879,11 +879,11 @@ public class NotificationManagerService extends SystemService {
Binder.restoreCallingIdentity(identity);
}
- identity = Binder.clearCallingIdentity();
+ final long identity2 = Binder.clearCallingIdentity();
try {
mVibrator.cancel();
} finally {
- Binder.restoreCallingIdentity(identity);
+ Binder.restoreCallingIdentity(identity2);
}
}
}
@@ -1339,7 +1339,7 @@ public class NotificationManagerService extends SystemService {
@GuardedBy("mNotificationLock")
void clearSoundLocked() {
mSoundNotificationKey = null;
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
if (player != null) {
@@ -1354,7 +1354,7 @@ public class NotificationManagerService extends SystemService {
@GuardedBy("mNotificationLock")
void clearVibrateLocked() {
mVibrateNotificationKey = null;
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mVibrator.cancel();
} finally {
@@ -2865,7 +2865,7 @@ public class NotificationManagerService extends SystemService {
callingUid);
final boolean appIsForeground;
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
appIsForeground = mActivityManager.getUidImportance(callingUid)
== IMPORTANCE_FOREGROUND;
@@ -2885,7 +2885,7 @@ public class NotificationManagerService extends SystemService {
if (isAppRenderedToast && !isSystemToast && !isPackageInForegroundForToast(pkg,
callingUid)) {
boolean block;
- long id = Binder.clearCallingIdentity();
+ final long id = Binder.clearCallingIdentity();
try {
// CHANGE_BACKGROUND_CUSTOM_TOAST_BLOCK is gated on targetSdk, so block will be
// false for apps with targetSdk < R. For apps with targetSdk R+, text toasts
@@ -2911,7 +2911,7 @@ public class NotificationManagerService extends SystemService {
synchronized (mToastQueue) {
int callingPid = Binder.getCallingPid();
- long callingId = Binder.clearCallingIdentity();
+ final long callingId = Binder.clearCallingIdentity();
try {
ToastRecord record;
int index = indexOfToastLocked(pkg, token);
@@ -2990,7 +2990,7 @@ public class NotificationManagerService extends SystemService {
}
synchronized (mToastQueue) {
- long callingId = Binder.clearCallingIdentity();
+ final long callingId = Binder.clearCallingIdentity();
try {
int index = indexOfToastLocked(pkg, token);
if (index >= 0) {
@@ -3008,7 +3008,7 @@ public class NotificationManagerService extends SystemService {
@Override
public void finishToken(String pkg, IBinder token) {
synchronized (mToastQueue) {
- long callingId = Binder.clearCallingIdentity();
+ final long callingId = Binder.clearCallingIdentity();
try {
int index = indexOfToastLocked(pkg, token);
if (index >= 0) {
@@ -3950,7 +3950,7 @@ public class NotificationManagerService extends SystemService {
public void cancelNotificationsFromListener(INotificationListener token, String[] keys) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
synchronized (mNotificationLock) {
final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
@@ -3988,7 +3988,7 @@ public class NotificationManagerService extends SystemService {
@Override
public void requestBindListener(ComponentName component) {
checkCallerIsSystemOrSameApp(component.getPackageName());
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
ManagedServices manager =
mAssistants.isComponentEnabledForCurrentProfiles(component)
@@ -4002,7 +4002,7 @@ public class NotificationManagerService extends SystemService {
@Override
public void requestUnbindListener(INotificationListener token) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
// allow bound services to disable themselves
synchronized (mNotificationLock) {
@@ -4016,7 +4016,7 @@ public class NotificationManagerService extends SystemService {
@Override
public void setNotificationsShownFromListener(INotificationListener token, String[] keys) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
synchronized (mNotificationLock) {
final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
@@ -4075,7 +4075,7 @@ public class NotificationManagerService extends SystemService {
@Override
public void snoozeNotificationUntilContextFromListener(INotificationListener token,
String key, String snoozeCriterionId) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
synchronized (mNotificationLock) {
final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
@@ -4094,7 +4094,7 @@ public class NotificationManagerService extends SystemService {
@Override
public void snoozeNotificationUntilFromListener(INotificationListener token, String key,
long duration) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
synchronized (mNotificationLock) {
final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
@@ -4112,7 +4112,7 @@ public class NotificationManagerService extends SystemService {
*/
@Override
public void unsnoozeNotificationFromAssistant(INotificationListener token, String key) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
synchronized (mNotificationLock) {
final ManagedServiceInfo info =
@@ -4132,7 +4132,7 @@ public class NotificationManagerService extends SystemService {
@Override
public void unsnoozeNotificationFromSystemListener(INotificationListener token,
String key) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
synchronized (mNotificationLock) {
final ManagedServiceInfo info =
@@ -4159,7 +4159,7 @@ public class NotificationManagerService extends SystemService {
String tag, int id) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
synchronized (mNotificationLock) {
final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
@@ -4456,7 +4456,7 @@ public class NotificationManagerService extends SystemService {
@Override
public void requestUnbindProvider(IConditionProvider provider) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
// allow bound services to disable themselves
final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
@@ -4469,7 +4469,7 @@ public class NotificationManagerService extends SystemService {
@Override
public void requestBindProvider(ComponentName component) {
checkCallerIsSystemOrSameApp(component.getPackageName());
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mConditionProviders.setComponentState(component, true);
} finally {
@@ -5036,7 +5036,7 @@ public class NotificationManagerService extends SystemService {
private int getUidForPackageAndUser(String pkg, UserHandle user) throws RemoteException {
int uid = 0;
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
uid = mPackageManager.getPackageUid(pkg, 0, user.getIdentifier());
} finally {
@@ -7111,7 +7111,7 @@ public class NotificationManagerService extends SystemService {
boolean delayVibForSound) {
// Escalate privileges so we can use the vibrator even if the
// notifying app does not have the VIBRATE permission.
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
final VibrationEffect effect;
try {
@@ -7719,7 +7719,7 @@ public class NotificationManagerService extends SystemService {
// vibrate
if (canceledKey.equals(mVibrateNotificationKey)) {
mVibrateNotificationKey = null;
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mVibrator.cancel();
}
@@ -8644,7 +8644,7 @@ public class NotificationManagerService extends SystemService {
if (mCompanionManager == null) {
return false;
}
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
List<String> associations = mCompanionManager.getAssociations(
info.component.getPackageName(), info.userid);
diff --git a/services/core/java/com/android/server/notification/NotificationShellCmd.java b/services/core/java/com/android/server/notification/NotificationShellCmd.java
index 927dc25ac6ce..73272a012671 100644
--- a/services/core/java/com/android/server/notification/NotificationShellCmd.java
+++ b/services/core/java/com/android/server/notification/NotificationShellCmd.java
@@ -133,7 +133,7 @@ public class NotificationShellCmd extends ShellCommand {
}
String callingPackage = null;
final int callingUid = Binder.getCallingUid();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
if (callingUid == Process.ROOT_UID) {
callingPackage = NotificationManagerService.ROOT_PKG;
diff --git a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
index 35170332a077..14affe7b4dd5 100644
--- a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
+++ b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
@@ -302,7 +302,7 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
private void readSnoozed() {
synchronized (mSnoozedForAlarm) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
final String setting = Settings.Secure.getStringForUser(
mContext.getContentResolver(),
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index 9a9e733cb390..f7d69fdc09d2 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -496,7 +496,7 @@ public class SnoozeHelper {
private void scheduleRepostAtTime(String pkg, String key, int userId, long time) {
Runnable runnable = () -> {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
final PendingIntent pi = createPendingIntent(pkg, key, userId);
mAm.cancel(pi);
diff --git a/services/core/java/com/android/server/pm/DumpState.java b/services/core/java/com/android/server/pm/DumpState.java
index 99a109367afc..520871ff40c8 100644
--- a/services/core/java/com/android/server/pm/DumpState.java
+++ b/services/core/java/com/android/server/pm/DumpState.java
@@ -43,6 +43,7 @@ public final class DumpState {
public static final int DUMP_SERVICE_PERMISSIONS = 1 << 24;
public static final int DUMP_APEX = 1 << 25;
public static final int DUMP_QUERIES = 1 << 26;
+ public static final int DUMP_KNOWN_PACKAGES = 1 << 27;
public static final int OPTION_SHOW_FILTERS = 1 << 0;
public static final int OPTION_DUMP_ALL_COMPONENTS = 1 << 1;
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 9646b9ce8edf..c0329b2b2fe6 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -771,8 +771,8 @@ class InstantAppRegistry {
for (int i = 0; i < packageCount; i++) {
final String packageToDelete = packagesToDelete.get(i);
if (mService.deletePackageX(packageToDelete, PackageManager.VERSION_CODE_HIGHEST,
- UserHandle.USER_SYSTEM, PackageManager.DELETE_ALL_USERS)
- == PackageManager.DELETE_SUCCEEDED) {
+ UserHandle.USER_SYSTEM, PackageManager.DELETE_ALL_USERS,
+ true /*removedBySystem*/) == PackageManager.DELETE_SUCCEEDED) {
if (file.getUsableSpace() >= neededSpace) {
return true;
}
diff --git a/services/core/java/com/android/server/pm/InstantAppResolverConnection.java b/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
index a9a4589fdb94..4f75f04b11b6 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolverConnection.java
@@ -139,7 +139,7 @@ final class InstantAppResolverConnection implements DeathRecipient {
@WorkerThread
private IInstantAppResolver getRemoteInstanceLazy(String token)
throws ConnectionException, TimeoutException, InterruptedException {
- long binderToken = Binder.clearCallingIdentity();
+ final long binderToken = Binder.clearCallingIdentity();
try {
return bind(token);
} finally {
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 4c1b700d958e..9bb6f7892972 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -261,7 +261,7 @@ public class LauncherAppsService extends SystemService {
verifyCallingPackage(callingPackage);
List<SessionInfo> sessionInfos = new ArrayList<>();
int[] userIds = mUm.getEnabledProfileIds(getCallingUserId());
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
for (int userId : userIds) {
sessionInfos.addAll(getPackageInstallerService().getAllSessions(userId)
@@ -541,7 +541,7 @@ public class LauncherAppsService extends SystemService {
}
final int callingUid = injectBinderCallingUid();
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
final PackageManagerInternal pmInt =
LocalServices.getService(PackageManagerInternal.class);
@@ -615,7 +615,7 @@ public class LauncherAppsService extends SystemService {
}
final int callingUid = injectBinderCallingUid();
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
final PackageManagerInternal pmInt =
LocalServices.getService(PackageManagerInternal.class);
@@ -649,7 +649,7 @@ public class LauncherAppsService extends SystemService {
}
final int callingUid = injectBinderCallingUid();
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
final PackageManagerInternal pmInt =
LocalServices.getService(PackageManagerInternal.class);
@@ -928,7 +928,7 @@ public class LauncherAppsService extends SystemService {
}
final int callingUid = injectBinderCallingUid();
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
final int state = mIPM.getComponentEnabledSetting(component, user.getIdentifier());
switch (state) {
@@ -999,7 +999,7 @@ public class LauncherAppsService extends SystemService {
boolean canLaunch = false;
final int callingUid = injectBinderCallingUid();
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
final PackageManagerInternal pmInt =
LocalServices.getService(PackageManagerInternal.class);
@@ -1050,7 +1050,7 @@ public class LauncherAppsService extends SystemService {
}
final Intent intent;
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
String packageName = component.getPackageName();
intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 31ee59717dba..2e1543b17320 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -244,7 +244,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
mSessionsDir.mkdirs();
mApexManager = ApexManager.getInstance();
- mStagingManager = new StagingManager(this, context, apexParserSupplier);
+ mStagingManager = new StagingManager(context, apexParserSupplier);
LocalServices.getService(SystemServiceManager.class).startService(
new Lifecycle(context, this));
@@ -746,9 +746,6 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
synchronized (mSessions) {
mSessions.put(sessionId, session);
}
- if (params.isStaged) {
- mStagingManager.createSession(session);
- }
mCallbacks.notifySessionCreated(session.sessionId, session.userId);
@@ -980,7 +977,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
} else if (canSilentlyInstallPackage) {
// Allow the device owner and affiliated profile owner to silently delete packages
// Need to clear the calling identity to get DELETE_PACKAGES permission
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags);
} finally {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 37fa9a2e19db..649cafb1cb06 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -1602,13 +1602,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
validateApkInstallLocked();
}
}
- }
-
- if (params.isStaged) {
- mStagingManager.checkNonOverlappingWithStagedSessions(this);
- }
-
- synchronized (mLock) {
if (mDestroyed) {
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
"Session destroyed");
@@ -2311,7 +2304,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
return (params.installFlags & PackageManager.INSTALL_APEX) != 0;
}
- private boolean sessionContains(Predicate<PackageInstallerSession> filter) {
+ boolean sessionContains(Predicate<PackageInstallerSession> filter) {
if (!isMultiPackage()) {
return filter.test(this);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0f9a5cc331a0..9caa91b63dee 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -94,6 +94,7 @@ import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.content.pm.PackageManager.RESTRICTION_NONE;
import static android.content.pm.PackageManager.UNINSTALL_REASON_UNKNOWN;
+import static android.content.pm.PackageManagerInternal.LAST_KNOWN_PACKAGE;
import static android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V4;
import static android.content.pm.PackageParser.isApkFile;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
@@ -686,6 +687,8 @@ public class PackageManagerService extends IPackageManager.Stub
private static final String PACKAGE_SCHEME = "package";
+ private static final String COMPANION_PACKAGE_NAME = "com.android.companiondevicemanager";
+
/** Canonical intent used to identify what counts as a "web browser" app */
private static final Intent sBrowserIntent;
static {
@@ -2148,7 +2151,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (succeeded) {
// Send the removed broadcasts
if (res.removedInfo != null) {
- res.removedInfo.sendPackageRemovedBroadcasts(killApp);
+ res.removedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/);
}
// Allowlist any restricted permissions first as some may be runtime
@@ -2229,8 +2232,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Send installed broadcasts if the package is not a static shared lib.
if (res.pkg.getStaticSharedLibName() == null) {
- mProcessLoggingHandler.invalidateProcessLoggingBaseApkHash(
- res.pkg.getBaseApkPath());
+ mProcessLoggingHandler.invalidateBaseApkHash(res.pkg.getBaseApkPath());
// Send added for users that see the package for the first time
// sendPackageAddedForNewUsers also deals with system apps
@@ -2494,13 +2496,6 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- for (int i = 0, size = filesToChecksum.size(); i < size; ++i) {
- final File file = filesToChecksum.get(i).second;
- if (!file.exists()) {
- throw new IllegalStateException("File not found: " + file.getPath());
- }
- }
-
final Certificate[] trustedCerts = (trustedInstallers != null) ? decodeCertificates(
trustedInstallers) : null;
@@ -5313,8 +5308,8 @@ public class PackageManagerService extends IPackageManager.Stub
final VersionedPackage pkgToDelete = packagesToDelete.get(i);
// Delete the package synchronously (will fail of the lib used for any user).
if (deletePackageX(pkgToDelete.getPackageName(), pkgToDelete.getLongVersionCode(),
- UserHandle.USER_SYSTEM, PackageManager.DELETE_ALL_USERS)
- == PackageManager.DELETE_SUCCEEDED) {
+ UserHandle.USER_SYSTEM, PackageManager.DELETE_ALL_USERS,
+ true /*removedBySystem*/) == PackageManager.DELETE_SUCCEEDED) {
if (volume.getUsableSpace() >= neededSpace) {
return true;
}
@@ -5699,7 +5694,7 @@ public class PackageManagerService extends IPackageManager.Stub
continue;
}
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
PackageInfo packageInfo = getPackageInfoVersioned(declaringPackage, flags
| PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId);
@@ -7632,7 +7627,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
private boolean isUserEnabled(int userId) {
- long callingId = Binder.clearCallingIdentity();
+ final long callingId = Binder.clearCallingIdentity();
try {
UserInfo userInfo = mUserManager.getUserInfo(userId);
return userInfo != null && userInfo.isEnabled();
@@ -8043,7 +8038,7 @@ public class PackageManagerService extends IPackageManager.Stub
private ResolveInfo createForwardingResolveInfoUnchecked(IntentFilter filter,
int sourceUserId, int targetUserId) {
ResolveInfo forwardingResolveInfo = new ResolveInfo();
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
boolean targetIsProfile;
try {
targetIsProfile = mUserManager.getUserInfo(targetUserId).isManagedProfile();
@@ -10178,7 +10173,7 @@ public class PackageManagerService extends IPackageManager.Stub
mPackageUsage.maybeWriteAsync(mSettings.mPackages);
mCompilerStats.maybeWriteAsync();
}
- long callingId = Binder.clearCallingIdentity();
+ final long callingId = Binder.clearCallingIdentity();
try {
synchronized (mInstallLock) {
return performDexOptInternalWithDependenciesLI(p, pkgSetting, options);
@@ -13173,7 +13168,7 @@ public class PackageManagerService extends IPackageManager.Stub
return false;
}
- long callingId = Binder.clearCallingIdentity();
+ final long callingId = Binder.clearCallingIdentity();
try {
boolean sendAdded = false;
boolean sendRemoved = false;
@@ -13303,7 +13298,7 @@ public class PackageManagerService extends IPackageManager.Stub
info.removedUsers = new int[] {userId};
info.broadcastUsers = new int[] {userId};
info.uid = UserHandle.getUid(userId, pkgSetting.appId);
- info.sendPackageRemovedBroadcasts(true /*killApp*/);
+ info.sendPackageRemovedBroadcasts(true /*killApp*/, false /*removedBySystem*/);
}
private void sendDistractingPackagesChanged(String[] pkgList, int[] uidList, int userId,
@@ -13340,7 +13335,7 @@ public class PackageManagerService extends IPackageManager.Stub
true /* requireFullPermission */, false /* checkShell */,
"getApplicationHidden for user " + userId);
PackageSetting ps;
- long callingId = Binder.clearCallingIdentity();
+ final long callingId = Binder.clearCallingIdentity();
try {
// writer
synchronized (mLock) {
@@ -13395,7 +13390,7 @@ public class PackageManagerService extends IPackageManager.Stub
return PackageManager.INSTALL_FAILED_USER_RESTRICTED;
}
- long callingId = Binder.clearCallingIdentity();
+ final long callingId = Binder.clearCallingIdentity();
try {
boolean installed = false;
final boolean instantApp =
@@ -14486,7 +14481,7 @@ public class PackageManagerService extends IPackageManager.Stub
// was never set.
EventLog.writeEvent(0x534e4554, "150857253", callingUid, "");
- long binderToken = Binder.clearCallingIdentity();
+ final long binderToken = Binder.clearCallingIdentity();
try {
if (mInjector.getCompatibility().isChangeEnabledByUid(
THROW_EXCEPTION_ON_REQUIRE_INSTALL_PACKAGES_TO_ADD_INSTALLER_PACKAGE,
@@ -14778,20 +14773,6 @@ public class PackageManagerService extends IPackageManager.Stub
return mUser;
}
- /**
- * Gets the user handle for the user that the rollback agent should
- * use to look up information about this installation when enabling
- * rollback.
- */
- UserHandle getRollbackUser() {
- // The session for packages installed for "all" users is
- // associated with the "system" user.
- if (mUser == UserHandle.ALL) {
- return UserHandle.SYSTEM;
- }
- return mUser;
- }
-
HandlerParams setTraceMethod(String traceMethod) {
this.traceMethod = traceMethod;
return this;
@@ -17322,11 +17303,14 @@ public class PackageManagerService extends IPackageManager.Stub
mIncrementalManager.unregisterCallback(mPathString, this);
final SparseArray<int[]> newBroadcastAllowList;
synchronized (mLock) {
+ final PackageSetting ps = mSettings.mPackages.get(mPackageName);
+ if (ps == null) {
+ return;
+ }
newBroadcastAllowList = mAppsFilter.getVisibilityAllowList(
- getPackageSettingInternal(mPackageName, Process.SYSTEM_UID),
- mInstalledUserIds, mSettings.mPackages);
+ ps, mInstalledUserIds, mSettings.mPackages);
}
- Bundle extras = new Bundle(1);
+ Bundle extras = new Bundle();
extras.putInt(Intent.EXTRA_UID, mUserId);
extras.putString(Intent.EXTRA_PACKAGE_NAME, mPackageName);
sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_LOADED, mPackageName,
@@ -17339,11 +17323,14 @@ public class PackageManagerService extends IPackageManager.Stub
public void onPackageUnstartable(int reason) {
final SparseArray<int[]> newBroadcastAllowList;
synchronized (mLock) {
+ final PackageSetting ps = mSettings.mPackages.get(mPackageName);
+ if (ps == null) {
+ return;
+ }
newBroadcastAllowList = mAppsFilter.getVisibilityAllowList(
- getPackageSettingInternal(mPackageName, Process.SYSTEM_UID),
- mInstalledUserIds, mSettings.mPackages);
+ ps, mInstalledUserIds, mSettings.mPackages);
}
- Bundle extras = new Bundle(1);
+ Bundle extras = new Bundle();
extras.putInt(Intent.EXTRA_UID, mUserId);
extras.putString(Intent.EXTRA_PACKAGE_NAME, mPackageName);
extras.putInt(Intent.EXTRA_REASON, reason);
@@ -17358,11 +17345,14 @@ public class PackageManagerService extends IPackageManager.Stub
public void onPackageStartable() {
final SparseArray<int[]> newBroadcastAllowList;
synchronized (mLock) {
+ final PackageSetting ps = mSettings.mPackages.get(mPackageName);
+ if (ps == null) {
+ return;
+ }
newBroadcastAllowList = mAppsFilter.getVisibilityAllowList(
- getPackageSettingInternal(mPackageName, Process.SYSTEM_UID),
- mInstalledUserIds, mSettings.mPackages);
+ ps, mInstalledUserIds, mSettings.mPackages);
}
- Bundle extras = new Bundle(1);
+ Bundle extras = new Bundle();
extras.putInt(Intent.EXTRA_UID, mUserId);
extras.putString(Intent.EXTRA_PACKAGE_NAME, mPackageName);
// send broadcast to users with this app installed
@@ -18578,21 +18568,21 @@ public class PackageManagerService extends IPackageManager.Stub
if (doDeletePackage) {
if (!deleteAllUsers) {
returnCode = deletePackageX(internalPackageName, versionCode,
- userId, deleteFlags);
+ userId, deleteFlags, false /*removedBySystem*/);
} else {
int[] blockUninstallUserIds = getBlockUninstallForUsers(
internalPackageName, users);
// If nobody is blocking uninstall, proceed with delete for all users
if (ArrayUtils.isEmpty(blockUninstallUserIds)) {
returnCode = deletePackageX(internalPackageName, versionCode,
- userId, deleteFlags);
+ userId, deleteFlags, false /*removedBySystem*/);
} else {
// Otherwise uninstall individually for users with blockUninstalls=false
final int userFlags = deleteFlags & ~PackageManager.DELETE_ALL_USERS;
for (int userId1 : users) {
if (!ArrayUtils.contains(blockUninstallUserIds, userId1)) {
returnCode = deletePackageX(internalPackageName, versionCode,
- userId1, userFlags);
+ userId1, userFlags, false /*removedBySystem*/);
if (returnCode != PackageManager.DELETE_SUCCEEDED) {
Slog.w(TAG, "Package delete failed for user " + userId1
+ ", returnCode " + returnCode);
@@ -18819,8 +18809,12 @@ public class PackageManagerService extends IPackageManager.Stub
* updating mSettings to reflect current status
* persisting settings for later use
* sending a broadcast if necessary
+ *
+ * @param removedBySystem A boolean to indicate the package was removed automatically without
+ * the user-initiated action.
*/
- int deletePackageX(String packageName, long versionCode, int userId, int deleteFlags) {
+ int deletePackageX(String packageName, long versionCode, int userId, int deleteFlags,
+ boolean removedBySystem) {
final PackageRemovedInfo info = new PackageRemovedInfo(this);
final boolean res;
@@ -18917,7 +18911,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (res) {
final boolean killApp = (deleteFlags & PackageManager.DELETE_DONT_KILL_APP) == 0;
- info.sendPackageRemovedBroadcasts(killApp);
+ info.sendPackageRemovedBroadcasts(killApp, removedBySystem);
info.sendSystemPackageUpdatedBroadcasts();
}
// Force a gc here.
@@ -18993,8 +18987,8 @@ public class PackageManagerService extends IPackageManager.Stub
this.packageSender = packageSender;
}
- void sendPackageRemovedBroadcasts(boolean killApp) {
- sendPackageRemovedBroadcastInternal(killApp);
+ void sendPackageRemovedBroadcasts(boolean killApp, boolean removedBySystem) {
+ sendPackageRemovedBroadcastInternal(killApp, removedBySystem);
}
void sendSystemPackageUpdatedBroadcasts() {
@@ -19023,7 +19017,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- private void sendPackageRemovedBroadcastInternal(boolean killApp) {
+ private void sendPackageRemovedBroadcastInternal(boolean killApp, boolean removedBySystem) {
// Don't send static shared library removal broadcasts as these
// libs are visible only the the apps that depend on them an one
// cannot remove the library if it has a dependency.
@@ -19035,6 +19029,7 @@ public class PackageManagerService extends IPackageManager.Stub
extras.putInt(Intent.EXTRA_UID, removedUid);
extras.putBoolean(Intent.EXTRA_DATA_REMOVED, dataRemoved);
extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp);
+ extras.putBoolean(Intent.EXTRA_REMOVED_BY_SYSTEM, removedBySystem);
if (isUpdate || isRemovedPackageSystemUpdate) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
@@ -21154,7 +21149,7 @@ public class PackageManagerService extends IPackageManager.Stub
if (packageName == null) {
return null;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
if (getPackageInfo(packageName, MATCH_FACTORY_ONLY, UserHandle.USER_SYSTEM) == null) {
PackageInfo packageInfo = getPackageInfo(packageName, 0, UserHandle.USER_SYSTEM);
@@ -21515,7 +21510,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- long callingId = Binder.clearCallingIdentity();
+ final long callingId = Binder.clearCallingIdentity();
try {
if (sendNow) {
int packageUid = UserHandle.getUid(userId, pkgSetting.appId);
@@ -22062,6 +22057,7 @@ public class PackageManagerService extends IPackageManager.Stub
pw.println(" dexopt: dump dexopt state");
pw.println(" compiler-stats: dump compiler statistics");
pw.println(" service-permissions: dump permissions required by services");
+ pw.println(" known-packages: dump known packages");
pw.println(" <package.name>: info about given package");
return;
} else if ("--checkin".equals(opt)) {
@@ -22206,6 +22202,8 @@ public class PackageManagerService extends IPackageManager.Stub
dumpState.setDump(DumpState.DUMP_CHANGES);
} else if ("service-permissions".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_SERVICE_PERMISSIONS);
+ } else if ("known-packages".equals(cmd)) {
+ dumpState.setDump(DumpState.DUMP_KNOWN_PACKAGES);
} else if ("write".equals(cmd)) {
synchronized (mLock) {
writeSettingsLPrTEMP();
@@ -22230,6 +22228,37 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
+ if (!checkin
+ && dumpState.isDumping(DumpState.DUMP_KNOWN_PACKAGES)
+ && packageName == null) {
+ if (dumpState.onTitlePrinted()) {
+ pw.println();
+ }
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
+ ipw.println("Known Packages:");
+ ipw.increaseIndent();
+ for (int i = 0; i < LAST_KNOWN_PACKAGE; i++) {
+ final String knownPackage = mPmInternal.knownPackageToString(i);
+ if ("Unknown".equals(knownPackage)) {
+ continue;
+ }
+ ipw.print(knownPackage);
+ ipw.println(":");
+ final String[] pkgNames = mPmInternal.getKnownPackageNames(i,
+ UserHandle.USER_SYSTEM);
+ ipw.increaseIndent();
+ if (ArrayUtils.isEmpty(pkgNames)) {
+ ipw.println("none");
+ } else {
+ for (String name : pkgNames) {
+ ipw.println(name);
+ }
+ }
+ ipw.decreaseIndent();
+ }
+ ipw.decreaseIndent();
+ }
+
if (dumpState.isDumping(DumpState.DUMP_VERIFIERS) && packageName == null) {
if (!checkin) {
if (dumpState.onTitlePrinted())
@@ -23945,7 +23974,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
//end run
mHandler.post(() -> deletePackageX(packageName, PackageManager.VERSION_CODE_HIGHEST,
- userId, 0));
+ userId, 0, true /*removedBySystem*/));
}
}
}
@@ -24175,7 +24204,7 @@ public class PackageManagerService extends IPackageManager.Stub
// It is currently possible that the package will be deleted even if it is installed
// after this method returns.
mHandler.post(() -> deletePackageX(packageName, PackageManager.VERSION_CODE_HIGHEST,
- 0, PackageManager.DELETE_ALL_USERS));
+ 0, PackageManager.DELETE_ALL_USERS, true /*removedBySystem*/));
}
}
@@ -24719,7 +24748,7 @@ public class PackageManagerService extends IPackageManager.Stub
case PackageManagerInternal.PACKAGE_APP_PREDICTOR:
return filterOnlySystemPackages(mAppPredictionServicePackage);
case PackageManagerInternal.PACKAGE_COMPANION:
- return filterOnlySystemPackages("com.android.companiondevicemanager");
+ return filterOnlySystemPackages(COMPANION_PACKAGE_NAME);
case PackageManagerInternal.PACKAGE_RETAIL_DEMO:
return TextUtils.isEmpty(mRetailDemoPackage)
? ArrayUtils.emptyArray(String.class)
@@ -25769,25 +25798,16 @@ public class PackageManagerService extends IPackageManager.Stub
* @hide
*/
@Override
- public void logAppProcessStartIfNeeded(String processName, int uid, String seinfo,
- String apkFile, int pid) {
+ public void logAppProcessStartIfNeeded(String packageName, String processName, int uid,
+ String seinfo, String apkFile, int pid) {
if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return;
}
if (!SecurityLog.isLoggingEnabled()) {
return;
}
- Bundle data = new Bundle();
- data.putLong("startTimestamp", System.currentTimeMillis());
- data.putString("processName", processName);
- data.putInt("uid", uid);
- data.putString("seinfo", seinfo);
- data.putString("apkFile", apkFile);
- data.putInt("pid", pid);
- Message msg = mProcessLoggingHandler.obtainMessage(
- ProcessLoggingHandler.LOG_APP_PROCESS_START_MSG);
- msg.setData(data);
- mProcessLoggingHandler.sendMessage(msg);
+ mProcessLoggingHandler.logAppProcessStart(mContext, this, apkFile, packageName, processName,
+ uid, seinfo, pid);
}
public CompilerStats.PackageStats getCompilerPackageStats(String pkgName) {
diff --git a/services/core/java/com/android/server/pm/ProcessLoggingHandler.java b/services/core/java/com/android/server/pm/ProcessLoggingHandler.java
index c47dda4681f9..7fb34951d356 100644
--- a/services/core/java/com/android/server/pm/ProcessLoggingHandler.java
+++ b/services/core/java/com/android/server/pm/ProcessLoggingHandler.java
@@ -16,29 +16,47 @@
package com.android.server.pm;
+import static android.content.pm.PackageManager.EXTRA_CHECKSUMS;
+
import android.app.admin.SecurityLog;
+import android.content.Context;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
import android.content.Intent;
+import android.content.IntentSender;
+import android.content.pm.ApkChecksum;
+import android.content.pm.Checksum;
+import android.content.pm.IPackageManager;
import android.os.Bundle;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Message;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Slog;
import com.android.internal.os.BackgroundThread;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.HashMap;
-import android.util.Slog;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
public final class ProcessLoggingHandler extends Handler {
-
private static final String TAG = "ProcessLoggingHandler";
- static final int LOG_APP_PROCESS_START_MSG = 1;
- static final int INVALIDATE_BASE_APK_HASH_MSG = 2;
- private final HashMap<String, String> mProcessLoggingBaseApkHashes = new HashMap();
+ private static final int LOG_APP_PROCESS_START_MSG = 1;
+
+ private static final int CHECKSUM_TYPE = Checksum.TYPE_WHOLE_SHA256;
+
+ static class LoggingInfo {
+ public String apkHash = null;
+ public List<Bundle> pendingLogEntries = new ArrayList<>();
+ }
+
+ // Apk path to logging info map.
+ private final ArrayMap<String, LoggingInfo> mLoggingInfo = new ArrayMap<>();
ProcessLoggingHandler() {
super(BackgroundThread.getHandler().getLooper());
@@ -49,64 +67,133 @@ public final class ProcessLoggingHandler extends Handler {
switch (msg.what) {
case LOG_APP_PROCESS_START_MSG: {
Bundle bundle = msg.getData();
+ long startTimestamp = bundle.getLong("startTimestamp");
String processName = bundle.getString("processName");
int uid = bundle.getInt("uid");
String seinfo = bundle.getString("seinfo");
- String apkFile = bundle.getString("apkFile");
int pid = bundle.getInt("pid");
- long startTimestamp = bundle.getLong("startTimestamp");
- String apkHash = computeStringHashOfApk(apkFile);
+ String apkHash = bundle.getString("apkHash");
SecurityLog.writeEvent(SecurityLog.TAG_APP_PROCESS_START, processName,
startTimestamp, uid, pid, seinfo, apkHash);
break;
}
- case INVALIDATE_BASE_APK_HASH_MSG: {
- Bundle bundle = msg.getData();
- mProcessLoggingBaseApkHashes.remove(bundle.getString("apkFile"));
- break;
- }
}
}
- void invalidateProcessLoggingBaseApkHash(String apkPath) {
+ void logAppProcessStart(Context context, IPackageManager pms, String apkFile,
+ String packageName, String processName, int uid, String seinfo, int pid) {
Bundle data = new Bundle();
- data.putString("apkFile", apkPath);
- Message msg = obtainMessage(INVALIDATE_BASE_APK_HASH_MSG);
- msg.setData(data);
- sendMessage(msg);
- }
+ data.putLong("startTimestamp", System.currentTimeMillis());
+ data.putString("processName", processName);
+ data.putInt("uid", uid);
+ data.putString("seinfo", seinfo);
+ data.putInt("pid", pid);
- private String computeStringHashOfApk(String apkFile) {
if (apkFile == null) {
- return "No APK";
+ enqueueSecurityLogEvent(data, "No APK");
+ return;
}
- String apkHash = mProcessLoggingBaseApkHashes.get(apkFile);
- if (apkHash == null) {
- try {
- byte[] hash = computeHashOfApkFile(apkFile);
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < hash.length; i++) {
- sb.append(String.format("%02x", hash[i]));
- }
- apkHash = sb.toString();
- mProcessLoggingBaseApkHashes.put(apkFile, apkHash);
- } catch (IOException | NoSuchAlgorithmException e) {
- Slog.w(TAG, "computeStringHashOfApk() failed", e);
+
+ // Check cached apk hash.
+ boolean requestChecksums;
+ final LoggingInfo loggingInfo;
+ synchronized (mLoggingInfo) {
+ LoggingInfo cached = mLoggingInfo.get(apkFile);
+ requestChecksums = cached == null;
+ if (requestChecksums) {
+ // Create a new pending cache entry.
+ cached = new LoggingInfo();
+ mLoggingInfo.put(apkFile, cached);
}
+ loggingInfo = cached;
}
- return apkHash != null ? apkHash : "Failed to count APK hash";
+
+ synchronized (loggingInfo) {
+ // Still pending?
+ if (!TextUtils.isEmpty(loggingInfo.apkHash)) {
+ enqueueSecurityLogEvent(data, loggingInfo.apkHash);
+ return;
+ }
+
+ loggingInfo.pendingLogEntries.add(data);
+ }
+
+ if (!requestChecksums) {
+ return;
+ }
+
+ // Request base checksums when first added entry.
+ // Capturing local loggingInfo to still log even if hash was invalidated.
+ try {
+ pms.requestChecksums(packageName, false, 0, CHECKSUM_TYPE, null,
+ new IntentSender((IIntentSender) new IIntentSender.Stub() {
+ @Override
+ public void send(int code, Intent intent, String resolvedType,
+ IBinder allowlistToken, IIntentReceiver finishedReceiver,
+ String requiredPermission, Bundle options) {
+ processChecksums(loggingInfo, intent);
+ }
+ }), context.getUserId());
+ } catch (RemoteException e) {
+ Slog.e(TAG, "requestChecksums() failed", e);
+ processChecksums(loggingInfo, null);
+ }
+ }
+
+ void processChecksums(final LoggingInfo loggingInfo, Intent intent) {
+ Parcelable[] parcelables = intent.getParcelableArrayExtra(EXTRA_CHECKSUMS);
+ ApkChecksum[] checksums = Arrays.copyOf(parcelables, parcelables.length,
+ ApkChecksum[].class);
+
+ for (ApkChecksum checksum : checksums) {
+ if (checksum.getType() == CHECKSUM_TYPE) {
+ processChecksum(loggingInfo, checksum.getValue());
+ break;
+ }
+ }
+ }
+
+ void processChecksum(final LoggingInfo loggingInfo, final byte[] hash) {
+ final String apkHash;
+ if (hash != null) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < hash.length; i++) {
+ sb.append(String.format("%02x", hash[i]));
+ }
+ apkHash = sb.toString();
+ } else {
+ apkHash = "Failed to count APK hash";
+ }
+
+ List<Bundle> pendingLogEntries;
+ synchronized (loggingInfo) {
+ if (!TextUtils.isEmpty(loggingInfo.apkHash)) {
+ return;
+ }
+ loggingInfo.apkHash = apkHash;
+
+ pendingLogEntries = loggingInfo.pendingLogEntries;
+ loggingInfo.pendingLogEntries = null;
+ }
+
+ if (pendingLogEntries != null) {
+ for (Bundle data : pendingLogEntries) {
+ enqueueSecurityLogEvent(data, apkHash);
+ }
+ }
+ }
+
+ void enqueueSecurityLogEvent(Bundle data, String apkHash) {
+ data.putString("apkHash", apkHash);
+
+ Message msg = this.obtainMessage(LOG_APP_PROCESS_START_MSG);
+ msg.setData(data);
+ this.sendMessage(msg);
}
- private byte[] computeHashOfApkFile(String packageArchiveLocation)
- throws IOException, NoSuchAlgorithmException {
- MessageDigest md = MessageDigest.getInstance("SHA-256");
- FileInputStream input = new FileInputStream(new File(packageArchiveLocation));
- byte[] buffer = new byte[65536];
- int size;
- while ((size = input.read(buffer)) > 0) {
- md.update(buffer, 0, size);
+ void invalidateBaseApkHash(String apkFile) {
+ synchronized (mLoggingInfo) {
+ mLoggingInfo.remove(apkFile);
}
- input.close();
- return md.digest();
}
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 1dc035f26d83..4c8d2b9b0a9e 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4387,7 +4387,7 @@ public final class Settings {
*/
private static List<UserInfo> getUsers(UserManagerService userManager, boolean excludeDying,
boolean excludePreCreated) {
- long id = Binder.clearCallingIdentity();
+ final long id = Binder.clearCallingIdentity();
try {
return userManager.getUsers(/* excludePartial= */ true, excludeDying,
excludePreCreated);
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 529f16af883d..3bad3cb1d372 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -17,7 +17,6 @@
package com.android.server.pm;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.apex.ApexInfo;
import android.apex.ApexInfoList;
import android.apex.ApexSessionInfo;
@@ -46,8 +45,6 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
-import android.os.ParcelFileDescriptor;
-import android.os.ParcelableException;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -80,7 +77,6 @@ import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -96,7 +92,6 @@ public class StagingManager {
private static final String TAG = "StagingManager";
- private final PackageInstallerService mPi;
private final ApexManager mApexManager;
private final PowerManager mPowerManager;
private final Context mContext;
@@ -116,9 +111,7 @@ public class StagingManager {
@GuardedBy("mSuccessfulStagedSessionIds")
private final List<Integer> mSuccessfulStagedSessionIds = new ArrayList<>();
- StagingManager(PackageInstallerService pi, Context context,
- Supplier<PackageParser2> packageParserSupplier) {
- mPi = pi;
+ StagingManager(Context context, Supplier<PackageParser2> packageParserSupplier) {
mContext = context;
mPackageParserSupplier = packageParserSupplier;
@@ -650,118 +643,6 @@ public class StagingManager {
return "";
}
- private List<String> findAPKsInDir(File stageDir) {
- List<String> ret = new ArrayList<>();
- if (stageDir != null && stageDir.exists()) {
- for (File file : stageDir.listFiles()) {
- if (file.getAbsolutePath().toLowerCase().endsWith(".apk")) {
- ret.add(file.getAbsolutePath());
- }
- }
- }
- return ret;
- }
-
- private PackageInstallerSession createAndWriteApkSession(
- PackageInstallerSession originalSession) throws PackageManagerException {
- final int errorCode = SessionInfo.STAGED_SESSION_ACTIVATION_FAILED;
- if (originalSession.stageDir == null) {
- Slog.wtf(TAG, "Attempting to install a staged APK session with no staging dir");
- throw new PackageManagerException(errorCode,
- "Attempting to install a staged APK session with no staging dir");
- }
- List<String> apkFilePaths = findAPKsInDir(originalSession.stageDir);
- if (apkFilePaths.isEmpty()) {
- Slog.w(TAG, "Can't find staged APK in " + originalSession.stageDir.getAbsolutePath());
- throw new PackageManagerException(errorCode,
- "Can't find staged APK in " + originalSession.stageDir.getAbsolutePath());
- }
-
- PackageInstaller.SessionParams params = originalSession.params.copy();
- params.isStaged = false;
- params.installFlags |= PackageManager.INSTALL_STAGED;
- params.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION;
- try {
- int apkSessionId = mPi.createSession(
- params, originalSession.getInstallerPackageName(),
- originalSession.getInstallerAttributionTag(), originalSession.userId);
- PackageInstallerSession apkSession = mPi.getSession(apkSessionId);
- apkSession.open();
- for (int i = 0, size = apkFilePaths.size(); i < size; i++) {
- final String apkFilePath = apkFilePaths.get(i);
- File apkFile = new File(apkFilePath);
- ParcelFileDescriptor pfd = ParcelFileDescriptor.open(apkFile,
- ParcelFileDescriptor.MODE_READ_ONLY);
- long sizeBytes = (pfd == null) ? -1 : pfd.getStatSize();
- if (sizeBytes < 0) {
- Slog.e(TAG, "Unable to get size of: " + apkFilePath);
- throw new PackageManagerException(errorCode,
- "Unable to get size of: " + apkFilePath);
- }
- apkSession.write(apkFile.getName(), 0, sizeBytes, pfd);
- }
- return apkSession;
- } catch (IOException | ParcelableException e) {
- Slog.e(TAG, "Failure to install APK staged session " + originalSession.sessionId, e);
- throw new PackageManagerException(errorCode, "Failed to create/write APK session", e);
- }
- }
-
- /**
- * Extract apks in the given session into a new session. Returns {@code null} if there is no
- * apks in the given session. Only parent session is returned for multi-package session.
- */
- @Nullable
- private PackageInstallerSession extractApksInSession(PackageInstallerSession session)
- throws PackageManagerException {
- if (!session.isMultiPackage() && !session.isApexSession()) {
- return createAndWriteApkSession(session);
- } else if (session.isMultiPackage()) {
- // For multi-package staged sessions containing APKs, we identify which child sessions
- // contain an APK, and with those then create a new multi-package group of sessions,
- // carrying over all the session parameters and unmarking them as staged. On commit the
- // sessions will be installed atomically.
- final List<PackageInstallerSession> childSessions = new ArrayList<>();
- for (PackageInstallerSession s : session.getChildSessions()) {
- if (!s.isApexSession()) {
- childSessions.add(s);
- }
- }
- if (childSessions.isEmpty()) {
- // APEX-only multi-package staged session, nothing to do.
- return null;
- }
- final PackageInstaller.SessionParams params = session.params.copy();
- params.isStaged = false;
- final int apkParentSessionId = mPi.createSession(
- params, session.getInstallerPackageName(), session.getInstallerAttributionTag(),
- session.userId);
- final PackageInstallerSession apkParentSession = mPi.getSession(apkParentSessionId);
- try {
- apkParentSession.open();
- } catch (IOException e) {
- Slog.e(TAG, "Unable to prepare multi-package session for staged session "
- + session.sessionId);
- throw new PackageManagerException(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
- "Unable to prepare multi-package session for staged session");
- }
-
- for (int i = 0, size = childSessions.size(); i < size; i++) {
- final PackageInstallerSession apkChildSession = createAndWriteApkSession(
- childSessions.get(i));
- try {
- apkParentSession.addChildSessionId(apkChildSession.sessionId);
- } catch (IllegalStateException e) {
- Slog.e(TAG, "Failed to add a child session for installing the APK files", e);
- throw new PackageManagerException(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
- "Failed to add a child session " + apkChildSession.sessionId);
- }
- }
- return apkParentSession;
- }
- return null;
- }
-
/**
* Throws a PackageManagerException if there are duplicate packages in apk and apk-in-apex.
*/
@@ -828,6 +709,8 @@ public class StagingManager {
}
void commitSession(@NonNull PackageInstallerSession session) {
+ // Store this parent session which will be used to check overlapping later
+ createSession(session);
mPreRebootVerificationHandler.startPreRebootVerification(session);
}
@@ -857,14 +740,16 @@ public class StagingManager {
* </ul>
* @throws PackageManagerException if session fails the check
*/
- void checkNonOverlappingWithStagedSessions(@NonNull PackageInstallerSession session)
+ private void checkNonOverlappingWithStagedSessions(@NonNull PackageInstallerSession session)
throws PackageManagerException {
if (session.isMultiPackage()) {
// We cannot say a parent session overlaps until we process its children
return;
}
- if (session.getPackageName() == null) {
- throw new PackageManagerException(PackageManager.INSTALL_FAILED_INVALID_APK,
+
+ String packageName = session.getPackageName();
+ if (packageName == null) {
+ throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
"Cannot stage session " + session.sessionId + " with package name null");
}
@@ -876,40 +761,26 @@ public class StagingManager {
synchronized (mStagedSessions) {
for (int i = 0; i < mStagedSessions.size(); i++) {
final PackageInstallerSession stagedSession = mStagedSessions.valueAt(i);
- if (!stagedSession.isCommitted() || stagedSession.isStagedAndInTerminalState()
+ if (stagedSession.hasParentSessionId() || !stagedSession.isCommitted()
+ || stagedSession.isStagedAndInTerminalState()
|| stagedSession.isDestroyed()) {
continue;
}
- if (stagedSession.isMultiPackage()) {
- // This active parent staged session is useless as it doesn't have a package
- // name and the session we are checking is not a parent session either.
- continue;
- }
- // Check if stagedSession has an active parent session or not
- if (stagedSession.hasParentSessionId()) {
- final int parentId = stagedSession.getParentSessionId();
- final PackageInstallerSession parentSession = mStagedSessions.get(parentId);
- if (parentSession == null || parentSession.isStagedAndInTerminalState()
- || parentSession.isDestroyed()) {
- // Parent session has been abandoned or terminated already
- continue;
- }
- }
- // From here on, stagedSession is a non-parent active staged session
+ // From here on, stagedSession is a parent active staged session
// Check if session is one of the active sessions
- if (session.sessionId == stagedSession.sessionId) {
+ if (getSessionIdForParentOrSelf(session) == stagedSession.sessionId) {
Slog.w(TAG, "Session " + session.sessionId + " is already staged");
continue;
}
// New session cannot have same package name as one of the active sessions
- if (session.getPackageName().equals(stagedSession.getPackageName())) {
+ if (stagedSession.sessionContains(s -> s.getPackageName().equals(packageName))) {
if (isRollback) {
// If the new session is a rollback, then it gets priority. The existing
// session is failed to unblock rollback.
- final PackageInstallerSession root = getParentSessionOrSelf(stagedSession);
+ final PackageInstallerSession root = stagedSession;
if (!ensureActiveApexSessionIsAborted(root)) {
Slog.e(TAG, "Failed to abort apex session " + root.sessionId);
// Safe to ignore active apex session abort failure since session
@@ -923,7 +794,7 @@ public class StagingManager {
+ "blocking rollback session: " + session.sessionId);
} else {
throw new PackageManagerException(
- PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
+ SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
"Package: " + session.getPackageName() + " in session: "
+ session.sessionId + " has been staged already by session:"
+ " " + stagedSession.sessionId, null);
@@ -933,17 +804,16 @@ public class StagingManager {
// Staging multiple root sessions is not allowed if device doesn't support
// checkpoint. If session and stagedSession do not have common ancestor, they are
// from two different root sessions.
- if (!supportsCheckpoint && getSessionIdForParentOrSelf(session)
- != getSessionIdForParentOrSelf(stagedSession)) {
+ if (!supportsCheckpoint) {
throw new PackageManagerException(
- PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
+ SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
"Cannot stage multiple sessions without checkpoint support", null);
}
}
}
}
- void createSession(@NonNull PackageInstallerSession sessionInfo) {
+ private void createSession(@NonNull PackageInstallerSession sessionInfo) {
synchronized (mStagedSessions) {
mStagedSessions.append(sessionInfo.sessionId, sessionInfo);
}
@@ -1019,16 +889,15 @@ public class StagingManager {
}
void restoreSession(@NonNull PackageInstallerSession session, boolean isDeviceUpgrading) {
- PackageInstallerSession sessionToResume = session;
- synchronized (mStagedSessions) {
- mStagedSessions.append(session.sessionId, session);
- if (session.hasParentSessionId()) {
- // Only parent sessions can be restored
- return;
- }
+ if (session.hasParentSessionId()) {
+ // Only parent sessions can be restored
+ return;
}
+ // Store this parent session which will be used to check overlapping later
+ createSession(session);
// The preconditions used during pre-reboot verification might have changed when device
// is upgrading. Updated staged sessions to activation failed before we resume the session.
+ PackageInstallerSession sessionToResume = session;
if (isDeviceUpgrading && !sessionToResume.isStagedAndInTerminalState()) {
sessionToResume.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
"Build fingerprint has changed");
@@ -1279,6 +1148,19 @@ public class StagingManager {
* See {@link PreRebootVerificationHandler} to see all nodes of pre reboot verification
*/
private void handlePreRebootVerification_Start(@NonNull PackageInstallerSession session) {
+ try {
+ if (session.isMultiPackage()) {
+ for (PackageInstallerSession s : session.getChildSessions()) {
+ checkNonOverlappingWithStagedSessions(s);
+ }
+ } else {
+ checkNonOverlappingWithStagedSessions(session);
+ }
+ } catch (PackageManagerException e) {
+ onPreRebootVerificationFailure(session, e.error, e.getMessage());
+ return;
+ }
+
int rollbackId = -1;
if ((session.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
// If rollback is enabled for this session, we call through to the RollbackManager
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 0a8c8f6cbebc..2ada6131b0d2 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1660,7 +1660,7 @@ public class UserManagerService extends IUserManager.Stub {
}
}
if (changed) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
sendUserInfoChangedBroadcast(userId);
} finally {
@@ -3769,7 +3769,7 @@ public class UserManagerService extends IUserManager.Stub {
if (user == null) {
return null;
}
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user.id);
// Change the setting before applying the DISALLOW_SHARE_LOCATION restriction, otherwise
@@ -3822,7 +3822,7 @@ public class UserManagerService extends IUserManager.Stub {
return false;
}
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
final UserData userData;
synchronized (mPackagesLock) {
@@ -3883,7 +3883,7 @@ public class UserManagerService extends IUserManager.Stub {
}
private boolean removeUserUnchecked(@UserIdInt int userId) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
final UserData userData;
int currentUser = ActivityManager.getCurrentUser();
@@ -3991,7 +3991,7 @@ public class UserManagerService extends IUserManager.Stub {
// Let other services shutdown any activity and clean up their state before completely
// wiping the user's system directory and removing from the user list
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
Intent removedIntent = new Intent(Intent.ACTION_USER_REMOVED);
removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
@@ -4153,7 +4153,7 @@ public class UserManagerService extends IUserManager.Stub {
}
private int getUidForPackage(String packageName) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
return mContext.getPackageManager().getApplicationInfo(packageName,
PackageManager.MATCH_ANY_USER).uid;
@@ -5067,7 +5067,7 @@ public class UserManagerService extends IUserManager.Stub {
@Override
public void setUserIcon(@UserIdInt int userId, Bitmap bitmap) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
synchronized (mPackagesLock) {
UserData userData = getUserDataNoChecks(userId);
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 37127233be13..f74913c03ce2 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -501,7 +501,7 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
}
Log.i("PackageManager", "Compiling layouts in " + packageName + " (" + apkPath +
") to " + outDexFile);
- long callingId = Binder.clearCallingIdentity();
+ final long callingId = Binder.clearCallingIdentity();
try {
synchronized (mInstallLock) {
return mInstaller.compileLayouts(apkPath, packageName, outDexFile,
diff --git a/services/core/java/com/android/server/pm/dex/ViewCompiler.java b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
index a5672664f6fd..8afe62aabd59 100644
--- a/services/core/java/com/android/server/pm/dex/ViewCompiler.java
+++ b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
@@ -46,7 +46,7 @@ public class ViewCompiler {
final String outDexFile = dataDir.getAbsolutePath() + "/code_cache/compiled_view.dex";
Log.i("PackageManager", "Compiling layouts in " + packageName + " (" + apkPath +
") to " + outDexFile);
- long callingId = Binder.clearCallingIdentity();
+ final long callingId = Binder.clearCallingIdentity();
try {
synchronized (mInstallLock) {
return mInstaller.compileLayouts(apkPath, packageName, outDexFile,
diff --git a/services/core/java/com/android/server/pm/permission/OWNERS b/services/core/java/com/android/server/pm/permission/OWNERS
index 01dc01efaca8..0e88862e01b1 100644
--- a/services/core/java/com/android/server/pm/permission/OWNERS
+++ b/services/core/java/com/android/server/pm/permission/OWNERS
@@ -1,4 +1,5 @@
moltmann@google.com
+zhanghai@google.com
per-file DefaultPermissionGrantPolicy.java = hackbod@android.com
per-file DefaultPermissionGrantPolicy.java = jsharkey@android.com
per-file DefaultPermissionGrantPolicy.java = svetoslavganov@google.com
@@ -7,3 +8,4 @@ per-file DefaultPermissionGrantPolicy.java = yamasani@google.com
per-file DefaultPermissionGrantPolicy.java = patb@google.com
per-file DefaultPermissionGrantPolicy.java = eugenesusla@google.com
per-file DefaultPermissionGrantPolicy.java = moltmann@google.com
+per-file DefaultPermissionGrantPolicy.java = zhanghai@google.com
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 132535602b75..25e1848816d1 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -691,7 +691,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
boolean overridePolicy = false;
if (callingUid != Process.SYSTEM_UID && callingUid != Process.ROOT_UID) {
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
if ((flagMask & FLAG_PERMISSION_POLICY_FIXED) != 0) {
if (checkAdjustPolicyFlagPermission) {
@@ -1055,7 +1055,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// check.
if (packageName != null) {
// Allow access to a package that has been granted the READ_DEVICE_IDENTIFIERS appop.
- long token = mInjector.clearCallingIdentity();
+ final long token = mInjector.clearCallingIdentity();
AppOpsManager appOpsManager = (AppOpsManager) mInjector.getSystemService(
Context.APP_OPS_SERVICE);
try {
@@ -3215,7 +3215,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
+ " to register permissions as one time.");
Objects.requireNonNull(packageName);
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
getOneTimePermissionUserManager(userId).startPackageOneTimeSession(packageName,
timeoutMillis, importanceToResetTimer, importanceToKeepSessionAlive);
@@ -3231,7 +3231,7 @@ public class PermissionManagerService extends IPermissionManager.Stub {
+ " to remove permissions as one time.");
Objects.requireNonNull(packageName);
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
getOneTimePermissionUserManager(userId).stopPackageOneTimeSession(packageName);
} finally {
diff --git a/services/core/java/com/android/server/policy/DeviceStatePolicyImpl.java b/services/core/java/com/android/server/policy/DeviceStatePolicyImpl.java
new file mode 100644
index 000000000000..54f618327da8
--- /dev/null
+++ b/services/core/java/com/android/server/policy/DeviceStatePolicyImpl.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import android.annotation.NonNull;
+
+import com.android.server.devicestate.DeviceStatePolicy;
+import com.android.server.devicestate.DeviceStateProvider;
+
+/**
+ * Default empty implementation of {@link DeviceStatePolicy}.
+ *
+ * @see DeviceStateProviderImpl
+ */
+public final class DeviceStatePolicyImpl implements DeviceStatePolicy {
+ private final DeviceStateProvider mProvider;
+
+ public DeviceStatePolicyImpl() {
+ mProvider = new DeviceStateProviderImpl();
+ }
+
+ public DeviceStateProvider getDeviceStateProvider() {
+ return mProvider;
+ }
+
+ @Override
+ public void configureDeviceForState(int state, @NonNull Runnable onComplete) {
+ onComplete.run();
+ }
+}
diff --git a/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
new file mode 100644
index 000000000000..85ab0bc12cae
--- /dev/null
+++ b/services/core/java/com/android/server/policy/DeviceStateProviderImpl.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import android.annotation.Nullable;
+
+import com.android.server.devicestate.DeviceStateProvider;
+
+/**
+ * Default implementation of {@link DeviceStateProvider}. Currently only supports
+ * {@link #DEFAULT_DEVICE_STATE}.
+ *
+ * @see DeviceStatePolicyImpl
+ */
+final class DeviceStateProviderImpl implements DeviceStateProvider {
+ private static final int DEFAULT_DEVICE_STATE = 0;
+
+ @Nullable
+ private Listener mListener = null;
+
+ @Override
+ public void setListener(Listener listener) {
+ if (mListener != null) {
+ throw new RuntimeException("Provider already has a listener set.");
+ }
+
+ mListener = listener;
+ mListener.onSupportedDeviceStatesChanged(new int[]{ DEFAULT_DEVICE_STATE });
+ mListener.onStateChanged(DEFAULT_DEVICE_STATE);
+ }
+}
diff --git a/services/core/java/com/android/server/power/AttentionDetector.java b/services/core/java/com/android/server/power/AttentionDetector.java
index cbdfc56d6aa4..06edd19a376a 100644
--- a/services/core/java/com/android/server/power/AttentionDetector.java
+++ b/services/core/java/com/android/server/power/AttentionDetector.java
@@ -18,14 +18,12 @@ package com.android.server.power;
import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE;
-import android.Manifest;
import android.app.ActivityManager;
import android.app.SynchronousUserSwitchObserver;
import android.attention.AttentionManagerInternal;
import android.attention.AttentionManagerInternal.AttentionCallbackInternal;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.PowerManager;
@@ -124,9 +122,6 @@ public class AttentionDetector {
protected WindowManagerInternal mWindowManager;
@VisibleForTesting
- protected PackageManager mPackageManager;
-
- @VisibleForTesting
protected ContentResolver mContentResolver;
/**
@@ -164,7 +159,6 @@ public class AttentionDetector {
public void systemReady(Context context) {
mContext = context;
updateEnabledFromSettings(context);
- mPackageManager = context.getPackageManager();
mContentResolver = context.getContentResolver();
mAttentionManager = LocalServices.getService(AttentionManagerInternal.class);
mWindowManager = LocalServices.getService(WindowManagerInternal.class);
@@ -192,14 +186,11 @@ public class AttentionDetector {
public long updateUserActivity(long nextScreenDimming, long dimDurationMillis) {
if (nextScreenDimming == mLastActedOnNextScreenDimming
|| !mIsSettingEnabled
+ || !isAttentionServiceSupported()
|| mWindowManager.isKeyguardShowingAndNotOccluded()) {
return nextScreenDimming;
}
- if (!isAttentionServiceSupported() || !serviceHasSufficientPermissions()) {
- return nextScreenDimming;
- }
-
final long now = SystemClock.uptimeMillis();
final long whenToCheck = nextScreenDimming - getPreDimCheckDurationMillis();
final long whenToStopExtending = mLastUserActivityTime + getMaxExtensionMillis();
@@ -300,18 +291,6 @@ public class AttentionDetector {
return mAttentionManager != null && mAttentionManager.isAttentionServiceSupported();
}
- /**
- * Returns {@code true} if the attention service has sufficient permissions, disables the
- * depending features otherwise.
- */
- @VisibleForTesting
- boolean serviceHasSufficientPermissions() {
- final String attentionPackage = mPackageManager.getAttentionServicePackageName();
- return attentionPackage != null && mPackageManager.checkPermission(
- Manifest.permission.CAMERA, attentionPackage)
- == PackageManager.PERMISSION_GRANTED;
- }
-
public void dump(PrintWriter pw) {
pw.println("AttentionDetector:");
pw.println(" mIsSettingEnabled=" + mIsSettingEnabled);
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index a291cef5b39e..e7b1b4e4a687 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -660,7 +660,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
@Override
public String getDefaultSmsPackage(int userId) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
return CollectionUtils.firstOrNull(
getRoleHoldersAsUser(RoleManager.ROLE_SMS, userId));
@@ -699,7 +699,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
}
private int getUidForPackage(String packageName) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
return getContext().getPackageManager().getApplicationInfo(packageName,
PackageManager.MATCH_ANY_USER).uid;
diff --git a/services/core/java/com/android/server/search/Searchables.java b/services/core/java/com/android/server/search/Searchables.java
index ca7f0366df60..6e1e979b1bac 100644
--- a/services/core/java/com/android/server/search/Searchables.java
+++ b/services/core/java/com/android/server/search/Searchables.java
@@ -234,7 +234,7 @@ public class Searchables {
List<ResolveInfo> searchList;
final Intent intent = new Intent(Intent.ACTION_SEARCH);
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
searchList = queryIntentActivities(intent,
PackageManager.GET_META_DATA | PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index 2a74b3d23829..ee9694f90216 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -281,7 +281,7 @@ public class SliceManagerService extends ISliceManager.Stub {
String providerPkg = getProviderPkg(grantUri, providerUser);
mPermissions.grantSliceAccess(pkg, userId, providerPkg, providerUser, grantUri);
}
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
mContext.getContentResolver().notifyChange(uri, null);
} finally {
@@ -402,7 +402,7 @@ public class SliceManagerService extends ISliceManager.Stub {
}
private String getProviderPkg(Uri uri, int user) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
String providerName = getUriWithoutUserId(uri).getAuthority();
ProviderInfo provider = mContext.getPackageManager().resolveContentProviderAsUser(
@@ -438,7 +438,7 @@ public class SliceManagerService extends ISliceManager.Stub {
}
private boolean hasFullSliceAccess(String pkg, int userId) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
boolean ret = isDefaultHomeApp(pkg, userId) || isAssistant(pkg, userId)
|| isGrantedFullAccess(pkg, userId);
diff --git a/services/core/java/com/android/server/slice/SliceShellCommand.java b/services/core/java/com/android/server/slice/SliceShellCommand.java
index 9137a3bcbf2b..bdc8bbd13509 100644
--- a/services/core/java/com/android/server/slice/SliceShellCommand.java
+++ b/services/core/java/com/android/server/slice/SliceShellCommand.java
@@ -69,7 +69,7 @@ public class SliceShellCommand extends ShellCommand {
return -1;
}
Context context = mService.getContext();
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
Uri uri = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index c871a5e9647f..e0b671f38426 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -1574,7 +1574,7 @@ public class StatsPullAtomService extends SystemService {
}
int pullWifiActivityInfoLocked(int atomTag, List<StatsEvent> pulledData) {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
SynchronousResultReceiver wifiReceiver = new SynchronousResultReceiver("wifi");
mWifiManager.getWifiActivityEnergyInfoAsync(
@@ -1622,7 +1622,7 @@ public class StatsPullAtomService extends SystemService {
}
int pullModemActivityInfoLocked(int atomTag, List<StatsEvent> pulledData) {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony");
mTelephony.requestModemActivityInfo(modemReceiver);
@@ -2723,7 +2723,7 @@ public class StatsPullAtomService extends SystemService {
// Add a RoleHolder atom for each package that holds a role.
int pullRoleHolderLocked(int atomTag, List<StatsEvent> pulledData) {
- long callingToken = Binder.clearCallingIdentity();
+ final long callingToken = Binder.clearCallingIdentity();
try {
PackageManager pm = mContext.getPackageManager();
RoleManagerInternal rmi = LocalServices.getService(RoleManagerInternal.class);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index d1fd0adb44c2..6a68dc1fb2a2 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -1158,7 +1158,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
@Override
public void onPanelRevealed(boolean clearNotificationEffects, int numItems) {
enforceStatusBarService();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.onPanelRevealed(clearNotificationEffects, numItems);
} finally {
@@ -1169,7 +1169,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
@Override
public void clearNotificationEffects() throws RemoteException {
enforceStatusBarService();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.clearEffects();
} finally {
@@ -1180,7 +1180,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
@Override
public void onPanelHidden() throws RemoteException {
enforceStatusBarService();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.onPanelHidden();
} finally {
@@ -1196,7 +1196,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
enforceStatusBarService();
String reason = PowerManager.SHUTDOWN_USER_REQUESTED;
ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.prepareForPossibleShutdown();
// ShutdownThread displays UI, so give it a UI context.
@@ -1217,7 +1217,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
? PowerManager.REBOOT_SAFE_MODE
: PowerManager.SHUTDOWN_USER_REQUESTED;
ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.prepareForPossibleShutdown();
mHandler.post(() -> {
@@ -1236,7 +1236,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
@Override
public void onGlobalActionsShown() {
enforceStatusBarService();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
if (mGlobalActionListener == null) return;
mGlobalActionListener.onGlobalActionsShown();
@@ -1248,7 +1248,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
@Override
public void onGlobalActionsHidden() {
enforceStatusBarService();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
if (mGlobalActionListener == null) return;
mGlobalActionListener.onGlobalActionsDismissed();
@@ -1262,7 +1262,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
enforceStatusBarService();
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.onNotificationClick(callingUid, callingPid, key, nv);
} finally {
@@ -1277,7 +1277,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
enforceStatusBarService();
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.onNotificationActionClick(callingUid, callingPid, key,
actionIndex, action, nv, generatedByAssistant);
@@ -1292,7 +1292,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
enforceStatusBarService();
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
// WARNING: this will call back into us to do the remove. Don't hold any locks.
mNotificationDelegate.onNotificationError(callingUid, callingPid,
@@ -1310,7 +1310,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
enforceStatusBarService();
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.onNotificationClear(callingUid, callingPid, pkg, tag, id, userId,
key, dismissalSurface, dismissalSentiment, nv);
@@ -1324,7 +1324,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
NotificationVisibility[] newlyVisibleKeys, NotificationVisibility[] noLongerVisibleKeys)
throws RemoteException {
enforceStatusBarService();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.onNotificationVisibilityChanged(
newlyVisibleKeys, noLongerVisibleKeys);
@@ -1337,7 +1337,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
public void onNotificationExpansionChanged(String key, boolean userAction, boolean expanded,
int location) throws RemoteException {
enforceStatusBarService();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.onNotificationExpansionChanged(
key, userAction, expanded, location);
@@ -1349,7 +1349,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
@Override
public void onNotificationDirectReplied(String key) throws RemoteException {
enforceStatusBarService();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.onNotificationDirectReplied(key);
} finally {
@@ -1361,7 +1361,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
public void onNotificationSmartSuggestionsAdded(String key, int smartReplyCount,
int smartActionCount, boolean generatedByAssistant, boolean editBeforeSending) {
enforceStatusBarService();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.onNotificationSmartSuggestionsAdded(key, smartReplyCount,
smartActionCount, generatedByAssistant, editBeforeSending);
@@ -1375,7 +1375,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
String key, int replyIndex, CharSequence reply, int notificationLocation,
boolean modifiedBeforeSending) throws RemoteException {
enforceStatusBarService();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.onNotificationSmartReplySent(key, replyIndex, reply,
notificationLocation, modifiedBeforeSending);
@@ -1387,7 +1387,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
@Override
public void onNotificationSettingsViewed(String key) throws RemoteException {
enforceStatusBarService();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.onNotificationSettingsViewed(key);
} finally {
@@ -1400,7 +1400,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
enforceStatusBarService();
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.onClearAll(callingUid, callingPid, userId);
} finally {
@@ -1411,7 +1411,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
@Override
public void onNotificationBubbleChanged(String key, boolean isBubble, int flags) {
enforceStatusBarService();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.onNotificationBubbleChanged(key, isBubble, flags);
} finally {
@@ -1422,7 +1422,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
@Override
public void onBubbleNotificationSuppressionChanged(String key, boolean isNotifSuppressed) {
enforceStatusBarService();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.onBubbleNotificationSuppressionChanged(key, isNotifSuppressed);
} finally {
@@ -1446,7 +1446,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
String packageName) {
enforceStatusBarService();
int callingUid = Binder.getCallingUid();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.grantInlineReplyUriPermission(key, uri, user, packageName,
callingUid);
@@ -1459,7 +1459,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
public void clearInlineReplyUriPermissions(String key) {
enforceStatusBarService();
int callingUid = Binder.getCallingUid();
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
mNotificationDelegate.clearInlineReplyUriPermissions(key, callingUid);
} finally {
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index 70ab48b9005b..59cebf769a4e 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -114,7 +114,7 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
enforceSuggestManualTimePermission();
Objects.requireNonNull(timeSignal);
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
return mTimeDetectorStrategy.suggestManualTime(timeSignal);
} finally {
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
index 6e1f89b3919d..d09cd38d7680 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -148,7 +148,7 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
enforceManageTimeZoneDetectorPermission();
int userId = mCallerIdentityInjector.getCallingUserId();
- long token = mCallerIdentityInjector.clearCallingIdentity();
+ final long token = mCallerIdentityInjector.clearCallingIdentity();
try {
ConfigurationInternal configurationInternal =
mTimeZoneDetectorStrategy.getConfigurationInternal(userId);
@@ -164,7 +164,7 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
Objects.requireNonNull(configuration);
int callingUserId = mCallerIdentityInjector.getCallingUserId();
- long token = mCallerIdentityInjector.clearCallingIdentity();
+ final long token = mCallerIdentityInjector.clearCallingIdentity();
try {
return mTimeZoneDetectorStrategy.updateConfiguration(callingUserId, configuration);
} finally {
@@ -278,7 +278,7 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub
Objects.requireNonNull(timeZoneSuggestion);
int userId = mCallerIdentityInjector.getCallingUserId();
- long token = mCallerIdentityInjector.clearCallingIdentity();
+ final long token = mCallerIdentityInjector.clearCallingIdentity();
try {
return mTimeZoneDetectorStrategy.suggestManualTimeZone(userId, timeZoneSuggestion);
} finally {
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 89b108c24630..0e8fd8fa9f8a 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -1125,7 +1125,7 @@ public class TrustManagerService extends SystemService {
userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
false /* allowAll */, true /* requireFull */, "isDeviceLocked", null);
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
userId = resolveProfileParent(userId);
@@ -1141,7 +1141,7 @@ public class TrustManagerService extends SystemService {
userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
false /* allowAll */, true /* requireFull */, "isDeviceSecure", null);
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
userId = resolveProfileParent(userId);
@@ -1328,7 +1328,7 @@ public class TrustManagerService extends SystemService {
}
private int resolveProfileParent(int userId) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
UserInfo parent = mUserManager.getProfileParent(userId);
if (parent != null) {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 5f4d46cabdc0..8b0963b9f535 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1444,7 +1444,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
public void engineShown(IWallpaperEngine engine) {
synchronized (mLock) {
if (mReply != null) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
mReply.sendResult(null);
} catch (RemoteException e) {
@@ -2009,7 +2009,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
public boolean hasNamedWallpaper(String name) {
synchronized (mLock) {
List<UserInfo> users;
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
users = ((UserManager) mContext.getSystemService(Context.USER_SERVICE)).getUsers();
} finally {
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 90a153be8800..ee46ce13ee73 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -171,7 +171,7 @@ public class WebViewUpdateService extends SystemService {
return;
}
- long callingId = Binder.clearCallingIdentity();
+ final long callingId = Binder.clearCallingIdentity();
try {
WebViewUpdateService.this.mImpl.notifyRelroCreationCompleted();
} finally {
@@ -232,7 +232,7 @@ public class WebViewUpdateService extends SystemService {
throw new SecurityException(msg);
}
- long callingId = Binder.clearCallingIdentity();
+ final long callingId = Binder.clearCallingIdentity();
try {
return WebViewUpdateService.this.mImpl.changeProviderAndSetting(
newProvider);
@@ -285,7 +285,7 @@ public class WebViewUpdateService extends SystemService {
throw new SecurityException(msg);
}
- long callingId = Binder.clearCallingIdentity();
+ final long callingId = Binder.clearCallingIdentity();
try {
WebViewUpdateService.this.mImpl.enableMultiProcess(enable);
} finally {
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 45d3fce1ac21..9ed68b8041db 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -2058,6 +2058,8 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
// Update the current top activity.
mTopResumedActivity = topStack.mResumedActivity;
scheduleTopResumedActivityStateIfNeeded();
+
+ mService.updateTopApp(mTopResumedActivity);
}
/** Schedule top resumed state change if previous top activity already reported back. */
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index eaa58390d39b..96740128879b 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -324,7 +324,6 @@ public abstract class ActivityTaskManagerInternal {
public abstract void onProcessRemoved(String name, int uid);
public abstract void onCleanUpApplicationRecord(WindowProcessController proc);
public abstract int getTopProcessState();
- public abstract boolean isHeavyWeightProcess(WindowProcessController proc);
public abstract void clearHeavyWeightProcessIfEquals(WindowProcessController proc);
public abstract void finishHeavyWeightApp();
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index e06c156bceab..48b0b7d27917 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -386,16 +386,18 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
/** All processes we currently have running mapped by pid and uid */
final WindowProcessControllerMap mProcessMap = new WindowProcessControllerMap();
/** This is the process holding what we currently consider to be the "home" activity. */
- WindowProcessController mHomeProcess;
+ volatile WindowProcessController mHomeProcess;
/** The currently running heavy-weight process, if any. */
- WindowProcessController mHeavyWeightProcess = null;
+ volatile WindowProcessController mHeavyWeightProcess;
boolean mHasHeavyWeightFeature;
boolean mHasLeanbackFeature;
+ /** The process of the top most activity. */
+ volatile WindowProcessController mTopApp;
/**
* This is the process holding the activity the user last visited that is in a different process
* from the one they are currently in.
*/
- WindowProcessController mPreviousProcess;
+ volatile WindowProcessController mPreviousProcess;
/** The time at which the previous process was last visible. */
long mPreviousProcessVisibleTime;
@@ -593,7 +595,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
* Whether mSleeping can quickly toggled between true/false without the device actually
* display changing states is undefined.
*/
- private boolean mSleeping = false;
+ private volatile boolean mSleeping;
/**
* The mDreaming state is set by the {@link DreamManagerService} when it receives a request to
@@ -606,7 +608,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
* The process state used for processes that are running the top activities.
* This changes between TOP and TOP_SLEEPING to following mSleeping.
*/
- int mTopProcessState = ActivityManager.PROCESS_STATE_TOP;
+ volatile int mTopProcessState = ActivityManager.PROCESS_STATE_TOP;
@Retention(RetentionPolicy.SOURCE)
@IntDef({
@@ -2172,7 +2174,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public RootTaskInfo getFocusedRootTaskInfo() throws RemoteException {
enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getFocusedRootTaskInfo()");
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
Task focusedStack = getTopDisplayFocusedStack();
@@ -2357,7 +2359,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public Rect getTaskBounds(int taskId) {
mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getTaskBounds()");
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
Rect rect = new Rect();
try {
synchronized (mGlobalLock) {
@@ -2921,7 +2923,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public List<RootTaskInfo> getAllRootTaskInfos() {
enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getAllRootTaskInfos()");
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
return mRootWindowContainer.getAllRootTaskInfos(INVALID_DISPLAY);
@@ -2934,7 +2936,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public RootTaskInfo getRootTaskInfo(int windowingMode, int activityType) {
enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getRootTaskInfo()");
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
return mRootWindowContainer.getRootTaskInfo(windowingMode, activityType);
@@ -2948,7 +2950,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public List<RootTaskInfo> getAllRootTaskInfosOnDisplay(int displayId) {
enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS,
"getAllRootTaskInfosOnDisplay()");
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
return mRootWindowContainer.getAllRootTaskInfos(displayId);
@@ -2962,7 +2964,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public RootTaskInfo getRootTaskInfoOnDisplay(int windowingMode, int activityType,
int displayId) {
enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "getRootTaskInfoOnDisplay()");
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
return mRootWindowContainer.getRootTaskInfo(windowingMode, activityType, displayId);
@@ -3004,7 +3006,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public void startSystemLockTaskMode(int taskId) {
mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "startSystemLockTaskMode");
// This makes inner call to look as if it was initiated by system.
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
final Task task = mRootWindowContainer.anyTaskForId(taskId,
@@ -3055,7 +3057,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
// - will put the device in fully locked mode (LockTask), if the app is allowlisted
// - will start the pinned mode, otherwise
final int callingUid = Binder.getCallingUid();
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
// When a task is locked, dismiss the pinned stack if it exists
mRootWindowContainer.removeRootTasksInWindowingModes(WINDOWING_MODE_PINNED);
@@ -3068,7 +3070,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
private void stopLockTaskModeInternal(@Nullable IBinder token, boolean isSystemCaller) {
final int callingUid = Binder.getCallingUid();
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
Task task = null;
@@ -3149,7 +3151,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
public List<IBinder> getAppTasks(String callingPackage) {
int callingUid = Binder.getCallingUid();
assertPackageMatchesCallingUid(callingPackage);
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
return mRecentTasks.getAppTasksList(callingUid, callingPackage);
@@ -3368,7 +3370,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public boolean resizeTask(int taskId, Rect bounds, int resizeMode) {
mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeTask()");
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
final Task task = mRootWindowContainer.anyTaskForId(taskId,
@@ -3433,7 +3435,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
synchronized (mGlobalLock) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
if (mKeyguardShown != keyguardShowing) {
mKeyguardShown = keyguardShowing;
final Message msg = PooledLambda.obtainMessage(
@@ -3498,7 +3500,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public void toggleFreeformWindowingMode(IBinder token) {
synchronized (mGlobalLock) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
final ActivityRecord r = ActivityRecord.forTokenLocked(token);
if (r == null) {
@@ -3818,7 +3820,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Override
public boolean showAssistFromActivity(IBinder token, Bundle args) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
ActivityRecord caller = ActivityRecord.forTokenLocked(token);
@@ -3862,7 +3864,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
try {
activityToCallback.app.getThread().scheduleLocalVoiceInteractionStarted(activity,
voiceInteractor);
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
startRunningVoiceLocked(voiceSession, activityToCallback.info.applicationInfo.uid);
} finally {
@@ -3999,7 +4001,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
+ "Device doesn't support picture-in-picture mode");
}
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
return mRootWindowContainer.moveTopStackActivityToPinnedRootTask(rootTaskId);
} finally {
@@ -4177,7 +4179,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
Rect tempDockedTaskInsetBounds,
Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds) {
enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "resizePrimarySplitScreen()");
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
final TaskDisplayArea tc = mRootWindowContainer.getDefaultTaskDisplayArea();
@@ -5569,6 +5571,13 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mH.sendMessage(m);
}
+ void updateTopApp(ActivityRecord topResumedActivity) {
+ final ActivityRecord top = topResumedActivity != null ? topResumedActivity
+ // If there is no resumed activity, it will choose the pausing activity.
+ : mRootWindowContainer.getTopResumedActivity();
+ mTopApp = top != null ? top.app : null;
+ }
+
void updateActivityUsageStats(ActivityRecord activity, int event) {
ComponentName taskRoot = null;
final Task task = activity.getTask();
@@ -6368,17 +6377,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@HotPath(caller = HotPath.OOM_ADJUSTMENT)
@Override
public int getTopProcessState() {
- synchronized (mGlobalLockWithoutBoost) {
- return mTopProcessState;
- }
- }
-
- @HotPath(caller = HotPath.OOM_ADJUSTMENT)
- @Override
- public boolean isHeavyWeightProcess(WindowProcessController proc) {
- synchronized (mGlobalLockWithoutBoost) {
- return proc == mHeavyWeightProcess;
- }
+ return mTopProcessState;
}
@HotPath(caller = HotPath.PROCESS_CHANGE)
@@ -6410,9 +6409,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@HotPath(caller = HotPath.OOM_ADJUSTMENT)
@Override
public boolean isSleeping() {
- synchronized (mGlobalLockWithoutBoost) {
- return isSleepingLocked();
- }
+ return mSleeping;
}
@Override
@@ -7206,15 +7203,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@HotPath(caller = HotPath.OOM_ADJUSTMENT)
@Override
public WindowProcessController getTopApp() {
- synchronized (mGlobalLockWithoutBoost) {
- if (mRootWindowContainer == null) {
- // Return null if mRootWindowContainer not yet initialize, while update
- // oomadj after AMS created.
- return null;
- }
- final ActivityRecord top = mRootWindowContainer.getTopResumedActivity();
- return top != null ? top.app : null;
- }
+ return mTopApp;
}
@Override
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index dd1d55b2d54d..3e798790f45e 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -58,7 +58,7 @@ class AppTaskImpl extends IAppTask.Stub {
checkCaller();
synchronized (mService.mGlobalLock) {
- long origId = Binder.clearCallingIdentity();
+ final long origId = Binder.clearCallingIdentity();
try {
// We remove the task from recents to preserve backwards
if (!mService.mStackSupervisor.removeTaskById(mTaskId, false,
@@ -76,7 +76,7 @@ class AppTaskImpl extends IAppTask.Stub {
checkCaller();
synchronized (mService.mGlobalLock) {
- long origId = Binder.clearCallingIdentity();
+ final long origId = Binder.clearCallingIdentity();
try {
Task task = mService.mRootWindowContainer.anyTaskForId(mTaskId,
MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
@@ -162,7 +162,7 @@ class AppTaskImpl extends IAppTask.Stub {
checkCaller();
synchronized (mService.mGlobalLock) {
- long origId = Binder.clearCallingIdentity();
+ final long origId = Binder.clearCallingIdentity();
try {
Task task = mService.mRootWindowContainer.anyTaskForId(mTaskId,
MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4b2c41ddecec..dafa07e5cc60 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -90,7 +90,9 @@ import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_L
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
import static com.android.server.wm.DisplayContentProto.APP_TRANSITION;
+import static com.android.server.wm.DisplayContentProto.CAN_SHOW_IME;
import static com.android.server.wm.DisplayContentProto.CLOSING_APPS;
+import static com.android.server.wm.DisplayContentProto.CURRENT_FOCUS;
import static com.android.server.wm.DisplayContentProto.DISPLAY_FRAMES;
import static com.android.server.wm.DisplayContentProto.DISPLAY_INFO;
import static com.android.server.wm.DisplayContentProto.DISPLAY_READY;
@@ -98,6 +100,10 @@ import static com.android.server.wm.DisplayContentProto.DPI;
import static com.android.server.wm.DisplayContentProto.FOCUSED_APP;
import static com.android.server.wm.DisplayContentProto.FOCUSED_ROOT_TASK_ID;
import static com.android.server.wm.DisplayContentProto.ID;
+import static com.android.server.wm.DisplayContentProto.IME_INSETS_SOURCE_PROVIDER;
+import static com.android.server.wm.DisplayContentProto.INPUT_METHOD_CONTROL_TARGET;
+import static com.android.server.wm.DisplayContentProto.INPUT_METHOD_INPUT_TARGET;
+import static com.android.server.wm.DisplayContentProto.INPUT_METHOD_TARGET;
import static com.android.server.wm.DisplayContentProto.OPENING_APPS;
import static com.android.server.wm.DisplayContentProto.RESUMED_ACTIVITY;
import static com.android.server.wm.DisplayContentProto.ROOT_DISPLAY_AREA;
@@ -2864,7 +2870,26 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
proto.write(FOCUSED_ROOT_TASK_ID, INVALID_TASK_ID);
}
proto.write(DISPLAY_READY, isReady());
-
+ if (mInputMethodTarget != null) {
+ mInputMethodTarget.dumpDebug(proto, INPUT_METHOD_TARGET, logLevel);
+ }
+ if (mInputMethodInputTarget != null) {
+ mInputMethodInputTarget.dumpDebug(proto, INPUT_METHOD_INPUT_TARGET, logLevel);
+ }
+ if (mInputMethodControlTarget != null
+ && mInputMethodControlTarget.getWindow() != null) {
+ mInputMethodControlTarget.getWindow().dumpDebug(proto, INPUT_METHOD_CONTROL_TARGET,
+ logLevel);
+ }
+ if (mCurrentFocus != null) {
+ mCurrentFocus.dumpDebug(proto, CURRENT_FOCUS, logLevel);
+ }
+ if (mInsetsStateController != null
+ && mInsetsStateController.getImeSourceProvider() != null) {
+ mInsetsStateController.getImeSourceProvider().dumpDebug(proto,
+ IME_INSETS_SOURCE_PROVIDER, logLevel);
+ }
+ proto.write(CAN_SHOW_IME, canShowIme());
proto.end(token);
}
@@ -3374,6 +3399,14 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
mUpdateImeTarget = updateImeTarget;
WindowState target = getWindow(mComputeImeTargetPredicate);
+ // Keeps the IME target with the last window while swiping up to recents to prevent
+ // flickering due to IME hide animation on top of recents.
+ // TODO(b/166736352): This logic should go away once we switch over target immediately
+ // and do the screenshot to preserve IME on disappearing target
+ if (target != null && curTarget != null && target.isActivityTypeHome()
+ && curTarget.getInsetsState().getSource(ITYPE_IME).isVisible()) {
+ return curTarget;
+ }
// Yet more tricksyness! If this window is a "starting" window, we do actually want
// to be on top of it, but it is not -really- where input will go. So look down below
@@ -3546,7 +3579,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
);
}
- private void updateImeParent() {
+ void updateImeParent() {
final SurfaceControl newParent = computeImeParent();
if (newParent != null) {
getPendingTransaction().reparent(mImeWindowsContainers.mSurfaceControl, newParent);
diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java
index f8495b5abdf5..d67f3f967e66 100644
--- a/services/core/java/com/android/server/wm/DisplayFrames.java
+++ b/services/core/java/com/android/server/wm/DisplayFrames.java
@@ -16,9 +16,8 @@
package com.android.server.wm;
-import static android.view.Surface.ROTATION_180;
-import static android.view.Surface.ROTATION_270;
-import static android.view.Surface.ROTATION_90;
+import static com.android.server.wm.DisplayFramesProto.CURRENT;
+import static com.android.server.wm.DisplayFramesProto.DOCK;
import static com.android.server.wm.DisplayFramesProto.STABLE_BOUNDS;
import android.annotation.NonNull;
@@ -155,6 +154,8 @@ public class DisplayFrames {
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
final long token = proto.start(fieldId);
mStable.dumpDebug(proto, STABLE_BOUNDS);
+ mDock.dumpDebug(proto, DOCK);
+ mCurrent.dumpDebug(proto, CURRENT);
proto.end(token);
}
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index dce798e81a86..3ff369a34764 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -929,7 +929,6 @@ public class DisplayPolicy {
attrs.hideTimeoutMilliseconds = mAccessibilityManager.getRecommendedTimeoutMillis(
(int) attrs.hideTimeoutMilliseconds,
AccessibilityManager.FLAG_CONTENT_TEXT);
- attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
// Toasts can't be clickable
attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
break;
diff --git a/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java b/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java
index c5c236416013..14880ed30f24 100644
--- a/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java
+++ b/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java
@@ -71,7 +71,7 @@ class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub
}
private void doTake(IBinder permissionOwner) throws RemoteException {
- long origId = Binder.clearCallingIdentity();
+ final long origId = Binder.clearCallingIdentity();
try {
for (int i = 0; i < mUris.size(); i++) {
UriGrantsManager.getService().grantUriPermissionFromOwner(
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index 1d8cdf7e773c..0813b4f9efe0 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -17,7 +17,11 @@
package com.android.server.wm;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME;
+import static com.android.server.wm.ImeInsetsSourceProviderProto.IME_TARGET_FROM_IME;
+import static com.android.server.wm.ImeInsetsSourceProviderProto.INSETS_SOURCE_PROVIDER;
+import static com.android.server.wm.ImeInsetsSourceProviderProto.IS_IME_LAYOUT_DRAWN;
+import android.util.proto.ProtoOutputStream;
import android.view.InsetsSource;
import android.view.WindowInsets;
@@ -154,4 +158,15 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider {
pw.println();
}
}
+
+ @Override
+ void dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel) {
+ final long token = proto.start(fieldId);
+ super.dumpDebug(proto, INSETS_SOURCE_PROVIDER, logLevel);
+ if (mImeTargetFromIme != null) {
+ mImeTargetFromIme.getWindow().dumpDebug(proto, IME_TARGET_FROM_IME, logLevel);
+ }
+ proto.write(IS_IME_LAYOUT_DRAWN, mIsImeLayoutDrawn);
+ proto.end(token);
+ }
}
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index 5bed1862a629..7defc5ddb3f4 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -23,6 +23,21 @@ import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME;
+import static com.android.server.wm.InsetsSourceProviderProto.CAPTURED_LEASH;
+import static com.android.server.wm.InsetsSourceProviderProto.CLIENT_VISIBLE;
+import static com.android.server.wm.InsetsSourceProviderProto.CONTROL;
+import static com.android.server.wm.InsetsSourceProviderProto.CONTROLLABLE;
+import static com.android.server.wm.InsetsSourceProviderProto.CONTROL_TARGET;
+import static com.android.server.wm.InsetsSourceProviderProto.FAKE_CONTROL;
+import static com.android.server.wm.InsetsSourceProviderProto.FAKE_CONTROL_TARGET;
+import static com.android.server.wm.InsetsSourceProviderProto.FINISH_SEAMLESS_ROTATE_FRAME_NUMBER;
+import static com.android.server.wm.InsetsSourceProviderProto.FRAME;
+import static com.android.server.wm.InsetsSourceProviderProto.IME_OVERRIDDEN_FRAME;
+import static com.android.server.wm.InsetsSourceProviderProto.IS_LEASH_READY_FOR_DISPATCHING;
+import static com.android.server.wm.InsetsSourceProviderProto.PENDING_CONTROL_TARGET;
+import static com.android.server.wm.InsetsSourceProviderProto.SEAMLESS_ROTATING;
+import static com.android.server.wm.InsetsSourceProviderProto.SERVER_VISIBLE;
+import static com.android.server.wm.InsetsSourceProviderProto.SOURCE;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_INSETS_CONTROL;
import static com.android.server.wm.WindowManagerService.H.LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED;
@@ -452,6 +467,36 @@ class InsetsSourceProvider {
}
}
+ void dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel) {
+ final long token = proto.start(fieldId);
+ mSource.dumpDebug(proto, SOURCE);
+ mTmpRect.dumpDebug(proto, FRAME);
+ mFakeControl.dumpDebug(proto, FAKE_CONTROL);
+ if (mControl != null) {
+ mControl.dumpDebug(proto, CONTROL);
+ }
+ if (mControlTarget != null && mControlTarget.getWindow() != null) {
+ mControlTarget.getWindow().dumpDebug(proto, CONTROL_TARGET, logLevel);
+ }
+ if (mPendingControlTarget != null && mPendingControlTarget.getWindow() != null) {
+ mPendingControlTarget.getWindow().dumpDebug(proto, PENDING_CONTROL_TARGET, logLevel);
+ }
+ if (mFakeControlTarget != null && mFakeControlTarget.getWindow() != null) {
+ mFakeControlTarget.getWindow().dumpDebug(proto, FAKE_CONTROL_TARGET, logLevel);
+ }
+ if (mAdapter != null && mAdapter.mCapturedLeash != null) {
+ mAdapter.mCapturedLeash.dumpDebug(proto, CAPTURED_LEASH);
+ }
+ mImeOverrideFrame.dumpDebug(proto, IME_OVERRIDDEN_FRAME);
+ proto.write(IS_LEASH_READY_FOR_DISPATCHING, mIsLeashReadyForDispatching);
+ proto.write(CLIENT_VISIBLE, mClientVisible);
+ proto.write(SERVER_VISIBLE, mServerVisible);
+ proto.write(SEAMLESS_ROTATING, mSeamlessRotating);
+ proto.write(FINISH_SEAMLESS_ROTATE_FRAME_NUMBER, mFinishSeamlessRotateFrameNumber);
+ proto.write(CONTROLLABLE, mControllable);
+ proto.end(token);
+ }
+
private class ControlAdapter implements AnimationAdapter {
private SurfaceControl mCapturedLeash;
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 80c7366a6678..71eb18ca4117 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -555,7 +555,7 @@ class KeyguardController {
&& !mService.mWindowManager.mPowerManager.isInteractive()
&& (mRequestDismissKeyguard || occludedByActivity)) {
controller.mStackSupervisor.wakeUp("handleTurnScreenOn");
- mTopOccludesActivity.setCurrentLaunchCanTurnScreenOn(false);
+ mTopTurnScreenOnActivity.setCurrentLaunchCanTurnScreenOn(false);
}
if (lastOccluded != mOccluded) {
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 38d20a8bd685..a40b3104c5ac 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -283,6 +283,20 @@ public class RecentsAnimationController implements DeathRecipient {
public void hideCurrentInputMethod() {
final long token = Binder.clearCallingIdentity();
try {
+ synchronized (mService.getWindowManagerLock()) {
+ // Make sure to update the correct IME parent in case that the IME parent may
+ // be computed as display layer when re-layout window happens during rotation
+ // but there is intermediate state that the bounds of task and the IME
+ // target's activity is not the same during rotating.
+ mDisplayContent.updateImeParent();
+
+ // Ignore hiding IME if IME window is attached to app.
+ // Since we would like to snapshot Task with IME window while transitioning
+ // to recents.
+ if (mDisplayContent.isImeAttachedToApp()) {
+ return;
+ }
+ }
final InputMethodManagerInternal inputMethodManagerInternal =
LocalServices.getService(InputMethodManagerInternal.class);
if (inputMethodManagerInternal != null) {
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 9ff99f5093d6..1fdb49f38cf5 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -255,7 +255,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
@Override
public boolean performHapticFeedback(int effectId, boolean always) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
return mService.mPolicy.performHapticFeedback(mUid, mPackageName,
effectId, always, null);
@@ -313,7 +313,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
if (DEBUG_TASK_POSITIONING) Slog.d(
TAG_WM, "startMovingTask: {" + startX + "," + startY + "}");
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
return mService.mTaskPositioningController.startMovingTask(window, startX, startY);
} finally {
@@ -325,7 +325,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
public void finishMovingTask(IWindow window) {
if (DEBUG_TASK_POSITIONING) Slog.d(TAG_WM, "finishMovingTask");
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
mService.mTaskPositioningController.finishTaskPositioning(window);
} finally {
@@ -335,7 +335,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
@Override
public void reportSystemGestureExclusionChanged(IWindow window, List<Rect> exclusionRects) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
mService.reportSystemGestureExclusionChanged(this, window, exclusionRects);
} finally {
@@ -352,7 +352,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
@Override
public void setWallpaperPosition(IBinder window, float x, float y, float xStep, float yStep) {
synchronized (mService.mGlobalLock) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
actionOnWallpaper(window, (wpController, windowState) ->
wpController.setWindowWallpaperPosition(windowState, x, y, xStep, yStep));
@@ -369,7 +369,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
+ zoom);
}
synchronized (mService.mGlobalLock) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
actionOnWallpaper(window, (wpController, windowState) ->
wpController.setWallpaperZoomOut(windowState, zoom));
@@ -398,7 +398,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
@Override
public void setWallpaperDisplayOffset(IBinder window, int x, int y) {
synchronized (mService.mGlobalLock) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
actionOnWallpaper(window, (wpController, windowState) ->
wpController.setWindowWallpaperDisplayOffset(windowState, x, y));
@@ -412,7 +412,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
int z, Bundle extras, boolean sync) {
synchronized (mService.mGlobalLock) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
final WindowState windowState = mService.windowForClientLocked(this, window, true);
return windowState.getDisplayContent().mWallpaperController
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index bc4f75276a95..87b470a54f77 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -368,7 +368,8 @@ class TaskSnapshotController {
SurfaceControl[] excludeLayers;
final WindowState imeWindow = task.getDisplayContent().mInputMethodWindow;
- if (imeWindow != null) {
+ // Exclude IME window snapshot when IME isn't proper to attach to app.
+ if (imeWindow != null && !task.getDisplayContent().isImeAttachedToApp()) {
excludeLayers = new SurfaceControl[1];
excludeLayers[0] = imeWindow.getSurfaceControl();
} else {
diff --git a/services/core/java/com/android/server/wm/VrController.java b/services/core/java/com/android/server/wm/VrController.java
index 54cac3845798..9e159aba4d77 100644
--- a/services/core/java/com/android/server/wm/VrController.java
+++ b/services/core/java/com/android/server/wm/VrController.java
@@ -101,7 +101,7 @@ final class VrController {
// - Calls to setPersistentVrThread will fail.
// - No threads will have elevated scheduling priority for VR.
//
- private int mVrState = FLAG_NON_VR_MODE;
+ private volatile int mVrState = FLAG_NON_VR_MODE;
// The single VR render thread on the device that is given elevated scheduling priority.
private int mVrRenderThreadTid = 0;
@@ -146,6 +146,14 @@ final class VrController {
}
/**
+ * Called without lock to determine whether to call {@link #onTopProcChangedLocked} in lock. It
+ * is used to optimize performance for the path that may have lock contention frequently.
+ */
+ boolean isInterestingToSchedGroup() {
+ return (mVrState & (FLAG_VR_MODE | FLAG_PERSISTENT_VR_MODE)) != 0;
+ }
+
+ /**
* Called when ActivityManagerService's TOP_APP process has changed.
*
* <p>Note: This must be called with the global ActivityManagerService lock held.
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 315014c1b248..66cb674f0acd 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -597,4 +597,9 @@ public abstract class WindowManagerInternal {
* @return The corresponding {@link WindowState#getName()}
*/
public abstract @Nullable String getImeTargetNameForLogging(int displayId);
+
+ /**
+ * Moves the {@link WindowToken} {@code binder} to the display specified by {@code displayId}.
+ */
+ public abstract void moveWindowTokenToDisplay(IBinder binder, int displayId);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 19cfcb21c8ac..223aa1e9be39 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -120,6 +120,7 @@ import static com.android.server.wm.WindowManagerServiceDumpProto.DISPLAY_FROZEN
import static com.android.server.wm.WindowManagerServiceDumpProto.FOCUSED_APP;
import static com.android.server.wm.WindowManagerServiceDumpProto.FOCUSED_DISPLAY_ID;
import static com.android.server.wm.WindowManagerServiceDumpProto.FOCUSED_WINDOW;
+import static com.android.server.wm.WindowManagerServiceDumpProto.HARD_KEYBOARD_AVAILABLE;
import static com.android.server.wm.WindowManagerServiceDumpProto.INPUT_METHOD_WINDOW;
import static com.android.server.wm.WindowManagerServiceDumpProto.LAST_ORIENTATION;
import static com.android.server.wm.WindowManagerServiceDumpProto.POLICY;
@@ -2013,7 +2014,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
void setTransparentRegionWindow(Session session, IWindow client, Region region) {
- long origId = Binder.clearCallingIdentity();
+ final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
WindowState w = windowForClientLocked(session, client, false);
@@ -2031,7 +2032,7 @@ public class WindowManagerService extends IWindowManager.Stub
void setInsetsWindow(Session session, IWindow client, int touchableInsets, Rect contentInsets,
Rect visibleInsets, Region touchableRegion) {
- long origId = Binder.clearCallingIdentity();
+ final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
WindowState w = windowForClientLocked(session, client, false);
@@ -2110,7 +2111,7 @@ public class WindowManagerService extends IWindowManager.Stub
boolean configChanged;
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
- long origId = Binder.clearCallingIdentity();
+ final long origId = Binder.clearCallingIdentity();
synchronized (mGlobalLock) {
final WindowState win = windowForClientLocked(session, client, false);
if (win == null) {
@@ -2723,6 +2724,32 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ /** @see WindowManagerInternal#moveWindowTokenToDisplay(IBinder, int) */
+ public void moveWindowTokenToDisplay(IBinder binder, int displayId) {
+ synchronized (mGlobalLock) {
+ final DisplayContent dc = mRoot.getDisplayContentOrCreate(displayId);
+ if (dc == null) {
+ ProtoLog.w(WM_ERROR, "moveWindowTokenToDisplay: Attempted to move token: %s"
+ + " to non-exiting displayId=%d", binder, displayId);
+ return;
+ }
+ final WindowToken token = mRoot.getWindowToken(binder);
+ if (token == null) {
+ ProtoLog.w(WM_ERROR,
+ "moveWindowTokenToDisplay: Attempted to move non-existing token: %s",
+ binder);
+ return;
+ }
+ if (token.getDisplayContent() == dc) {
+ ProtoLog.w(WM_ERROR,
+ "moveWindowTokenToDisplay: Cannot move to the original display "
+ + "for token: %s", binder);
+ return;
+ }
+ dc.reParentWindowToken(token);
+ }
+ }
+
void setNewDisplayOverrideConfiguration(Configuration overrideConfig,
@NonNull DisplayContent dc) {
if (dc.mWaitingForConfig) {
@@ -3057,7 +3084,7 @@ public class WindowManagerService extends IWindowManager.Stub
throw new SecurityException("Requires INTERACT_ACROSS_USERS permission");
}
- long origId = Binder.clearCallingIdentity();
+ final long origId = Binder.clearCallingIdentity();
try {
return mPolicy.isKeyguardSecure(userId);
} finally {
@@ -3723,7 +3750,7 @@ public class WindowManagerService extends IWindowManager.Stub
+ "rotation constant.");
}
- long origId = Binder.clearCallingIdentity();
+ final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
final DisplayContent display = mRoot.getDisplayContent(displayId);
@@ -3758,7 +3785,7 @@ public class WindowManagerService extends IWindowManager.Stub
ProtoLog.v(WM_DEBUG_ORIENTATION, "thawRotation: mRotation=%d", getDefaultDisplayRotation());
- long origId = Binder.clearCallingIdentity();
+ final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
final DisplayContent display = mRoot.getDisplayContent(displayId);
@@ -3811,7 +3838,7 @@ public class WindowManagerService extends IWindowManager.Stub
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateRotation");
- long origId = Binder.clearCallingIdentity();
+ final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
@@ -4104,7 +4131,7 @@ public class WindowManagerService extends IWindowManager.Stub
throw new SecurityException("Must hold permission " + WRITE_SECURE_SETTINGS);
}
- long origId = Binder.clearCallingIdentity();
+ final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
mPolicy.setOverrideFoldedArea(area);
@@ -4118,7 +4145,7 @@ public class WindowManagerService extends IWindowManager.Stub
* Get the display folded area.
*/
@NonNull Rect getFoldedArea() {
- long origId = Binder.clearCallingIdentity();
+ final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
return mPolicy.getFoldedArea();
@@ -4135,7 +4162,7 @@ public class WindowManagerService extends IWindowManager.Stub
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Must hold permission " + MANAGE_ACTIVITY_STACKS);
}
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
mDisplayNotificationController.registerListener(listener);
} finally {
@@ -5974,6 +6001,7 @@ public class WindowManagerService extends IWindowManager.Stub
proto.write(ROTATION, defaultDisplayContent.getRotation());
proto.write(LAST_ORIENTATION, defaultDisplayContent.getLastOrientation());
proto.write(FOCUSED_DISPLAY_ID, topFocusedDisplayContent.getDisplayId());
+ proto.write(HARD_KEYBOARD_AVAILABLE, mHardKeyboardAvailable);
}
private void dumpWindowsLocked(PrintWriter pw, boolean dumpAll,
@@ -7355,6 +7383,11 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ @Override
+ public void moveWindowTokenToDisplay(IBinder binder, int displayId) {
+ WindowManagerService.this.moveWindowTokenToDisplay(binder, displayId);
+ }
+
// TODO(multi-display): currently only used by PWM to notify keyguard transitions as well
// forwarding it to SystemUI for synchronizing status and navigation bar animations.
@Override
@@ -7856,7 +7889,7 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public void syncInputTransactions() {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
waitForAnimationsToComplete();
@@ -8054,7 +8087,7 @@ public class WindowManagerService extends IWindowManager.Stub
public boolean isLayerTracing() {
mAtmInternal.enforceCallerIsRecentsOrHasPermission(android.Manifest.permission.DUMP,
"isLayerTracing");
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
Parcel data = null;
Parcel reply = null;
@@ -8087,7 +8120,7 @@ public class WindowManagerService extends IWindowManager.Stub
public void setLayerTracing(boolean enabled) {
mAtmInternal.enforceCallerIsRecentsOrHasPermission(android.Manifest.permission.DUMP,
"setLayerTracing");
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
Parcel data = null;
try {
@@ -8114,7 +8147,7 @@ public class WindowManagerService extends IWindowManager.Stub
public void setLayerTracingFlags(int flags) {
mAtmInternal.enforceCallerIsRecentsOrHasPermission(android.Manifest.permission.DUMP,
"setLayerTracingFlags");
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
Parcel data = null;
try {
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index f1641cdfcf67..0b200e2bd6d2 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -120,7 +120,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
public IBinder startTransition(int type, @Nullable IBinder transitionToken,
@Nullable WindowContainerTransaction t) {
enforceStackPermission("startTransition()");
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
Transition transition = Transition.fromBinder(transitionToken);
@@ -147,7 +147,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
@Nullable WindowContainerTransaction t,
@Nullable IWindowContainerTransactionCallback callback) {
enforceStackPermission("finishTransition()");
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
int syncId = -1;
@@ -176,7 +176,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
throw new IllegalArgumentException(
"Null transaction passed to applySyncTransaction");
}
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
int effects = 0;
@@ -589,7 +589,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
@Override
public void registerTransitionPlayer(ITransitionPlayer player) {
enforceStackPermission("registerTransitionPlayer()");
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
mTransitionController.registerTransitionPlayer(player);
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 4b8a398582f3..fb9bdf5f58d7 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -178,10 +178,14 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
// Whether this process has ever started a service with the BIND_INPUT_METHOD permission.
private volatile boolean mHasImeService;
+ /** Whether {@link #mActivities} is not empty. */
+ private volatile boolean mHasActivities;
/** All activities running in the process (exclude destroying). */
private final ArrayList<ActivityRecord> mActivities = new ArrayList<>();
/** The activities will be removed but still belong to this process. */
private ArrayList<ActivityRecord> mInactiveActivities;
+ /** Whether {@link #mRecentTasks} is not empty. */
+ private volatile boolean mHasRecentTasks;
// any tasks this process had run root activities in
private final ArrayList<Task> mRecentTasks = new ArrayList<>();
// The most recent top-most activity that was resumed in the process for pre-Q app.
@@ -225,7 +229,8 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
private final OomScoreReferenceState mOomRefState;
public WindowProcessController(@NonNull ActivityTaskManagerService atm, ApplicationInfo info,
- String name, int uid, int userId, Object owner, WindowProcessListener listener) {
+ String name, int uid, int userId, Object owner,
+ @NonNull WindowProcessListener listener) {
mInfo = info;
mName = name;
mUid = uid;
@@ -386,7 +391,6 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
void postPendingUiCleanMsg(boolean pendingUiClean) {
- if (mListener == null) return;
// Posting on handler so WM lock isn't held when we call into AM.
final Message m = PooledLambda.obtainMessage(
WindowProcessListener::setPendingUiClean, mListener, pendingUiClean);
@@ -646,6 +650,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
return;
}
mActivities.add(r);
+ mHasActivities = true;
if (mInactiveActivities != null) {
mInactiveActivities.remove(r);
}
@@ -674,20 +679,20 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
mInactiveActivities.remove(r);
}
mActivities.remove(r);
+ mHasActivities = !mActivities.isEmpty();
updateActivityConfigurationListener();
}
void clearActivities() {
mInactiveActivities = null;
mActivities.clear();
+ mHasActivities = false;
updateActivityConfigurationListener();
}
@HotPath(caller = HotPath.OOM_ADJUSTMENT)
public boolean hasActivities() {
- synchronized (mAtm.mGlobalLockWithoutBoost) {
- return !mActivities.isEmpty();
- }
+ return mHasActivities;
}
@HotPath(caller = HotPath.OOM_ADJUSTMENT)
@@ -697,9 +702,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
@HotPath(caller = HotPath.LRU_UPDATE)
public boolean hasActivitiesOrRecentTasks() {
- synchronized (mAtm.mGlobalLockWithoutBoost) {
- return !mActivities.isEmpty() || !mRecentTasks.isEmpty();
- }
+ return mHasActivities || mHasRecentTasks;
}
private boolean hasActivityInVisibleTask() {
@@ -1147,7 +1150,6 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
void clearProfilerIfNeeded() {
- if (mListener == null) return;
// Posting on handler so WM lock isn't held when we call into AM.
mAtm.mH.sendMessage(PooledLambda.obtainMessage(
WindowProcessListener::clearProfilerIfNeeded, mListener));
@@ -1155,7 +1157,6 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
void updateProcessInfo(boolean updateServiceConnectionActivities, boolean activityChange,
boolean updateOomAdj, boolean addPendingTopUid) {
- if (mListener == null) return;
if (addPendingTopUid) {
mAtm.mAmInternal.addPendingTopUid(mUid, mPid);
}
@@ -1169,14 +1170,12 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
void updateServiceConnectionActivities() {
- if (mListener == null) return;
// Posting on handler so WM lock isn't held when we call into AM.
mAtm.mH.sendMessage(PooledLambda.obtainMessage(
WindowProcessListener::updateServiceConnectionActivities, mListener));
}
void setPendingUiCleanAndForceProcessStateUpTo(int newState) {
- if (mListener == null) return;
// Posting on handler so WM lock isn't held when we call into AM.
final Message m = PooledLambda.obtainMessage(
WindowProcessListener::setPendingUiCleanAndForceProcessStateUpTo,
@@ -1185,7 +1184,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
boolean isRemoved() {
- return mListener == null ? false : mListener.isRemoved();
+ return mListener.isRemoved();
}
private boolean shouldSetProfileProc() {
@@ -1210,7 +1209,6 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
void onStartActivity(int topProcessState, ActivityInfo info) {
- if (mListener == null) return;
String packageName = null;
if ((info.flags & ActivityInfo.FLAG_MULTIPROCESS) == 0
|| !"android".equals(info.packageName)) {
@@ -1234,7 +1232,6 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
void appDied(String reason) {
- if (mListener == null) return;
// Posting on handler so WM lock isn't held when we call into AM.
final Message m = PooledLambda.obtainMessage(
WindowProcessListener::appDied, mListener, reason);
@@ -1400,17 +1397,6 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
return;
}
- if (mListener.isCached()) {
- // This process is in a cached state. We will delay delivering the config change to the
- // process until the process is no longer cached.
- mHasPendingConfigurationChange = true;
- return;
- }
-
- dispatchConfigurationChange(config);
- }
-
- private void dispatchConfigurationChange(Configuration config) {
if (mPauseConfigurationDispatchCount > 0) {
mHasPendingConfigurationChange = true;
return;
@@ -1475,22 +1461,22 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
/** Returns the total time (in milliseconds) spent executing in both user and system code. */
public long getCpuTime() {
- return (mListener != null) ? mListener.getCpuTime() : 0;
+ return mListener.getCpuTime();
}
void addRecentTask(Task task) {
mRecentTasks.add(task);
+ mHasRecentTasks = true;
}
void removeRecentTask(Task task) {
mRecentTasks.remove(task);
+ mHasRecentTasks = !mRecentTasks.isEmpty();
}
@HotPath(caller = HotPath.OOM_ADJUSTMENT)
public boolean hasRecentTasks() {
- synchronized (mAtm.mGlobalLockWithoutBoost) {
- return !mRecentTasks.isEmpty();
- }
+ return mHasRecentTasks;
}
void clearRecentTasks() {
@@ -1498,6 +1484,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
mRecentTasks.get(i).clearRootProcess();
}
mRecentTasks.clear();
+ mHasRecentTasks = false;
}
public void appEarlyNotResponding(String annotation, Runnable killAppCallback) {
@@ -1556,22 +1543,6 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
/**
- * Called to notify WindowProcessController of a change in the process's cached state.
- *
- * @param isCached whether or not the process is cached.
- */
- @HotPath(caller = HotPath.OOM_ADJUSTMENT)
- public void onProcCachedStateChanged(boolean isCached) {
- if (!isCached) {
- synchronized (mAtm.mGlobalLockWithoutBoost) {
- if (mHasPendingConfigurationChange) {
- dispatchConfigurationChange(getConfiguration());
- }
- }
- }
- }
-
- /**
* Called to notify {@link WindowProcessController} of a started service.
*
* @param serviceInfo information describing the started service.
@@ -1602,23 +1573,28 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
@HotPath(caller = HotPath.OOM_ADJUSTMENT)
public void onTopProcChanged() {
- synchronized (mAtm.mGlobalLockWithoutBoost) {
- mAtm.mVrController.onTopProcChangedLocked(this);
+ if (mAtm.mVrController.isInterestingToSchedGroup()) {
+ mAtm.mH.post(() -> {
+ synchronized (mAtm.mGlobalLock) {
+ mAtm.mVrController.onTopProcChangedLocked(this);
+ }
+ });
}
}
@HotPath(caller = HotPath.OOM_ADJUSTMENT)
public boolean isHomeProcess() {
- synchronized (mAtm.mGlobalLockWithoutBoost) {
- return this == mAtm.mHomeProcess;
- }
+ return this == mAtm.mHomeProcess;
}
@HotPath(caller = HotPath.OOM_ADJUSTMENT)
public boolean isPreviousProcess() {
- synchronized (mAtm.mGlobalLockWithoutBoost) {
- return this == mAtm.mPreviousProcess;
- }
+ return this == mAtm.mPreviousProcess;
+ }
+
+ @HotPath(caller = HotPath.OOM_ADJUSTMENT)
+ public boolean isHeavyWeightProcess() {
+ return this == mAtm.mHeavyWeightProcess;
}
void setRunningRecentsAnimation(boolean running) {
@@ -1687,8 +1663,6 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
}
void dumpDebug(ProtoOutputStream proto, long fieldId) {
- if (mListener != null) {
- mListener.dumpDebug(proto, fieldId);
- }
+ mListener.dumpDebug(proto, fieldId);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 5defe478c49a..0b53bf6ca8f6 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -5337,7 +5337,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// Send information to SufaceFlinger about the priority of the current window.
updateFrameRateSelectionPriorityIfNeeded();
- mWinAnimator.prepareSurfaceLocked(true);
+ mWinAnimator.prepareSurfaceLocked(SurfaceControl.getGlobalTransaction(), true);
notifyBlastSyncTransaction();
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 13d8dc4c6be1..f3429769893f 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -652,7 +652,7 @@ class WindowStateAnimator {
return true;
}
- void setSurfaceBoundariesLocked(final boolean recoveringMemory) {
+ void setSurfaceBoundariesLocked(SurfaceControl.Transaction t, final boolean recoveringMemory) {
if (mSurfaceController == null) {
return;
}
@@ -662,11 +662,11 @@ class WindowStateAnimator {
final Task task = w.getTask();
if (shouldConsumeMainWindowSizeTransaction()) {
- task.getMainWindowSizeChangeTask().getSurfaceControl().deferTransactionUntil(
- mWin.getClientViewRootSurface(), mWin.getFrameNumber());
- mSurfaceController.deferTransactionUntil(mWin.getClientViewRootSurface(),
- mWin.getFrameNumber());
- SurfaceControl.mergeToGlobalTransaction(task.getMainWindowSizeChangeTransaction());
+ t.deferTransactionUntil(task.getMainWindowSizeChangeTask().getSurfaceControl(),
+ mWin.getClientViewRootSurface(), mWin.getFrameNumber());
+ t.deferTransactionUntil(mSurfaceController.mSurfaceControl,
+ mWin.getClientViewRootSurface(), mWin.getFrameNumber());
+ t.merge(task.getMainWindowSizeChangeTransaction());
task.setMainWindowSizeChangeTransaction(null);
}
@@ -691,8 +691,8 @@ class WindowStateAnimator {
// the WS position is reset (so the stack position is shown) at the same
// time that the buffer size changes.
setOffsetPositionForStackResize(false);
- mSurfaceController.deferTransactionUntil(mWin.getClientViewRootSurface(),
- mWin.getFrameNumber());
+ t.deferTransactionUntil(mSurfaceController.mSurfaceControl,
+ mWin.getClientViewRootSurface(), mWin.getFrameNumber());
} else {
final Task stack = mWin.getRootTask();
mTmpPos.x = 0;
@@ -705,9 +705,9 @@ class WindowStateAnimator {
}
}
if (!mIsWallpaper) {
- mSurfaceController.setPositionInTransaction(xOffset, yOffset, recoveringMemory);
+ mSurfaceController.setPosition(t, xOffset, yOffset, recoveringMemory);
} else {
- setWallpaperPositionAndScale(
+ setWallpaperPositionAndScale(t,
xOffset, yOffset, mWallpaperScale, recoveringMemory);
}
}
@@ -716,7 +716,7 @@ class WindowStateAnimator {
// Wallpaper is already updated above when calling setWallpaperPositionAndScale so
// we only need to consider the non-wallpaper case here.
if (!mIsWallpaper) {
- mSurfaceController.setMatrixInTransaction(
+ mSurfaceController.setMatrix(t,
mDsDx * w.mHScale,
mDtDx * w.mVScale,
mDtDy * w.mHScale,
@@ -738,7 +738,7 @@ class WindowStateAnimator {
}
}
- void prepareSurfaceLocked(final boolean recoveringMemory) {
+ void prepareSurfaceLocked(SurfaceControl.Transaction t, final boolean recoveringMemory) {
final WindowState w = mWin;
if (!hasSurface()) {
@@ -755,7 +755,7 @@ class WindowStateAnimator {
computeShownFrameLocked();
- setSurfaceBoundariesLocked(recoveringMemory);
+ setSurfaceBoundariesLocked(t, recoveringMemory);
if (mIsWallpaper && !w.mWallpaperVisible) {
// Wallpaper is no longer visible and there is no wp target => hide it.
@@ -797,7 +797,7 @@ class WindowStateAnimator {
boolean prepared = true;
if (mIsWallpaper) {
- setWallpaperPositionAndScale(
+ setWallpaperPositionAndScale(t,
mXOffset, mYOffset, mWallpaperScale, recoveringMemory);
} else {
prepared =
@@ -884,7 +884,8 @@ class WindowStateAnimator {
Slog.i(TAG, ">>> OPEN TRANSACTION setWallpaperOffset");
}
mService.openSurfaceTransaction();
- setWallpaperPositionAndScale(dx, dy, scale, false);
+ setWallpaperPositionAndScale(SurfaceControl.getGlobalTransaction(),
+ dx, dy, scale, false);
} catch (RuntimeException e) {
Slog.w(TAG, "Error positioning surface of " + mWin
+ " pos=(" + dx + "," + dy + ")", e);
@@ -899,8 +900,8 @@ class WindowStateAnimator {
return true;
}
- private void setWallpaperPositionAndScale(int dx, int dy, float scale,
- boolean recoveringMemory) {
+ private void setWallpaperPositionAndScale(SurfaceControl.Transaction t,
+ int dx, int dy, float scale, boolean recoveringMemory) {
DisplayInfo displayInfo = mWin.getDisplayInfo();
Matrix matrix = mWin.mTmpMatrix;
matrix.setTranslate(dx, dy);
@@ -909,9 +910,9 @@ class WindowStateAnimator {
matrix.getValues(mWin.mTmpMatrixArray);
matrix.reset();
- mSurfaceController.setPositionInTransaction(mWin.mTmpMatrixArray[MTRANS_X],
+ mSurfaceController.setPosition(t,mWin.mTmpMatrixArray[MTRANS_X],
mWin.mTmpMatrixArray[MTRANS_Y], recoveringMemory);
- mSurfaceController.setMatrixInTransaction(
+ mSurfaceController.setMatrix(t,
mDsDx * mWin.mTmpMatrixArray[MSCALE_X] * mWin.mHScale,
mDtDx * mWin.mTmpMatrixArray[MSKEW_Y] * mWin.mVScale,
mDtDy * mWin.mTmpMatrixArray[MSKEW_X] * mWin.mHScale,
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 9b40822c8ab5..160ad89b71f4 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -236,10 +236,6 @@ class WindowSurfaceController {
}
}
- void setPositionInTransaction(float left, float top, boolean recoveringMemory) {
- setPosition(null, left, top, recoveringMemory);
- }
-
void setPosition(SurfaceControl.Transaction t, float left, float top,
boolean recoveringMemory) {
final boolean surfaceMoved = mSurfaceX != left || mSurfaceY != top;
@@ -251,11 +247,7 @@ class WindowSurfaceController {
ProtoLog.i(WM_SHOW_TRANSACTIONS,
"SURFACE POS (setPositionInTransaction) @ (%f,%f): %s", left, top, title);
- if (t == null) {
- mSurfaceControl.setPosition(left, top);
- } else {
- t.setPosition(mSurfaceControl, left, top);
- }
+ t.setPosition(mSurfaceControl, left, top);
} catch (RuntimeException e) {
Slog.w(TAG, "Error positioning surface of " + this
+ " pos=(" + left + "," + top + ")", e);
@@ -266,11 +258,6 @@ class WindowSurfaceController {
}
}
- void setMatrixInTransaction(float dsdx, float dtdx, float dtdy, float dsdy,
- boolean recoveringMemory) {
- setMatrix(null, dsdx, dtdx, dtdy, dsdy, false);
- }
-
void setMatrix(SurfaceControl.Transaction t, float dsdx, float dtdx,
float dtdy, float dsdy, boolean recoveringMemory) {
final boolean matrixChanged = mLastDsdx != dsdx || mLastDtdx != dtdx ||
@@ -287,11 +274,7 @@ class WindowSurfaceController {
try {
ProtoLog.i(WM_SHOW_TRANSACTIONS, "SURFACE MATRIX [%f,%f,%f,%f]: %s",
dsdx, dtdx, dtdy, dsdy, title);
- if (t == null) {
- mSurfaceControl.setMatrix(dsdx, dtdx, dtdy, dsdy);
- } else {
- t.setMatrix(mSurfaceControl, dsdx, dtdx, dtdy, dsdy);
- }
+ t.setMatrix(mSurfaceControl, dsdx, dtdx, dtdy, dsdy);
} catch (RuntimeException e) {
// If something goes wrong with the surface (such
// as running out of memory), don't take down the
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index d14780e59ab1..4413dc3df6bb 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -74,6 +74,9 @@
using android::base::ParseUint;
using android::base::StringPrintf;
+using android::os::BlockUntrustedTouchesMode;
+using android::os::InputEventInjectionResult;
+using android::os::InputEventInjectionSync;
// Maximum allowable delay value in a vibration pattern before
// which the delay will be truncated.
@@ -1473,17 +1476,20 @@ static jint nativeInjectInputEvent(JNIEnv* env, jclass /* clazz */,
jint syncMode, jint timeoutMillis, jint policyFlags) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+ // static_cast is safe because the value was already checked at the Java layer
+ InputEventInjectionSync mode = static_cast<InputEventInjectionSync>(syncMode);
+
if (env->IsInstanceOf(inputEventObj, gKeyEventClassInfo.clazz)) {
KeyEvent keyEvent;
status_t status = android_view_KeyEvent_toNative(env, inputEventObj, & keyEvent);
if (status) {
jniThrowRuntimeException(env, "Could not read contents of KeyEvent object.");
- return INPUT_EVENT_INJECTION_FAILED;
+ return static_cast<jint>(InputEventInjectionResult::FAILED);
}
- const int32_t result =
+ const InputEventInjectionResult result =
im->getInputManager()->getDispatcher()->injectInputEvent(&keyEvent, injectorPid,
- injectorUid, syncMode,
+ injectorUid, mode,
std::chrono::milliseconds(
timeoutMillis),
uint32_t(policyFlags));
@@ -1492,19 +1498,19 @@ static jint nativeInjectInputEvent(JNIEnv* env, jclass /* clazz */,
const MotionEvent* motionEvent = android_view_MotionEvent_getNativePtr(env, inputEventObj);
if (!motionEvent) {
jniThrowRuntimeException(env, "Could not read contents of MotionEvent object.");
- return INPUT_EVENT_INJECTION_FAILED;
+ return static_cast<jint>(InputEventInjectionResult::FAILED);
}
- const int32_t result =
- (jint)im->getInputManager()
- ->getDispatcher()
- ->injectInputEvent(motionEvent, injectorPid, injectorUid, syncMode,
- std::chrono::milliseconds(timeoutMillis),
- uint32_t(policyFlags));
+ const InputEventInjectionResult result =
+ im->getInputManager()->getDispatcher()->injectInputEvent(motionEvent, injectorPid,
+ injectorUid, mode,
+ std::chrono::milliseconds(
+ timeoutMillis),
+ uint32_t(policyFlags));
return static_cast<jint>(result);
} else {
jniThrowRuntimeException(env, "Invalid input event type.");
- return INPUT_EVENT_INJECTION_FAILED;
+ return static_cast<jint>(InputEventInjectionResult::FAILED);
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 5f6ac10bee40..b7d94c17e45c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1124,7 +1124,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
boolean storageManagerIsNonDefaultBlockEncrypted() {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
return StorageManager.isNonDefaultBlockEncrypted();
} finally {
@@ -1148,10 +1148,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return mContext.getSystemService(WifiManager.class);
}
+ @SuppressWarnings("AndroidFrameworkBinderIdentity")
long binderClearCallingIdentity() {
return Binder.clearCallingIdentity();
}
+ @SuppressWarnings("AndroidFrameworkBinderIdentity")
void binderRestoreCallingIdentity(long token) {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index eca9f1556d43..177cb1aaaddd 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -107,6 +107,7 @@ import com.android.server.connectivity.IpConnectivityMetrics;
import com.android.server.contentcapture.ContentCaptureManagerInternal;
import com.android.server.coverage.CoverageService;
import com.android.server.devicepolicy.DevicePolicyManagerService;
+import com.android.server.devicestate.DeviceStateManagerService;
import com.android.server.display.DisplayManagerService;
import com.android.server.display.color.ColorDisplayService;
import com.android.server.dreams.DreamManagerService;
@@ -1254,6 +1255,10 @@ public final class SystemServer {
mSystemServiceManager.startService(AppIntegrityManagerService.class);
t.traceEnd();
+ t.traceBegin("DeviceStateManagerService");
+ mSystemServiceManager.startService(DeviceStateManagerService.class);
+ t.traceEnd();
+
} catch (Throwable e) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting core service");
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index 2cfdf3fd4f6f..47505a398a6f 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -667,7 +667,7 @@ public class MidiService extends IMidiManager.Stub {
}
// clear calling identity so bindService does not fail
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
client.addDeviceConnection(device, callback);
} finally {
@@ -692,7 +692,7 @@ public class MidiService extends IMidiManager.Stub {
}
// clear calling identity so bindService does not fail
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
client.addDeviceConnection(device, callback);
} finally {
diff --git a/services/net/java/android/net/ip/IpClientManager.java b/services/net/java/android/net/ip/IpClientManager.java
index db464e732e91..94bc1ecdc40c 100644
--- a/services/net/java/android/net/ip/IpClientManager.java
+++ b/services/net/java/android/net/ip/IpClientManager.java
@@ -87,6 +87,8 @@ public class IpClientManager {
} catch (RemoteException e) {
log("Error confirming IpClient configuration", e);
return false;
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
}
diff --git a/services/restrictions/java/com/android/server/restrictions/RestrictionsManagerService.java b/services/restrictions/java/com/android/server/restrictions/RestrictionsManagerService.java
index 946d28ee3210..62dbd89c48cb 100644
--- a/services/restrictions/java/com/android/server/restrictions/RestrictionsManagerService.java
+++ b/services/restrictions/java/com/android/server/restrictions/RestrictionsManagerService.java
@@ -76,7 +76,7 @@ public final class RestrictionsManagerService extends SystemService {
public boolean hasRestrictionsProvider() throws RemoteException {
int userHandle = UserHandle.getCallingUserId();
if (mDpm != null) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
return mDpm.getRestrictionsProvider(userHandle) != null;
} finally {
@@ -97,7 +97,7 @@ public final class RestrictionsManagerService extends SystemService {
int callingUid = Binder.getCallingUid();
int userHandle = UserHandle.getUserId(callingUid);
if (mDpm != null) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
ComponentName restrictionsProvider =
mDpm.getRestrictionsProvider(userHandle);
@@ -130,7 +130,7 @@ public final class RestrictionsManagerService extends SystemService {
}
final int userHandle = UserHandle.getCallingUserId();
if (mDpm != null) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
ComponentName restrictionsProvider =
mDpm.getRestrictionsProvider(userHandle);
@@ -163,7 +163,7 @@ public final class RestrictionsManagerService extends SystemService {
int callingUid = Binder.getCallingUid();
int userHandle = UserHandle.getUserId(callingUid);
if (mDpm != null) {
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
ComponentName permProvider = mDpm.getRestrictionsProvider(userHandle);
if (permProvider == null) {
diff --git a/services/robotests/backup/src/com/android/server/backup/BackupAgentTimeoutParametersTest.java b/services/robotests/backup/src/com/android/server/backup/BackupAgentTimeoutParametersTest.java
index 5b226f36d565..f58e295b4957 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupAgentTimeoutParametersTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupAgentTimeoutParametersTest.java
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertEquals;
import android.content.ContentResolver;
import android.content.Context;
import android.os.Handler;
+import android.os.Process;
import android.platform.test.annotations.Presubmit;
import android.provider.Settings;
@@ -64,7 +65,7 @@ public class BackupAgentTimeoutParametersTest {
long kvBackupAgentTimeoutMillis = mParameters.getKvBackupAgentTimeoutMillis();
long fullBackupAgentTimeoutMillis = mParameters.getFullBackupAgentTimeoutMillis();
long sharedBackupAgentTimeoutMillis = mParameters.getSharedBackupAgentTimeoutMillis();
- long restoreAgentTimeoutMillis = mParameters.getRestoreAgentTimeoutMillis();
+ long restoreSessionTimeoutMillis = mParameters.getRestoreSessionTimeoutMillis();
long restoreAgentFinishedTimeoutMillis = mParameters.getRestoreAgentFinishedTimeoutMillis();
assertEquals(
@@ -77,14 +78,41 @@ public class BackupAgentTimeoutParametersTest {
BackupAgentTimeoutParameters.DEFAULT_SHARED_BACKUP_AGENT_TIMEOUT_MILLIS,
sharedBackupAgentTimeoutMillis);
assertEquals(
- BackupAgentTimeoutParameters.DEFAULT_RESTORE_AGENT_TIMEOUT_MILLIS,
- restoreAgentTimeoutMillis);
+ BackupAgentTimeoutParameters.DEFAULT_RESTORE_SESSION_TIMEOUT_MILLIS,
+ restoreSessionTimeoutMillis);
assertEquals(
BackupAgentTimeoutParameters.DEFAULT_RESTORE_AGENT_FINISHED_TIMEOUT_MILLIS,
restoreAgentFinishedTimeoutMillis);
}
@Test
+ public void
+ testGetRestoreAgentTimeout_afterConstructorWithStartForSystemAgent_returnsDefaultValue() {
+ mParameters.start();
+
+ // Numbers before FIRST_APPLICATION_UID are reserved as UIDs for system components.
+ long restoreTimeout =
+ mParameters.getRestoreAgentTimeoutMillis(Process.FIRST_APPLICATION_UID - 1);
+
+ assertThat(restoreTimeout)
+ .isEqualTo(
+ BackupAgentTimeoutParameters.DEFAULT_RESTORE_SYSTEM_AGENT_TIMEOUT_MILLIS);
+ }
+
+ @Test
+ public void
+ testGetRestoreAgentTimeout_afterConstructorWithStartForAppAgent_returnsDefaultValue() {
+ mParameters.start();
+
+ // Numbers starting from FIRST_APPLICATION_UID are reserved for app UIDs.
+ long restoreTimeout =
+ mParameters.getRestoreAgentTimeoutMillis(Process.FIRST_APPLICATION_UID);
+
+ assertThat(restoreTimeout)
+ .isEqualTo(BackupAgentTimeoutParameters.DEFAULT_RESTORE_AGENT_TIMEOUT_MILLIS);
+ }
+
+ @Test
public void testGetQuotaExceededTimeoutMillis_returnsDefaultValue() {
mParameters.start();
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index a250c217614d..d032dbd5f47f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -457,12 +457,12 @@ public class MockingOomAdjusterTests {
public void testUpdateOomAdj_DoOne_HeavyWeight() {
ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
- doReturn(true).when(sService.mAtmInternal).isHeavyWeightProcess(any(
- WindowProcessController.class));
+ doReturn(mock(WindowProcessController.class)).when(app).getWindowProcessController();
+ WindowProcessController wpc = app.getWindowProcessController();
+ doReturn(true).when(wpc).isHeavyWeightProcess();
sService.mWakefulness = PowerManagerInternal.WAKEFULNESS_AWAKE;
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
- doReturn(false).when(sService.mAtmInternal).isHeavyWeightProcess(any(
- WindowProcessController.class));
+ doReturn(false).when(wpc).isHeavyWeightProcess();
assertProcStates(app, PROCESS_STATE_HEAVY_WEIGHT, HEAVY_WEIGHT_APP_ADJ,
SCHED_GROUP_BACKGROUND);
diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
index 8d4f2aa69d68..8d60de9abe99 100644
--- a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java
@@ -24,6 +24,7 @@ import static org.mockito.AdditionalMatchers.gt;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.intThat;
import static org.mockito.ArgumentMatchers.notNull;
@@ -36,11 +37,13 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
+import android.app.AppOpsManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.PackageManagerInternal;
import android.hardware.vibrator.IVibrator;
+import android.media.AudioAttributes;
import android.os.Handler;
import android.os.IBinder;
import android.os.IVibratorStateListener;
@@ -104,6 +107,7 @@ public class VibratorServiceTest {
@Mock private PowerManagerInternal mPowerManagerInternalMock;
@Mock private PowerSaveState mPowerSaveStateMock;
@Mock private Vibrator mVibratorMock;
+ @Mock private AppOpsManager mAppOpsManagerMock;
@Mock private VibratorService.NativeWrapper mNativeWrapperMock;
@Mock private IVibratorStateListener mVibratorStateListenerMock;
@Mock private IBinder mVibratorStateListenerBinderMock;
@@ -121,6 +125,7 @@ public class VibratorServiceTest {
when(mContextSpy.getContentResolver()).thenReturn(contentResolver);
when(mContextSpy.getSystemService(eq(Context.VIBRATOR_SERVICE))).thenReturn(mVibratorMock);
+ when(mContextSpy.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManagerMock);
when(mVibratorMock.getDefaultHapticFeedbackIntensity())
.thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
when(mVibratorMock.getDefaultNotificationVibrationIntensity())
@@ -133,6 +138,14 @@ public class VibratorServiceTest {
when(mPowerManagerInternalMock.getLowPowerState(PowerManager.ServiceType.VIBRATION))
.thenReturn(mPowerSaveStateMock);
+ setVibrationIntensityUserSetting(Settings.System.VIBRATE_WHEN_RINGING, 1);
+ setVibrationIntensityUserSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
+ Vibrator.VIBRATION_INTENSITY_MEDIUM);
+ setVibrationIntensityUserSetting(Settings.System.RING_VIBRATION_INTENSITY,
+ Vibrator.VIBRATION_INTENSITY_MEDIUM);
+ setVibrationIntensityUserSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY,
+ Vibrator.VIBRATION_INTENSITY_MEDIUM);
+
addLocalServiceMock(PackageManagerInternal.class, mPackageManagerInternalMock);
addLocalServiceMock(PowerManagerInternal.class, mPowerManagerInternalMock);
FakeSettingsProvider.clearSettingsProvider();
@@ -286,6 +299,55 @@ public class VibratorServiceTest {
}
@Test
+ public void vibrate_withAudioAttributes_usesOriginalAudioUsageInAppOpsManager() {
+ VibratorService service = createService();
+ service.systemReady();
+
+ VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
+ AudioAttributes audioAttributes = new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY).build();
+ VibrationAttributes vibrationAttributes = new VibrationAttributes.Builder(
+ audioAttributes, effect).build();
+
+ vibrate(service, effect, vibrationAttributes);
+
+ verify(mAppOpsManagerMock).checkAudioOpNoThrow(eq(AppOpsManager.OP_VIBRATE),
+ eq(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY), anyInt(), anyString());
+ }
+
+ @Test
+ public void vibrate_withVibrationAttributes_usesCorrespondingAudioUsageInAppOpsManager() {
+ VibratorService service = createService();
+ service.systemReady();
+
+ vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), ALARM_ATTRS);
+ vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_TICK), NOTIFICATION_ATTRS);
+ vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK), RINGTONE_ATTRS);
+ vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_TICK), HAPTIC_FEEDBACK_ATTRS);
+ vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_CLICK),
+ new VibrationAttributes.Builder().setUsage(
+ VibrationAttributes.USAGE_COMMUNICATION_REQUEST).build());
+ vibrate(service, VibrationEffect.get(VibrationEffect.EFFECT_TICK),
+ new VibrationAttributes.Builder().setUsage(
+ VibrationAttributes.USAGE_UNKNOWN).build());
+
+ InOrder inOrderVerifier = inOrder(mAppOpsManagerMock);
+ inOrderVerifier.verify(mAppOpsManagerMock).checkAudioOpNoThrow(eq(AppOpsManager.OP_VIBRATE),
+ eq(AudioAttributes.USAGE_ALARM), anyInt(), anyString());
+ inOrderVerifier.verify(mAppOpsManagerMock).checkAudioOpNoThrow(eq(AppOpsManager.OP_VIBRATE),
+ eq(AudioAttributes.USAGE_NOTIFICATION), anyInt(), anyString());
+ inOrderVerifier.verify(mAppOpsManagerMock).checkAudioOpNoThrow(eq(AppOpsManager.OP_VIBRATE),
+ eq(AudioAttributes.USAGE_NOTIFICATION_RINGTONE), anyInt(), anyString());
+ inOrderVerifier.verify(mAppOpsManagerMock).checkAudioOpNoThrow(eq(AppOpsManager.OP_VIBRATE),
+ eq(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION), anyInt(), anyString());
+ inOrderVerifier.verify(mAppOpsManagerMock).checkAudioOpNoThrow(eq(AppOpsManager.OP_VIBRATE),
+ eq(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST),
+ anyInt(), anyString());
+ inOrderVerifier.verify(mAppOpsManagerMock).checkAudioOpNoThrow(eq(AppOpsManager.OP_VIBRATE),
+ eq(AudioAttributes.USAGE_UNKNOWN), anyInt(), anyString());
+ }
+
+ @Test
public void vibrate_withOneShotAndAmplitudeControl_turnsVibratorOnAndSetsAmplitude() {
mockVibratorCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
VibratorService service = createService();
@@ -367,7 +429,7 @@ public class VibratorServiceTest {
// Wait for VibrateThread to turn vibrator ON with total timing and no callback.
Thread.sleep(5);
- verify(mNativeWrapperMock).vibratorOn(eq(30L), eq(0L));
+ verify(mNativeWrapperMock).vibratorOn(eq(30L), anyLong());
// First amplitude set right away.
verify(mNativeWrapperMock).vibratorSetAmplitude(eq(100));
@@ -434,8 +496,8 @@ public class VibratorServiceTest {
Thread.sleep(15);
InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
- inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(3L), eq(0L));
- inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(2L), eq(0L));
+ inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(3L), anyLong());
+ inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(2L), anyLong());
inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
}
@@ -637,6 +699,11 @@ public class VibratorServiceTest {
vibrate(service, effect, ALARM_ATTRS);
}
+ private void vibrate(VibratorService service, VibrationEffect effect, AudioAttributes attrs) {
+ VibrationAttributes attributes = new VibrationAttributes.Builder(attrs, effect).build();
+ vibrate(service, effect, attributes);
+ }
+
private void vibrate(VibratorService service, VibrationEffect effect,
VibrationAttributes attributes) {
service.vibrate(UID, PACKAGE_NAME, effect, attributes, "some reason", service);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
index 6acd9b6b3803..9ba9188dc580 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
@@ -16,6 +16,8 @@
package com.android.server.accessibility.magnification;
+import static com.android.server.accessibility.magnification.FullScreenMagnificationController.MagnificationRequestObserver;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
@@ -93,6 +95,10 @@ public class FullScreenMagnificationControllerTest {
final Context mMockContext = mock(Context.class);
final AccessibilityManagerService mMockAms = mock(AccessibilityManagerService.class);
final WindowManagerInternal mMockWindowManager = mock(WindowManagerInternal.class);
+ private final MagnificationAnimationCallback mAnimationCallback = mock(
+ MagnificationAnimationCallback.class);
+ private final MagnificationRequestObserver mRequestObserver = mock(
+ MagnificationRequestObserver.class);
final MessageCapturingHandler mMessageCapturingHandler = new MessageCapturingHandler(null);
ValueAnimator mMockValueAnimator;
@@ -100,12 +106,10 @@ public class FullScreenMagnificationControllerTest {
ValueAnimator.AnimatorListener mStateListener;
FullScreenMagnificationController mFullScreenMagnificationController;
- MagnificationAnimationCallback mAnimationCallback;
@Before
public void setUp() {
Looper looper = InstrumentationRegistry.getContext().getMainLooper();
- mAnimationCallback = Mockito.mock(MagnificationAnimationCallback.class);
// Pretending ID of the Thread associated with looper as main thread ID in controller
when(mMockContext.getMainLooper()).thenReturn(looper);
when(mMockControllerCtx.getContext()).thenReturn(mMockContext);
@@ -116,7 +120,7 @@ public class FullScreenMagnificationControllerTest {
initMockWindowManager();
mFullScreenMagnificationController = new FullScreenMagnificationController(
- mMockControllerCtx, new Object());
+ mMockControllerCtx, new Object(), mRequestObserver);
}
@After
@@ -345,6 +349,7 @@ public class FullScreenMagnificationControllerTest {
verify(mMockAms).notifyMagnificationChanged(displayId,
INITIAL_MAGNIFICATION_REGION, scale, newCenter.x, newCenter.y);
verify(mMockValueAnimator).start();
+ verify(mRequestObserver).onRequestMagnificationSpec(displayId, SERVICE_ID_1);
// Initial value
when(mMockValueAnimator.getAnimatedFraction()).thenReturn(0.0f);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
index 008cbed10d18..1cdd873860b8 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
@@ -53,6 +53,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.accessibility.EventStreamTransformation;
+import com.android.server.accessibility.magnification.FullScreenMagnificationController.MagnificationRequestObserver;
import com.android.server.accessibility.magnification.MagnificationGestureHandler.ScaleChangedListener;
import com.android.server.testutils.OffsettableClock;
import com.android.server.testutils.TestHandler;
@@ -126,6 +127,8 @@ public class FullScreenMagnificationGestureHandlerTest {
FullScreenMagnificationController mFullScreenMagnificationController;
@Mock
ScaleChangedListener mMockScaleChangedListener;
+ @Mock
+ MagnificationRequestObserver mMagnificationRequestObserver;
private OffsettableClock mClock;
private FullScreenMagnificationGestureHandler mMgh;
@@ -148,7 +151,7 @@ public class FullScreenMagnificationGestureHandlerTest {
when(mockController.getAnimationDuration()).thenReturn(1000L);
when(mockWindowManager.setMagnificationCallbacks(eq(DISPLAY_0), any())).thenReturn(true);
mFullScreenMagnificationController = new FullScreenMagnificationController(mockController,
- new Object()) {
+ new Object(), mMagnificationRequestObserver) {
@Override
public boolean magnificationRegionContains(int displayId, float x, float y) {
return true;
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
index 3e34f8a428db..e82ff344d4cc 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java
@@ -250,6 +250,17 @@ public class MagnificationControllerTest {
verify(mScreenMagnificationController).setUserId(CURRENT_USER_ID);
verify(mWindowMagnificationManager).setUserId(CURRENT_USER_ID);
}
+
+ @Test
+ public void onMagnificationRequest_windowMagnifying_disableWindow() throws RemoteException {
+ setMagnificationEnabled(MODE_WINDOW);
+
+ mMagnificationController.onRequestMagnificationSpec(TEST_DISPLAY, 1);
+ mMockConnection.invokeCallbacks();
+
+ assertFalse(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
+ }
+
private void setMagnificationEnabled(int mode) throws RemoteException {
setMagnificationEnabled(mode, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y);
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localbackend/converter/SchemaToProtoConverterTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localbackend/converter/SchemaToProtoConverterTest.java
new file mode 100644
index 000000000000..8b2fd1ce9fef
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localbackend/converter/SchemaToProtoConverterTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.appsearch.external.localbackend.converter;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.appsearch.AppSearchSchema;
+
+import com.android.server.appsearch.proto.IndexingConfig;
+import com.android.server.appsearch.proto.PropertyConfigProto;
+import com.android.server.appsearch.proto.SchemaTypeConfigProto;
+import com.android.server.appsearch.proto.TermMatchType;
+
+import org.junit.Test;
+
+public class SchemaToProtoConverterTest {
+ @Test
+ public void testGetProto_Email() {
+ AppSearchSchema emailSchema = new AppSearchSchema.Builder("Email")
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("subject")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).addProperty(new AppSearchSchema.PropertyConfig.Builder("body")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).build();
+
+ SchemaTypeConfigProto expectedEmailProto = SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("Email")
+ .addProperties(PropertyConfigProto.newBuilder()
+ .setPropertyName("subject")
+ .setDataType(PropertyConfigProto.DataType.Code.STRING)
+ .setSchemaType("")
+ .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
+ .setIndexingConfig(
+ com.android.server.appsearch.proto.IndexingConfig.newBuilder()
+ .setTokenizerType(IndexingConfig.TokenizerType.Code.PLAIN)
+ .setTermMatchType(TermMatchType.Code.PREFIX)
+ )
+ ).addProperties(PropertyConfigProto.newBuilder()
+ .setPropertyName("body")
+ .setDataType(PropertyConfigProto.DataType.Code.STRING)
+ .setSchemaType("")
+ .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
+ .setIndexingConfig(
+ com.android.server.appsearch.proto.IndexingConfig.newBuilder()
+ .setTokenizerType(IndexingConfig.TokenizerType.Code.PLAIN)
+ .setTermMatchType(TermMatchType.Code.PREFIX)
+ )
+ ).build();
+
+ assertThat(SchemaToProtoConverter.convert(emailSchema)).isEqualTo(expectedEmailProto);
+ }
+
+ @Test
+ public void testGetProto_MusicRecording() {
+ AppSearchSchema musicRecordingSchema = new AppSearchSchema.Builder("MusicRecording")
+ .addProperty(new AppSearchSchema.PropertyConfig.Builder("artist")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_STRING)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_REPEATED)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_PLAIN)
+ .build()
+ ).addProperty(new AppSearchSchema.PropertyConfig.Builder("pubDate")
+ .setDataType(AppSearchSchema.PropertyConfig.DATA_TYPE_INT64)
+ .setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
+ .setIndexingType(AppSearchSchema.PropertyConfig.INDEXING_TYPE_NONE)
+ .setTokenizerType(AppSearchSchema.PropertyConfig.TOKENIZER_TYPE_NONE)
+ .build()
+ ).build();
+
+ SchemaTypeConfigProto expectedMusicRecordingProto = SchemaTypeConfigProto.newBuilder()
+ .setSchemaType("MusicRecording")
+ .addProperties(PropertyConfigProto.newBuilder()
+ .setPropertyName("artist")
+ .setDataType(PropertyConfigProto.DataType.Code.STRING)
+ .setSchemaType("")
+ .setCardinality(PropertyConfigProto.Cardinality.Code.REPEATED)
+ .setIndexingConfig(
+ com.android.server.appsearch.proto.IndexingConfig.newBuilder()
+ .setTokenizerType(IndexingConfig.TokenizerType.Code.PLAIN)
+ .setTermMatchType(TermMatchType.Code.PREFIX)
+ )
+ ).addProperties(PropertyConfigProto.newBuilder()
+ .setPropertyName("pubDate")
+ .setDataType(PropertyConfigProto.DataType.Code.INT64)
+ .setSchemaType("")
+ .setCardinality(PropertyConfigProto.Cardinality.Code.OPTIONAL)
+ .setIndexingConfig(
+ com.android.server.appsearch.proto.IndexingConfig.newBuilder()
+ .setTokenizerType(IndexingConfig.TokenizerType.Code.NONE)
+ .setTermMatchType(TermMatchType.Code.UNKNOWN)
+ )
+ ).build();
+
+ assertThat(SchemaToProtoConverter.convert(musicRecordingSchema))
+ .isEqualTo(expectedMusicRecordingProto);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
index 922d71554426..dbaa482ff2ea 100644
--- a/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
@@ -20,6 +20,7 @@ import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE;
import static com.android.server.attention.AttentionManagerService.ATTENTION_CACHE_BUFFER_SIZE;
import static com.android.server.attention.AttentionManagerService.DEFAULT_STALE_AFTER_MILLIS;
+import static com.android.server.attention.AttentionManagerService.DEVICE_CONFIG_MAX_STALENESS_MILLIS;
import static com.android.server.attention.AttentionManagerService.KEY_STALE_AFTER_MILLIS;
import static com.google.common.truth.Truth.assertThat;
@@ -39,6 +40,7 @@ import android.os.IPowerManager;
import android.os.IThermalService;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.provider.DeviceConfig;
import android.service.attention.IAttentionCallback;
import android.service.attention.IAttentionService;
@@ -205,6 +207,38 @@ public class AttentionManagerServiceTest {
DEFAULT_STALE_AFTER_MILLIS);
}
+ @Test
+ public void testEnsureDeviceConfigCachedValuesFreshness_doesNotCallDeviceConfigTooFrequently() {
+ DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+ KEY_STALE_AFTER_MILLIS, String.valueOf(DEFAULT_STALE_AFTER_MILLIS), false);
+ assertThat(mSpyAttentionManager.getStaleAfterMillis()).isEqualTo(
+ DEFAULT_STALE_AFTER_MILLIS);
+
+ DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+ KEY_STALE_AFTER_MILLIS, "123", false);
+
+ // New value is ignored
+ assertThat(mSpyAttentionManager.getStaleAfterMillis()).isEqualTo(
+ DEFAULT_STALE_AFTER_MILLIS);
+ }
+
+
+ @Test
+ public void testEnsureDeviceConfigCachedValuesFreshness_refreshesWhenStale() {
+ DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+ KEY_STALE_AFTER_MILLIS, String.valueOf(DEFAULT_STALE_AFTER_MILLIS), false);
+ assertThat(mSpyAttentionManager.getStaleAfterMillis()).isEqualTo(
+ DEFAULT_STALE_AFTER_MILLIS);
+
+ DeviceConfig.setProperty(NAMESPACE_ATTENTION_MANAGER_SERVICE,
+ KEY_STALE_AFTER_MILLIS, "123", false);
+ mSpyAttentionManager.mLastReadDeviceConfigMillis =
+ SystemClock.elapsedRealtime() - (DEVICE_CONFIG_MAX_STALENESS_MILLIS + 1);
+
+ // Values are refreshed
+ assertThat(mSpyAttentionManager.getStaleAfterMillis()).isEqualTo(123);
+ }
+
private class MockIAttentionService implements IAttentionService {
public void checkAttention(IAttentionCallback callback) throws RemoteException {
callback.onSuccess(0, 0);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 09b6d7b0cd7e..cb49a519d10a 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -113,7 +113,7 @@ public class DpmMockContext extends MockContext {
}
public void withCleanCallingIdentity(@NonNull FunctionalUtils.ThrowingRunnable action) {
- long callingIdentity = clearCallingIdentity();
+ final long callingIdentity = clearCallingIdentity();
Throwable throwableToPropagate = null;
try {
action.runOrThrow();
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
new file mode 100644
index 000000000000..59d4e2ae6ae4
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.devicestate;
+
+import static com.android.server.devicestate.DeviceStateManagerService.INVALID_DEVICE_STATE;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertThrows;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Unit tests for {@link DeviceStateManagerService}.
+ * <p/>
+ * Run with <code>atest DeviceStateManagerServiceTest</code>.
+ */
+@RunWith(AndroidJUnit4.class)
+public final class DeviceStateManagerServiceTest {
+ private static final int DEFAULT_DEVICE_STATE = 0;
+ private static final int OTHER_DEVICE_STATE = 1;
+ private static final int UNSUPPORTED_DEVICE_STATE = 999;
+
+ private TestDeviceStatePolicy mPolicy;
+ private TestDeviceStateProvider mProvider;
+ private DeviceStateManagerService mService;
+
+ @Before
+ public void setup() {
+ mProvider = new TestDeviceStateProvider();
+ mPolicy = new TestDeviceStatePolicy(mProvider);
+ mService = new DeviceStateManagerService(InstrumentationRegistry.getContext(), mPolicy);
+ mService.onStart();
+ }
+
+ @Test
+ public void requestStateChange() {
+ assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getPendingState(), INVALID_DEVICE_STATE);
+ assertEquals(mService.getRequestedState(), DEFAULT_DEVICE_STATE);
+ assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), DEFAULT_DEVICE_STATE);
+
+ mProvider.notifyRequestState(OTHER_DEVICE_STATE);
+ assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
+ assertEquals(mService.getPendingState(), INVALID_DEVICE_STATE);
+ assertEquals(mService.getRequestedState(), OTHER_DEVICE_STATE);
+ assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), OTHER_DEVICE_STATE);
+ }
+
+ @Test
+ public void requestStateChange_pendingState() {
+ mPolicy.blockConfigure();
+
+ mProvider.notifyRequestState(OTHER_DEVICE_STATE);
+ assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getPendingState(), OTHER_DEVICE_STATE);
+ assertEquals(mService.getRequestedState(), OTHER_DEVICE_STATE);
+ assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), OTHER_DEVICE_STATE);
+
+ mProvider.notifyRequestState(DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getPendingState(), OTHER_DEVICE_STATE);
+ assertEquals(mService.getRequestedState(), DEFAULT_DEVICE_STATE);
+ assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), OTHER_DEVICE_STATE);
+
+ mPolicy.resumeConfigure();
+ assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getPendingState(), INVALID_DEVICE_STATE);
+ assertEquals(mService.getRequestedState(), DEFAULT_DEVICE_STATE);
+ assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), DEFAULT_DEVICE_STATE);
+ }
+
+ @Test
+ public void requestStateChange_unsupportedState() {
+ mProvider.notifyRequestState(UNSUPPORTED_DEVICE_STATE);
+ assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getPendingState(), INVALID_DEVICE_STATE);
+ assertEquals(mService.getRequestedState(), DEFAULT_DEVICE_STATE);
+ assertEquals(mPolicy.getMostRecentRequestedStateToConfigure(), DEFAULT_DEVICE_STATE);
+ }
+
+ @Test
+ public void requestStateChange_invalidState() {
+ assertThrows(IllegalArgumentException.class, () -> {
+ mProvider.notifyRequestState(INVALID_DEVICE_STATE);
+ });
+ }
+
+ @Test
+ public void supportedStatesChanged() {
+ assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getPendingState(), INVALID_DEVICE_STATE);
+ assertEquals(mService.getRequestedState(), DEFAULT_DEVICE_STATE);
+
+ mProvider.notifySupportedDeviceStates(new int []{ DEFAULT_DEVICE_STATE });
+
+ // The current committed and requests states do not change because the current state remains
+ // supported.
+ assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getPendingState(), INVALID_DEVICE_STATE);
+ assertEquals(mService.getRequestedState(), DEFAULT_DEVICE_STATE);
+ }
+
+ @Test
+ public void supportedStatesChanged_invalidState() {
+ assertThrows(IllegalArgumentException.class, () -> {
+ mProvider.notifySupportedDeviceStates(new int []{ INVALID_DEVICE_STATE });
+ });
+ }
+
+ @Test
+ public void supportedStatesChanged_unsupportedRequestedState() {
+ assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getPendingState(), INVALID_DEVICE_STATE);
+ assertEquals(mService.getRequestedState(), DEFAULT_DEVICE_STATE);
+
+ mProvider.notifySupportedDeviceStates(new int []{ OTHER_DEVICE_STATE });
+
+ // The current requested state is cleared because it is no longer supported.
+ assertEquals(mService.getCommittedState(), DEFAULT_DEVICE_STATE);
+ assertEquals(mService.getPendingState(), INVALID_DEVICE_STATE);
+ assertEquals(mService.getRequestedState(), INVALID_DEVICE_STATE);
+
+ mProvider.notifyRequestState(OTHER_DEVICE_STATE);
+
+ assertEquals(mService.getCommittedState(), OTHER_DEVICE_STATE);
+ assertEquals(mService.getPendingState(), INVALID_DEVICE_STATE);
+ assertEquals(mService.getRequestedState(), OTHER_DEVICE_STATE);
+ }
+
+ private static final class TestDeviceStatePolicy implements DeviceStatePolicy {
+ private final DeviceStateProvider mProvider;
+ private int mLastDeviceStateRequestedToConfigure = INVALID_DEVICE_STATE;
+ private boolean mConfigureBlocked = false;
+ private Runnable mPendingConfigureCompleteRunnable;
+
+ TestDeviceStatePolicy(DeviceStateProvider provider) {
+ mProvider = provider;
+ }
+
+ @Override
+ public DeviceStateProvider getDeviceStateProvider() {
+ return mProvider;
+ }
+
+ public void blockConfigure() {
+ mConfigureBlocked = true;
+ }
+
+ public void resumeConfigure() {
+ mConfigureBlocked = false;
+ if (mPendingConfigureCompleteRunnable != null) {
+ Runnable onComplete = mPendingConfigureCompleteRunnable;
+ mPendingConfigureCompleteRunnable = null;
+ onComplete.run();
+ }
+ }
+
+ public int getMostRecentRequestedStateToConfigure() {
+ return mLastDeviceStateRequestedToConfigure;
+ }
+
+ @Override
+ public void configureDeviceForState(int state, Runnable onComplete) {
+ if (mPendingConfigureCompleteRunnable != null) {
+ throw new IllegalStateException("configureDeviceForState() called while configure"
+ + " is pending");
+ }
+
+ mLastDeviceStateRequestedToConfigure = state;
+ if (mConfigureBlocked) {
+ mPendingConfigureCompleteRunnable = onComplete;
+ return;
+ }
+ onComplete.run();
+ }
+ }
+
+ private static final class TestDeviceStateProvider implements DeviceStateProvider {
+ private int[] mSupportedDeviceStates = new int[]{ DEFAULT_DEVICE_STATE,
+ OTHER_DEVICE_STATE };
+ private int mCurrentDeviceState = DEFAULT_DEVICE_STATE;
+ private Listener mListener;
+
+ @Override
+ public void setListener(Listener listener) {
+ if (mListener != null) {
+ throw new IllegalArgumentException("Provider already has listener set.");
+ }
+
+ mListener = listener;
+ mListener.onSupportedDeviceStatesChanged(mSupportedDeviceStates);
+ mListener.onStateChanged(mCurrentDeviceState);
+ }
+
+ public void notifySupportedDeviceStates(int[] supportedDeviceStates) {
+ mSupportedDeviceStates = supportedDeviceStates;
+ mListener.onSupportedDeviceStatesChanged(supportedDeviceStates);
+ }
+
+ public void notifyRequestState(int state) {
+ mCurrentDeviceState = state;
+ mListener.onStateChanged(state);
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index da25fd612463..13b019897600 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -343,7 +343,8 @@ public class DisplayManagerServiceTest {
displayDeviceInfo2.copyFrom(displayDeviceInfo);
displayDeviceInfo2.displayCutout = null;
displayDevice.setDisplayDeviceInfo(displayDeviceInfo2);
- displayManager.handleDisplayDeviceChanged(displayDevice);
+ displayManager.getDisplayDeviceRepository()
+ .onDisplayDeviceEvent(displayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED);
handler.runWithScissors(() -> {
}, 0 /* now */);
diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java
index b312e52ff74b..ac4501723c90 100644
--- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java
@@ -28,6 +28,9 @@ import android.view.SurfaceControl;
import org.junit.Before;
import org.junit.Test;
+import java.io.InputStream;
+import java.io.OutputStream;
+
public class LogicalDisplayTest {
private static final int DISPLAY_ID = 0;
private static final int LAYER_STACK = 0;
@@ -50,13 +53,21 @@ public class LogicalDisplayTest {
when(mDisplayDevice.getDisplayDeviceInfoLocked()).thenReturn(displayDeviceInfo);
DisplayDeviceRepository repo = new DisplayDeviceRepository(
- new DisplayManagerService.SyncRoot(), new DisplayDeviceRepository.Listener() {
+ new DisplayManagerService.SyncRoot(),
+ new PersistentDataStore(new PersistentDataStore.Injector() {
+ @Override
+ public InputStream openRead() {
+ return null;
+ }
+
@Override
- public void onDisplayDeviceEventLocked(DisplayDevice device, int event) {}
+ public OutputStream startWrite() {
+ return null;
+ }
@Override
- public void onTraversalRequested() {}
- });
+ public void finishWrite(OutputStream os, boolean success) {}
+ }));
repo.onDisplayDeviceEvent(mDisplayDevice, DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED);
mLogicalDisplay.updateLocked(repo);
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
index 0ccc02663dc5..2250185cf3d7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserInfoTest.java
@@ -17,6 +17,7 @@
package com.android.server.pm;
import static android.content.pm.UserInfo.FLAG_DEMO;
+import static android.content.pm.UserInfo.FLAG_DISABLED;
import static android.content.pm.UserInfo.FLAG_EPHEMERAL;
import static android.content.pm.UserInfo.FLAG_FULL;
import static android.content.pm.UserInfo.FLAG_GUEST;
@@ -166,6 +167,23 @@ public class UserManagerServiceUserInfoTest {
assertTrue(mUserManagerService.isUserOfType(testId, typeName));
}
+ /** Test UserInfo.supportsSwitchTo() for partial user. */
+ @Test
+ public void testSupportSwitchTo_partial() throws Exception {
+ UserInfo userInfo = createUser(100, FLAG_FULL, null);
+ userInfo.partial = true;
+ assertFalse("Switching to a partial user should be disabled",
+ userInfo.supportsSwitchTo());
+ }
+
+ /** Test UserInfo.supportsSwitchTo() for disabled user. */
+ @Test
+ public void testSupportSwitchTo_disabled() throws Exception {
+ UserInfo userInfo = createUser(100, FLAG_DISABLED, null);
+ assertFalse("Switching to a DISABLED user should be disabled",
+ userInfo.supportsSwitchTo());
+ }
+
/** Test UserInfo.supportsSwitchTo() for precreated users. */
@Test
public void testSupportSwitchTo_preCreated() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
index 4381bfdb0b56..af161ee8b818 100644
--- a/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/AttentionDetectorTest.java
@@ -39,7 +39,6 @@ import static org.mockito.Mockito.when;
import android.attention.AttentionManagerInternal;
import android.attention.AttentionManagerInternal.AttentionCallbackInternal;
-import android.content.pm.PackageManager;
import android.os.PowerManager;
import android.os.PowerManagerInternal;
import android.os.SystemClock;
@@ -64,8 +63,6 @@ public class AttentionDetectorTest extends AndroidTestCase {
private static final long DEFAULT_DIM_DURATION_MILLIS = 6_000L;
@Mock
- private PackageManager mPackageManager;
- @Mock
private AttentionManagerInternal mAttentionManagerInternal;
@Mock
private WindowManagerInternal mWindowManagerInternal;
@@ -80,9 +77,6 @@ public class AttentionDetectorTest extends AndroidTestCase {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- when(mPackageManager.getAttentionServicePackageName()).thenReturn("com.google.android.as");
- when(mPackageManager.checkPermission(any(), any())).thenReturn(
- PackageManager.PERMISSION_GRANTED);
when(mAttentionManagerInternal.checkAttention(anyLong(), any()))
.thenReturn(true);
when(mWindowManagerInternal.isKeyguardShowingAndNotOccluded()).thenReturn(false);
@@ -157,16 +151,6 @@ public class AttentionDetectorTest extends AndroidTestCase {
}
@Test
- public void testOnUserActivity_doesntCheckIfNotSufficientPermissions() {
- when(mPackageManager.checkPermission(any(), any())).thenReturn(
- PackageManager.PERMISSION_DENIED);
-
- long when = registerAttention();
- verify(mAttentionManagerInternal, never()).checkAttention(anyLong(), any());
- assertThat(mNextDimming).isEqualTo(when);
- }
-
- @Test
public void testOnUserActivity_doesntCrashIfNoAttentionService() {
mAttentionManagerInternal = null;
registerAttention();
@@ -452,7 +436,6 @@ public class AttentionDetectorTest extends AndroidTestCase {
super(AttentionDetectorTest.this.mOnUserAttention, new Object());
mAttentionManager = mAttentionManagerInternal;
mWindowManager = mWindowManagerInternal;
- mPackageManager = AttentionDetectorTest.this.mPackageManager;
mContentResolver = getContext().getContentResolver();
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index abcc14c6be93..9766cb546616 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -402,31 +402,33 @@ public class BuzzBeepBlinkTest extends UiServiceTestCase {
}
private void verifyNeverVibrate() {
- verify(mVibrator, never()).vibrate(anyInt(), anyString(), any(), anyString(), any());
+ verify(mVibrator, never()).vibrate(anyInt(), anyString(), any(), anyString(),
+ any(AudioAttributes.class));
}
private void verifyVibrate() {
verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), argThat(mVibrateOnceMatcher),
- anyString(), any());
+ anyString(), any(AudioAttributes.class));
}
private void verifyVibrate(int times) {
- verify(mVibrator, times(times)).vibrate(anyInt(), anyString(), any(), anyString(), any());
+ verify(mVibrator, times(times)).vibrate(anyInt(), anyString(), any(), anyString(),
+ any(AudioAttributes.class));
}
private void verifyVibrateLooped() {
verify(mVibrator, times(1)).vibrate(anyInt(), anyString(), argThat(mVibrateLoopMatcher),
- anyString(), any());
+ anyString(), any(AudioAttributes.class));
}
private void verifyDelayedVibrateLooped() {
verify(mVibrator, timeout(MAX_VIBRATION_DELAY).times(1)).vibrate(anyInt(), anyString(),
- argThat(mVibrateLoopMatcher), anyString(), any());
+ argThat(mVibrateLoopMatcher), anyString(), any(AudioAttributes.class));
}
private void verifyDelayedVibrate() {
verify(mVibrator, timeout(MAX_VIBRATION_DELAY).times(1)).vibrate(anyInt(), anyString(),
- argThat(mVibrateOnceMatcher), anyString(), any());
+ argThat(mVibrateOnceMatcher), anyString(), any(AudioAttributes.class));
}
private void verifyStopVibrate() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 0f805610af93..3349c6dda87f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -233,7 +233,11 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase {
.setTask(mRootWindowContainer.getDefaultTaskDisplayArea().getOrCreateRootHomeTask())
.build();
final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ activity.setState(Task.ActivityState.RESUMED, "test");
mSupervisor.endDeferResume();
+
+ assertEquals(activity.app, mAtm.mInternal.getTopApp());
+
// Assume the activity is finishing and hidden because it was crashed.
activity.finishing = true;
activity.mVisibleRequested = false;
@@ -246,6 +250,7 @@ public class ActivityTaskManagerServiceTests extends WindowTestsBase {
mAtm.mInternal.handleAppDied(activity.app, false /* restarting */,
null /* finishInstrumentationCallback */);
assertEquals(Task.ActivityState.RESUMED, homeActivity.getState());
+ assertEquals(homeActivity.app, mAtm.mInternal.getTopApp());
}
}
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 4a9046624779..e45b28e3f8c4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -526,7 +526,8 @@ public class DisplayContentTests extends WindowTestsBase {
for (int i = 0; i < types.length; i++) {
final int type = types[i];
windows[i] = createWindow(null /* parent */, type, displayContent, "window-" + type);
- windows[i].mHasSurface = false;
+ windows[i].setHasSurface(true);
+ windows[i].mWinAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
}
return windows;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java
new file mode 100644
index 000000000000..0a960bef015e
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/InputMethodMenuControllerTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.view.WindowManager;
+
+import com.android.server.inputmethod.InputMethodManagerService;
+import com.android.server.inputmethod.InputMethodMenuController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+// TODO(b/157888351): Move the test to inputmethod package once we find the way to test the
+// scenario there.
+/**
+ * Build/Install/Run:
+ * atest WmTests:InputMethodMenuControllerTest
+ */
+@Presubmit
+@RunWith(WindowTestRunner.class)
+public class InputMethodMenuControllerTest extends WindowTestsBase {
+
+ private InputMethodMenuController mController;
+
+ @Before
+ public void setUp() {
+ mController = new InputMethodMenuController(mock(InputMethodManagerService.class));
+ }
+
+ @Test
+ public void testGetSettingsContext() {
+ final Context contextOnDefaultDisplay = mController.getSettingsContext(DEFAULT_DISPLAY);
+
+ assertImeSwitchContextMetricsValidity(contextOnDefaultDisplay, mDefaultDisplay);
+
+ // Obtain the context again and check they are the same instance and match the display
+ // metrics of the secondary display.
+ final Context contextOnSecondaryDisplay = mController.getSettingsContext(
+ mDisplayContent.getDisplayId());
+
+ assertImeSwitchContextMetricsValidity(contextOnSecondaryDisplay, mDisplayContent);
+ assertThat(contextOnDefaultDisplay.getActivityToken())
+ .isEqualTo(contextOnSecondaryDisplay.getActivityToken());
+ }
+
+ private void assertImeSwitchContextMetricsValidity(Context context, DisplayContent dc) {
+ assertThat(context.getDisplayId()).isEqualTo(dc.getDisplayId());
+
+ final Rect contextBounds = context.getSystemService(WindowManager.class)
+ .getMaximumWindowMetrics().getBounds();
+ final Rect imeContainerBounds = dc.getImeContainer().getBounds();
+ assertThat(contextBounds).isEqualTo(imeContainerBounds);
+ }
+}
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 5b7cf5a72f0a..749f33e9fec2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -21,7 +21,9 @@ 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;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST;
@@ -32,8 +34,11 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
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;
@@ -176,4 +181,31 @@ public class WindowManagerServiceTests extends WindowTestsBase {
mWm.dismissKeyguard(null, "test-dismiss-keyguard");
verify(mWm.mAtmService.mStackSupervisor).wakeUp(anyString());
}
+
+ @Test
+ public void testMoveWindowTokenToDisplay_NullToken_DoNothing() {
+ mWm.moveWindowTokenToDisplay(null, mDisplayContent.getDisplayId());
+
+ verify(mDisplayContent, never()).reParentWindowToken(any());
+ }
+
+ @Test
+ public void testMoveWindowTokenToDisplay_SameDisplay_DoNothing() {
+ final WindowToken windowToken = createTestWindowToken(TYPE_INPUT_METHOD_DIALOG,
+ mDisplayContent);
+
+ mWm.moveWindowTokenToDisplay(windowToken.token, mDisplayContent.getDisplayId());
+
+ verify(mDisplayContent, never()).reParentWindowToken(any());
+ }
+
+ @Test
+ public void testMoveWindowTokenToDisplay_DifferentDisplay_DoMoveDisplay() {
+ final WindowToken windowToken = createTestWindowToken(TYPE_INPUT_METHOD_DIALOG,
+ mDisplayContent);
+
+ mWm.moveWindowTokenToDisplay(windowToken.token, DEFAULT_DISPLAY);
+
+ assertThat(windowToken.getDisplayContent()).isEqualTo(mDefaultDisplay);
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index e50c00975a7f..94bbfca012b0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -28,7 +28,6 @@ import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.when;
import android.Manifest;
import android.app.IApplicationThread;
@@ -160,31 +159,6 @@ public class WindowProcessControllerTests extends WindowTestsBase {
}
@Test
- public void testDelayingConfigurationChange() {
- when(mMockListener.isCached()).thenReturn(false);
-
- Configuration tmpConfig = new Configuration(mWpc.getConfiguration());
- invertOrientation(tmpConfig);
- mWpc.onConfigurationChanged(tmpConfig);
-
- // The last reported config should be the current config as the process is not cached.
- Configuration originalConfig = new Configuration(mWpc.getConfiguration());
- assertEquals(mWpc.getLastReportedConfiguration(), originalConfig);
-
- when(mMockListener.isCached()).thenReturn(true);
- invertOrientation(tmpConfig);
- mWpc.onConfigurationChanged(tmpConfig);
-
- Configuration newConfig = new Configuration(mWpc.getConfiguration());
-
- // Last reported config hasn't changed because the process is in a cached state.
- assertEquals(mWpc.getLastReportedConfiguration(), originalConfig);
-
- mWpc.onProcCachedStateChanged(false);
- assertEquals(mWpc.getLastReportedConfiguration(), newConfig);
- }
-
- @Test
public void testActivityNotOverridingSystemUiProcessConfig() {
final ComponentName systemUiServiceComponent = mAtm.getSysUiServiceComponentLocked();
ApplicationInfo applicationInfo = mock(ApplicationInfo.class);
diff --git a/services/usb/java/com/android/server/usb/UsbSerialReader.java b/services/usb/java/com/android/server/usb/UsbSerialReader.java
index 095e8e9b7b5b..f241e65ba755 100644
--- a/services/usb/java/com/android/server/usb/UsbSerialReader.java
+++ b/services/usb/java/com/android/server/usb/UsbSerialReader.java
@@ -77,7 +77,7 @@ class UsbSerialReader extends IUsbSerialReader.Stub {
UserHandle user = Binder.getCallingUserHandle();
int packageTargetSdkVersion;
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
PackageInfo pkg;
try {
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 14c7f04b9e82..444cb5cb89c7 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -281,7 +281,7 @@ public class UsbService extends IUsbManager.Stub {
int pid = Binder.getCallingPid();
int user = UserHandle.getUserId(uid);
- long ident = clearCallingIdentity();
+ final long ident = clearCallingIdentity();
try {
synchronized (mLock) {
if (mUserManager.isSameProfileGroup(user, mCurrentUserId)) {
@@ -318,7 +318,7 @@ public class UsbService extends IUsbManager.Stub {
int uid = Binder.getCallingUid();
int user = UserHandle.getUserId(uid);
- long ident = clearCallingIdentity();
+ final long ident = clearCallingIdentity();
try {
synchronized (mLock) {
if (mUserManager.isSameProfileGroup(user, mCurrentUserId)) {
diff --git a/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java b/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java
index 333edfd91b16..e20b1a4d6c89 100644
--- a/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java
+++ b/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java
@@ -505,22 +505,23 @@ class UsbUserPermissionManager {
int uid,
@NonNull Context userContext,
@NonNull PendingIntent pi) {
- long identity = Binder.clearCallingIdentity();
- Intent intent = new Intent();
- if (device != null) {
- intent.putExtra(UsbManager.EXTRA_DEVICE, device);
- } else {
- intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
- }
- intent.putExtra(Intent.EXTRA_INTENT, pi);
- intent.putExtra(Intent.EXTRA_UID, uid);
- intent.putExtra(UsbManager.EXTRA_CAN_BE_DEFAULT, canBeDefault);
- intent.putExtra(UsbManager.EXTRA_PACKAGE, packageName);
- intent.setComponent(ComponentName.unflattenFromString(userContext.getResources().getString(
- com.android.internal.R.string.config_usbPermissionActivity)));
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
+ final long identity = Binder.clearCallingIdentity();
try {
+ Intent intent = new Intent();
+ if (device != null) {
+ intent.putExtra(UsbManager.EXTRA_DEVICE, device);
+ } else {
+ intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+ }
+ intent.putExtra(Intent.EXTRA_INTENT, pi);
+ intent.putExtra(Intent.EXTRA_UID, uid);
+ intent.putExtra(UsbManager.EXTRA_CAN_BE_DEFAULT, canBeDefault);
+ intent.putExtra(UsbManager.EXTRA_PACKAGE, packageName);
+ intent.setComponent(
+ ComponentName.unflattenFromString(userContext.getResources().getString(
+ com.android.internal.R.string.config_usbPermissionActivity)));
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
userContext.startActivityAsUser(intent, mUser);
} catch (ActivityNotFoundException e) {
Slog.e(TAG, "unable to start UsbPermissionActivity");
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index b6506b408714..64f8c585c80b 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -1027,7 +1027,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
// internalClearGlobalStateLocked() cleans up the telephony and power save listeners.
private void internalClearGlobalStateLocked() {
// Unregister from call state changes.
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
} finally {
@@ -1100,7 +1100,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
if (mRecognitionRequested) {
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
// Get the current call state synchronously for the first recognition.
mCallActive = mTelephonyManager.getCallState() == TelephonyManager.CALL_STATE_OFFHOOK;
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
index a73e73e37fff..5999044d9427 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerService.java
@@ -899,7 +899,7 @@ public class SoundTriggerService extends SystemService {
mClient = new ISoundTriggerDetectionServiceClient.Stub() {
@Override
public void onOpFinished(int opId) {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
synchronized (mRemoteServiceLock) {
mRunningOpIds.remove(opId);
@@ -1013,7 +1013,7 @@ public class SoundTriggerService extends SystemService {
* Verify that the service has the expected properties and then bind to the service
*/
private void bind() {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
Intent i = new Intent();
i.setComponent(mServiceName);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index f4fc185d3b5c..917f65ab7c01 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1039,8 +1039,8 @@ public class VoiceInteractionManagerService extends SystemService {
}
final int callingUserId = UserHandle.getCallingUserId();
- final long caller = Binder.clearCallingIdentity();
boolean deleted = false;
+ final long caller = Binder.clearCallingIdentity();
try {
SoundTriggerSession session = mLoadedKeyphraseIds.get(keyphraseId);
if (session != null) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 0ff92739f8b6..cfdc5682a117 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -309,7 +309,7 @@ final class VoiceInteractionSessionConnection implements ServiceConnection,
if (!"content".equals(uri.getScheme())) {
return;
}
- long ident = Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
try {
// This will throw SecurityException for us.
mUgmInternal.checkGrantUriPermission(srcUid, null,
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 0469fa56e648..a6d72450156f 100755
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -2111,7 +2111,13 @@ public final class Call {
/**
* Obtains a list of canned, pre-configured message responses to present to the user as
- * ways of rejecting this {@code Call} using via a text message.
+ * ways of rejecting an incoming {@code Call} using via a text message.
+ * <p>
+ * <em>Note:</em> Since canned responses may be loaded from the file system, they are not
+ * guaranteed to be present when this {@link Call} is first added to the {@link InCallService}
+ * via {@link InCallService#onCallAdded(Call)}. The callback
+ * {@link Call.Callback#onCannedTextResponsesLoaded(Call, List)} will be called when/if canned
+ * responses for the call become available.
*
* @see #reject(boolean, String)
*
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index 4d9311c282f7..49f183151e27 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -64,7 +64,7 @@ import com.android.internal.telecom.ICallScreeningService;
* </li>
* </ol>
* <p>
- * <h2>Becoming the {@link CallScreeningService}</h2>
+ * <h2>Becoming the CallScreeningService</h2>
* Telecom will bind to a single app chosen by the user which implements the
* {@link CallScreeningService} API when there are new incoming and outgoing calls.
* <p>
@@ -90,7 +90,27 @@ import com.android.internal.telecom.ICallScreeningService;
* }
* }
* }
+ * }
* </pre>
+ *
+ * <h2>CallScreeningService Lifecycle</h2>
+ *
+ * The framework binds to the {@link CallScreeningService} implemented by the user-chosen app
+ * filling the {@link android.app.role.RoleManager#ROLE_CALL_SCREENING} role when incoming calls are
+ * received (prior to ringing) and when outgoing calls are placed. The platform calls the
+ * {@link #onScreenCall(Call.Details)} method to provide your service with details about the call.
+ * <p>
+ * For incoming calls, the {@link CallScreeningService} must call
+ * {@link #respondToCall(Call.Details, CallResponse)} within 5 seconds of being bound to indicate to
+ * the platform whether the call should be blocked or not. Your app must do this even if it is
+ * primarily performing caller ID operations and not screening calls. It is important to perform
+ * screening operations in a timely matter as the user's device will not begin ringing until the
+ * response is received (or the timeout is hit). A {@link CallScreeningService} may choose to
+ * perform local database lookups to help determine if a call should be screened or not; care should
+ * be taken to ensure the timeout is not repeatedly hit, causing delays in the incoming call flow.
+ * <p>
+ * If your app provides a caller ID experience, it should launch an activity to show the caller ID
+ * information from {@link #onScreenCall(Call.Details)}.
*/
public abstract class CallScreeningService extends Service {
/**
@@ -339,7 +359,7 @@ public abstract class CallScreeningService extends Service {
}
/**
- * Called when a new incoming or outgoing call is added which is not in the user's contact list.
+ * Called when a new incoming or outgoing call is added.
* <p>
* A {@link CallScreeningService} must indicate whether an incoming call is allowed or not by
* calling
@@ -347,21 +367,32 @@ public abstract class CallScreeningService extends Service {
* Your app can tell if a call is an incoming call by checking to see if
* {@link Call.Details#getCallDirection()} is {@link Call.Details#DIRECTION_INCOMING}.
* <p>
- * Note: The {@link Call.Details} instance provided to a call screening service will only have
- * the following properties set. The rest of the {@link Call.Details} properties will be set to
- * their default value or {@code null}.
+ * <em>Note:</em> A {@link CallScreeningService} must respond to a call within 5 seconds. After
+ * this time, the framework will unbind from the {@link CallScreeningService} and ignore its
+ * response.
+ * <p>
+ * <em>Note:</em> The {@link Call.Details} instance provided to a call screening service will
+ * only have the following properties set. The rest of the {@link Call.Details} properties will
+ * be set to their default value or {@code null}.
* <ul>
* <li>{@link Call.Details#getCallDirection()}</li>
+ * <li>{@link Call.Details#getCallerNumberVerificationStatus()}</li>
* <li>{@link Call.Details#getConnectTimeMillis()}</li>
* <li>{@link Call.Details#getCreationTimeMillis()}</li>
* <li>{@link Call.Details#getHandle()}</li>
- * <li>{@link Call.Details#getHandlePresentation()}</li>
* </ul>
* <p>
* Only calls where the {@link Call.Details#getHandle() handle} {@link Uri#getScheme() scheme}
* is {@link PhoneAccount#SCHEME_TEL} are passed for call
* screening. Further, only calls which are not in the user's contacts are passed for
- * screening. For outgoing calls, no post-dial digits are passed.
+ * screening, unless the {@link CallScreeningService} has been granted
+ * {@link Manifest.permission#READ_CONTACTS} permission by the user. For outgoing calls, no
+ * post-dial digits are passed.
+ * <p>
+ * Calls with a {@link Call.Details#getHandlePresentation()} of
+ * {@link TelecomManager#PRESENTATION_RESTRICTED}, {@link TelecomManager#PRESENTATION_UNKNOWN}
+ * or {@link TelecomManager#PRESENTATION_PAYPHONE} presentation are not provided to the
+ * {@link CallScreeningService}.
*
* @param callDetails Information about a new call, see {@link Call.Details}.
*/
@@ -376,6 +407,13 @@ public abstract class CallScreeningService extends Service {
* <p>
* Calls to this method are ignored unless the {@link Call.Details#getCallDirection()} is
* {@link Call.Details#DIRECTION_INCOMING}.
+ * <p>
+ * For incoming calls, a {@link CallScreeningService} MUST call this method within 5 seconds of
+ * {@link #onScreenCall(Call.Details)} being invoked by the platform.
+ * <p>
+ * Calls which are blocked/rejected will be logged to the system call log with a call type of
+ * {@link android.provider.CallLog.Calls#BLOCKED_TYPE} and
+ * {@link android.provider.CallLog.Calls#BLOCK_REASON_CALL_SCREENING_SERVICE} block reason.
*
* @param callDetails The call to allow.
* <p>
diff --git a/telecomm/java/android/telecom/DefaultDialerManager.java b/telecomm/java/android/telecom/DefaultDialerManager.java
index 5b806a6e57da..1c070748400d 100644
--- a/telecomm/java/android/telecom/DefaultDialerManager.java
+++ b/telecomm/java/android/telecom/DefaultDialerManager.java
@@ -74,7 +74,7 @@ public class DefaultDialerManager {
* */
public static boolean setDefaultDialerApplication(Context context, String packageName,
int user) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
CompletableFuture<Void> future = new CompletableFuture<>();
Consumer<Boolean> callback = successful -> {
@@ -128,7 +128,7 @@ public class DefaultDialerManager {
* @hide
* */
public static String getDefaultDialerApplication(Context context, int user) {
- long identity = Binder.clearCallingIdentity();
+ final long identity = Binder.clearCallingIdentity();
try {
return CollectionUtils.firstOrNull(context.getSystemService(RoleManager.class)
.getRoleHoldersAsUser(RoleManager.ROLE_DIALER, UserHandle.of(user)));
diff --git a/telephony/common/android/telephony/LocationAccessPolicy.java b/telephony/common/android/telephony/LocationAccessPolicy.java
index 502bfa3749eb..85d59a216f25 100644
--- a/telephony/common/android/telephony/LocationAccessPolicy.java
+++ b/telephony/common/android/telephony/LocationAccessPolicy.java
@@ -377,7 +377,7 @@ public final class LocationAccessPolicy {
}
private static boolean isCurrentProfile(@NonNull Context context, int uid) {
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
if (UserHandle.getUserHandleForUid(uid).getIdentifier()
== ActivityManager.getCurrentUser()) {
diff --git a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
index 7736473feafb..b8ca3267cf9e 100644
--- a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
+++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
@@ -96,7 +96,7 @@ public final class TelephonyUtils {
*/
public static void runWithCleanCallingIdentity(
@NonNull Runnable action) {
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
action.run();
} finally {
@@ -115,7 +115,7 @@ public final class TelephonyUtils {
*/
public static <T> T runWithCleanCallingIdentity(
@NonNull Supplier<T> action) {
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
return action.get();
} finally {
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index ee2fce7e7dd5..3a0e49e204cb 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -161,7 +161,7 @@ public class ImsMmTelManager implements RegistrationManager {
public void onCapabilitiesStatusChanged(int config) {
if (mLocalCallback == null) return;
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
mExecutor.execute(() -> mLocalCallback.onCapabilitiesStatusChanged(
new MmTelFeature.MmTelCapabilities(config)));
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index 94407f1dcd3a..a7586ec4ec18 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -99,7 +99,7 @@ public class ImsRcsManager {
public void onCapabilitiesStatusChanged(int config) {
if (mLocalCallback == null) return;
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
mExecutor.execute(() -> mLocalCallback.onAvailabilityChanged(
new RcsFeature.RcsImsCapabilities(config)));
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 2a073a1f1d81..3affdf64aae7 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -879,7 +879,7 @@ public class ProvisioningManager {
@Override
public final void onIntConfigChanged(int item, int value) {
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
mExecutor.execute(() ->
mLocalConfigurationCallback.onProvisioningIntChanged(item, value));
@@ -890,7 +890,7 @@ public class ProvisioningManager {
@Override
public final void onStringConfigChanged(int item, String value) {
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
mExecutor.execute(() ->
mLocalConfigurationCallback.onProvisioningStringChanged(item, value));
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index a427d056f915..4606f7d625aa 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -206,7 +206,7 @@ public class RcsUceAdapter {
public void onPublishStateChanged(int publishState) {
if (mLocalCallback == null) return;
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
mExecutor.execute(() -> mLocalCallback.onChanged(publishState));
} finally {
@@ -322,7 +322,7 @@ public class RcsUceAdapter {
IRcsUceControllerCallback internalCallback = new IRcsUceControllerCallback.Stub() {
@Override
public void onCapabilitiesReceived(List<RcsContactUceCapability> contactCapabilities) {
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
executor.execute(() ->
c.onCapabilitiesReceived(contactCapabilities));
@@ -332,7 +332,7 @@ public class RcsUceAdapter {
}
@Override
public void onError(int errorCode) {
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
executor.execute(() -> c.onError(errorCode));
} finally {
diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java
index e085dec10546..1a78e166932a 100644
--- a/telephony/java/android/telephony/ims/RegistrationManager.java
+++ b/telephony/java/android/telephony/ims/RegistrationManager.java
@@ -105,7 +105,7 @@ public interface RegistrationManager {
public void onRegistered(int imsRadioTech) {
if (mLocalCallback == null) return;
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
mExecutor.execute(() ->
mLocalCallback.onRegistered(getAccessType(imsRadioTech)));
@@ -118,7 +118,7 @@ public interface RegistrationManager {
public void onRegistering(int imsRadioTech) {
if (mLocalCallback == null) return;
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
mExecutor.execute(() ->
mLocalCallback.onRegistering(getAccessType(imsRadioTech)));
@@ -131,7 +131,7 @@ public interface RegistrationManager {
public void onDeregistered(ImsReasonInfo info) {
if (mLocalCallback == null) return;
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
mExecutor.execute(() -> mLocalCallback.onUnregistered(info));
} finally {
@@ -143,7 +143,7 @@ public interface RegistrationManager {
public void onTechnologyChangeFailed(int imsRadioTech, ImsReasonInfo info) {
if (mLocalCallback == null) return;
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
mExecutor.execute(() -> mLocalCallback.onTechnologyChangeFailed(
getAccessType(imsRadioTech), info));
@@ -155,7 +155,7 @@ public interface RegistrationManager {
public void onSubscriberAssociatedUriChanged(Uri[] uris) {
if (mLocalCallback == null) return;
- long callingIdentity = Binder.clearCallingIdentity();
+ final long callingIdentity = Binder.clearCallingIdentity();
try {
mExecutor.execute(() -> mLocalCallback.onSubscriberAssociatedUriChanged(uris));
} finally {
diff --git a/telephony/java/android/telephony/mbms/InternalDownloadProgressListener.java b/telephony/java/android/telephony/mbms/InternalDownloadProgressListener.java
index 6a135694869c..a413ef8a8738 100644
--- a/telephony/java/android/telephony/mbms/InternalDownloadProgressListener.java
+++ b/telephony/java/android/telephony/mbms/InternalDownloadProgressListener.java
@@ -43,7 +43,7 @@ public class InternalDownloadProgressListener extends IDownloadProgressListener.
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(new Runnable() {
@Override
diff --git a/telephony/java/android/telephony/mbms/InternalDownloadSessionCallback.java b/telephony/java/android/telephony/mbms/InternalDownloadSessionCallback.java
index ce32477b443b..67539a0ad7ee 100644
--- a/telephony/java/android/telephony/mbms/InternalDownloadSessionCallback.java
+++ b/telephony/java/android/telephony/mbms/InternalDownloadSessionCallback.java
@@ -40,7 +40,7 @@ public class InternalDownloadSessionCallback extends IMbmsDownloadSessionCallbac
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(new Runnable() {
@Override
@@ -59,7 +59,7 @@ public class InternalDownloadSessionCallback extends IMbmsDownloadSessionCallbac
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(new Runnable() {
@Override
@@ -78,7 +78,7 @@ public class InternalDownloadSessionCallback extends IMbmsDownloadSessionCallbac
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(new Runnable() {
@Override
diff --git a/telephony/java/android/telephony/mbms/InternalDownloadStatusListener.java b/telephony/java/android/telephony/mbms/InternalDownloadStatusListener.java
index 87163ff8b32c..ce96a8faeb49 100644
--- a/telephony/java/android/telephony/mbms/InternalDownloadStatusListener.java
+++ b/telephony/java/android/telephony/mbms/InternalDownloadStatusListener.java
@@ -42,7 +42,7 @@ public class InternalDownloadStatusListener extends IDownloadStatusListener.Stub
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(new Runnable() {
@Override
diff --git a/telephony/java/android/telephony/mbms/InternalGroupCallCallback.java b/telephony/java/android/telephony/mbms/InternalGroupCallCallback.java
index c7600b6c7843..5e1f1f170f60 100644
--- a/telephony/java/android/telephony/mbms/InternalGroupCallCallback.java
+++ b/telephony/java/android/telephony/mbms/InternalGroupCallCallback.java
@@ -38,7 +38,7 @@ public class InternalGroupCallCallback extends IGroupCallCallback.Stub {
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(new Runnable() {
@Override
@@ -57,7 +57,7 @@ public class InternalGroupCallCallback extends IGroupCallCallback.Stub {
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(new Runnable() {
@Override
@@ -76,7 +76,7 @@ public class InternalGroupCallCallback extends IGroupCallCallback.Stub {
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(new Runnable() {
@Override
diff --git a/telephony/java/android/telephony/mbms/InternalGroupCallSessionCallback.java b/telephony/java/android/telephony/mbms/InternalGroupCallSessionCallback.java
index 0b7667ec525c..ca4190c6b4f1 100644
--- a/telephony/java/android/telephony/mbms/InternalGroupCallSessionCallback.java
+++ b/telephony/java/android/telephony/mbms/InternalGroupCallSessionCallback.java
@@ -39,7 +39,7 @@ public class InternalGroupCallSessionCallback extends IMbmsGroupCallSessionCallb
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(new Runnable() {
@Override
@@ -58,7 +58,7 @@ public class InternalGroupCallSessionCallback extends IMbmsGroupCallSessionCallb
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(new Runnable() {
@Override
@@ -77,7 +77,7 @@ public class InternalGroupCallSessionCallback extends IMbmsGroupCallSessionCallb
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(new Runnable() {
@Override
@@ -96,7 +96,7 @@ public class InternalGroupCallSessionCallback extends IMbmsGroupCallSessionCallb
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(new Runnable() {
@Override
diff --git a/telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java b/telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java
index 3a4ed08ed954..d62add193e77 100644
--- a/telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java
+++ b/telephony/java/android/telephony/mbms/InternalStreamingServiceCallback.java
@@ -39,7 +39,7 @@ public class InternalStreamingServiceCallback extends IStreamingServiceCallback.
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(new Runnable() {
@Override
@@ -58,7 +58,7 @@ public class InternalStreamingServiceCallback extends IStreamingServiceCallback.
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(new Runnable() {
@Override
@@ -77,7 +77,7 @@ public class InternalStreamingServiceCallback extends IStreamingServiceCallback.
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(new Runnable() {
@Override
@@ -96,7 +96,7 @@ public class InternalStreamingServiceCallback extends IStreamingServiceCallback.
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(new Runnable() {
@Override
@@ -115,7 +115,7 @@ public class InternalStreamingServiceCallback extends IStreamingServiceCallback.
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(new Runnable() {
@Override
diff --git a/telephony/java/android/telephony/mbms/InternalStreamingSessionCallback.java b/telephony/java/android/telephony/mbms/InternalStreamingSessionCallback.java
index 2eb280e74106..f4ee4dc069a9 100644
--- a/telephony/java/android/telephony/mbms/InternalStreamingSessionCallback.java
+++ b/telephony/java/android/telephony/mbms/InternalStreamingSessionCallback.java
@@ -40,7 +40,7 @@ public class InternalStreamingSessionCallback extends IMbmsStreamingSessionCallb
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(new Runnable() {
@Override
@@ -60,7 +60,7 @@ public class InternalStreamingSessionCallback extends IMbmsStreamingSessionCallb
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(new Runnable() {
@Override
@@ -79,7 +79,7 @@ public class InternalStreamingSessionCallback extends IMbmsStreamingSessionCallb
return;
}
- long token = Binder.clearCallingIdentity();
+ final long token = Binder.clearCallingIdentity();
try {
mExecutor.execute(new Runnable() {
@Override
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
index 08144c845555..b53b78a8d5b2 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/ColorFiltersMutateActivity.java
@@ -22,6 +22,7 @@ import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
@@ -30,6 +31,7 @@ import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.RuntimeShader;
+import android.graphics.Shader;
import android.os.Bundle;
import android.view.View;
@@ -59,9 +61,10 @@ public class ColorFiltersMutateActivity extends Activity {
private int mPorterDuffColor = 0;
static final String sSkSL =
- "uniform float param1;\n"
- + "void main(float2 xy, inout half4 color) {\n"
- + "color = half4(color.r, half(param1), color.b, 1.0);\n"
+ "in shader bitmapShader;\n"
+ + "uniform float param1;\n"
+ + "half4 main(float2 xy) {\n"
+ + " return half4(sample(bitmapShader, xy).rgb, param1);\n"
+ "}\n";
private byte[] mUniforms = new byte[4];
@@ -84,7 +87,9 @@ public class ColorFiltersMutateActivity extends Activity {
mBlendPaint.setColorFilter(new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_OVER));
mShaderPaint = new Paint();
- mShaderPaint.setShader(new RuntimeShader(sSkSL, mUniforms, true));
+ Shader[] inputShaders = { new BitmapShader(mBitmap1, Shader.TileMode.CLAMP,
+ Shader.TileMode.CLAMP) };
+ mShaderPaint.setShader(new RuntimeShader(sSkSL, mUniforms, inputShaders, true));
setShaderParam1(0.0f);
ObjectAnimator sat = ObjectAnimator.ofFloat(this, "saturation", 1.0f);
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index ab2e4923c88e..52718bec9148 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -482,6 +482,26 @@ public class StagedRollbackTest {
}
@Test
+ public void testRollbackApkDataDirectories_Phase1() throws Exception {
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(-1);
+ Install.single(TestApp.A1).commit();
+ assertThat(InstallUtils.getInstalledVersion(TestApp.A)).isEqualTo(1);
+ }
+
+ @Test
+ public void testRollbackApkDataDirectories_Phase2() throws Exception {
+ Install.single(TestApp.A2).setStaged().setEnableRollback().commit();
+ }
+
+ @Test
+ public void testRollbackApkDataDirectories_Phase3() throws Exception {
+ RollbackInfo available = RollbackUtils.getAvailableRollback(TestApp.A);
+ RollbackUtils.rollback(available.getRollbackId(), TestApp.A2);
+ RollbackInfo committed = RollbackUtils.getCommittedRollbackById(available.getRollbackId());
+ InstallUtils.waitForSessionReady(committed.getCommittedSessionId());
+ }
+
+ @Test
public void isCheckpointSupported() {
Context context = InstrumentationRegistry.getInstrumentation().getContext();
StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index c2fd0c39221e..226d2d5db820 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -453,6 +453,43 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
after.forEach(dir -> assertDirectoryIsEmpty(dir));
}
+ /**
+ * Tests that data in DE apk data directory is restored when apk is rolled back.
+ */
+ @Test
+ public void testRollbackApkDataDirectories_De() throws Exception {
+ // Install version 1 of TESTAPP_A
+ runPhase("testRollbackApkDataDirectories_Phase1");
+
+ // Push files to apk data directory
+ String oldFilePath1 = apkDataDirDe(TESTAPP_A, 0) + "/" + TEST_FILENAME_1;
+ String oldFilePath2 = apkDataDirDe(TESTAPP_A, 0) + TEST_SUBDIR + TEST_FILENAME_2;
+ assertTrue(getDevice().pushString(TEST_STRING_1, oldFilePath1));
+ assertTrue(getDevice().pushString(TEST_STRING_2, oldFilePath2));
+
+ // Install version 2 of TESTAPP_A with rollback enabled
+ runPhase("testRollbackApkDataDirectories_Phase2");
+ getDevice().reboot();
+
+ // Replace files in data directory
+ getDevice().deleteFile(oldFilePath1);
+ getDevice().deleteFile(oldFilePath2);
+ String newFilePath3 = apkDataDirDe(TESTAPP_A, 0) + "/" + TEST_FILENAME_3;
+ String newFilePath4 = apkDataDirDe(TESTAPP_A, 0) + TEST_SUBDIR + TEST_FILENAME_4;
+ assertTrue(getDevice().pushString(TEST_STRING_3, newFilePath3));
+ assertTrue(getDevice().pushString(TEST_STRING_4, newFilePath4));
+
+ // Roll back the APK
+ runPhase("testRollbackApkDataDirectories_Phase3");
+ getDevice().reboot();
+
+ // Verify that old files have been restored and new files are gone
+ assertEquals(TEST_STRING_1, getDevice().pullFileContents(oldFilePath1));
+ assertEquals(TEST_STRING_2, getDevice().pullFileContents(oldFilePath2));
+ assertNull(getDevice().pullFile(newFilePath3));
+ assertNull(getDevice().pullFile(newFilePath4));
+ }
+
@Test
public void testExpireApexRollback() throws Exception {
List<String> before = getSnapshotDirectories("/data/misc_ce/0/apexrollback");
@@ -503,6 +540,10 @@ public class StagedRollbackTest extends BaseHostJUnit4Test {
return String.format("/data/misc_ce/%d/apexdata/%s", userId, apexName);
}
+ private static String apkDataDirDe(String apexName, int userId) {
+ return String.format("/data/user_de/%d/%s", userId, apexName);
+ }
+
private List<String> getSnapshotDirectories(String baseDir) {
try {
return getDevice().getFileEntry(baseDir).getChildren(false)
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index c3f1549409fc..7ab4d9766ef4 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -1263,7 +1263,7 @@ public class VpnTest {
}
@Override
- public boolean checkInterfacePresent(final Vpn vpn, final String iface) {
+ public boolean isInterfacePresent(final Vpn vpn, final String iface) {
return true;
}
}
diff --git a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
index ea803f2aba8b..a7d0860210b4 100644
--- a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
+++ b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
@@ -49,7 +49,8 @@ public final class FrameworksTestsFilter extends SelectTest {
"android.view.WindowMetricsTest",
"android.view.PendingInsetsControllerTest",
"android.app.WindowContextTest",
- "android.window.WindowMetricsHelperTest"
+ "android.window.WindowMetricsHelperTest",
+ "android.app.activity.ActivityThreadTest"
};
public FrameworksTestsFilter(Bundle testArgs) {
diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt
index 5a96cf1d9bdb..6e1ab5944eb6 100644
--- a/tools/codegen/src/com/android/codegen/Generators.kt
+++ b/tools/codegen/src/com/android/codegen/Generators.kt
@@ -3,7 +3,10 @@ package com.android.codegen
import com.github.javaparser.ast.body.FieldDeclaration
import com.github.javaparser.ast.body.MethodDeclaration
import com.github.javaparser.ast.body.VariableDeclarator
-import com.github.javaparser.ast.expr.*
+import com.github.javaparser.ast.expr.AnnotationExpr
+import com.github.javaparser.ast.expr.ArrayInitializerExpr
+import com.github.javaparser.ast.expr.LiteralExpr
+import com.github.javaparser.ast.expr.UnaryExpr
import java.io.File
@@ -703,7 +706,7 @@ fun ClassPrinter.generateSetters() {
generateFieldJavadoc(forceHide = FeatureFlag.SETTERS.hidden)
+GENERATED_MEMBER_HEADER
- "public $ClassType set$NameUpperCamel($annotatedTypeForSetterParam value)" {
+ "public @$NonNull $ClassType set$NameUpperCamel($annotatedTypeForSetterParam value)" {
generateSetFrom("value")
+"return this;"
}
diff --git a/tools/codegen/src/com/android/codegen/SharedConstants.kt b/tools/codegen/src/com/android/codegen/SharedConstants.kt
index 36070b55cb2e..785aa9107f90 100644
--- a/tools/codegen/src/com/android/codegen/SharedConstants.kt
+++ b/tools/codegen/src/com/android/codegen/SharedConstants.kt
@@ -1,7 +1,7 @@
package com.android.codegen
const val CODEGEN_NAME = "codegen"
-const val CODEGEN_VERSION = "1.0.16"
+const val CODEGEN_VERSION = "1.0.17"
const val CANONICAL_BUILDER_CLASS = "Builder"
const val BASE_BUILDER_CLASS = "BaseBuilder"
diff --git a/tools/stringslint/stringslint.py b/tools/stringslint/stringslint.py
index afe91cda37b0..15088fc81e88 100644
--- a/tools/stringslint/stringslint.py
+++ b/tools/stringslint/stringslint.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
+#-*- coding: utf-8 -*-
# Copyright (C) 2018 The Android Open Source Project
#
@@ -33,9 +34,6 @@ In general:
import re, sys, codecs
import lxml.etree as ET
-reload(sys)
-sys.setdefaultencoding('utf8')
-
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
def format(fg=None, bg=None, bright=False, bold=False, dim=False, reset=False):
@@ -118,7 +116,7 @@ def lint(path):
raw = f.read()
if len(raw.strip()) == 0:
return warnings
- tree = ET.fromstring(raw)
+ tree = ET.fromstring(bytes(raw, encoding='utf-8'))
root = tree #tree.getroot()
last_comment = None
@@ -231,6 +229,6 @@ for b in before:
if len(after) > 0:
for a in sorted(after.keys()):
- print after[a]
- print
+ print(after[a])
+ print()
sys.exit(1)
diff --git a/tools/stringslint/stringslint_sha.sh b/tools/stringslint/stringslint_sha.sh
index bd80bb4e6f3f..bd0569873197 100755
--- a/tools/stringslint/stringslint_sha.sh
+++ b/tools/stringslint/stringslint_sha.sh
@@ -1,5 +1,5 @@
#!/bin/bash
LOCAL_DIR="$( dirname ${BASH_SOURCE} )"
git show --name-only --pretty=format: $1 | grep values/strings.xml | while read file; do
- python $LOCAL_DIR/stringslint.py <(git show $1:$file) <(git show $1^:$file)
+ python3 $LOCAL_DIR/stringslint.py <(git show $1:$file) <(git show $1^:$file)
done
diff --git a/tools/xmlpersistence/src/main/kotlin/Generator.kt b/tools/xmlpersistence/src/main/kotlin/Generator.kt
index 28467b7fc0b0..b2c5f4ac767b 100644
--- a/tools/xmlpersistence/src/main/kotlin/Generator.kt
+++ b/tools/xmlpersistence/src/main/kotlin/Generator.kt
@@ -50,7 +50,7 @@ val FILE_HEADER = """
*/
// Generated by xmlpersistence. DO NOT MODIFY!
- // CHECKSTYLE:OFF
+ // CHECKSTYLE:OFF Generated code
// @formatter:off
""".trimIndent() + "\n\n"
@@ -128,9 +128,7 @@ private fun generateReadMethod(rootField: ClassFieldInfo): MethodSpec =
.addAnnotation(nullableType)
.addModifiers(Modifier.PUBLIC)
.returns(rootField.type)
- .addControlFlow(
- "try (final \$1T inputStream = mFile.openRead())", FileInputStream::class.java
- ) {
+ .addControlFlow("try (\$1T inputStream = mFile.openRead())", FileInputStream::class.java) {
addStatement("final \$1T parser = \$2T.newPullParser()", xmlPullParserType, xmlType)
addStatement("parser.setInput(inputStream, null)")
addStatement("return parse(parser)")
diff --git a/wifi/api/current.txt b/wifi/api/current.txt
index 69286187eef3..2d48a8325d6e 100644
--- a/wifi/api/current.txt
+++ b/wifi/api/current.txt
@@ -492,6 +492,7 @@ package android.net.wifi {
method @IntRange(from=0) public int getPriority();
method public int getPriorityGroup();
method @Nullable public String getSsid();
+ method public int getSubscriptionId();
method public boolean isAppInteractionRequired();
method public boolean isCredentialSharedWithUser();
method public boolean isEnhancedOpen();
@@ -520,6 +521,7 @@ package android.net.wifi {
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriority(@IntRange(from=0) int);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setPriorityGroup(int);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setSsid(@NonNull String);
+ method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setSubscriptionId(int);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setUntrusted(boolean);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWapiEnterpriseConfig(@NonNull android.net.wifi.WifiEnterpriseConfig);
method @NonNull public android.net.wifi.WifiNetworkSuggestion.Builder setWapiPassphrase(@NonNull String);
diff --git a/wifi/api/system-current.txt b/wifi/api/system-current.txt
index bf7003c409f9..98cb849084d4 100644
--- a/wifi/api/system-current.txt
+++ b/wifi/api/system-current.txt
@@ -350,6 +350,7 @@ package android.net.wifi {
field @Deprecated public int numScorerOverrideAndSwitchedNetwork;
field @Deprecated public boolean requirePmf;
field @Deprecated public boolean shared;
+ field @Deprecated public int subscriptionId;
field @Deprecated public boolean useExternalScores;
}
diff --git a/wifi/api/system-lint-baseline.txt b/wifi/api/system-lint-baseline.txt
index 6547ee8a2188..a5f3f7c08fa4 100644
--- a/wifi/api/system-lint-baseline.txt
+++ b/wifi/api/system-lint-baseline.txt
@@ -1,6 +1,11 @@
// Baseline format: 1.0
MissingGetterMatchingBuilder: android.net.wifi.rtt.RangingRequest.Builder#addResponder(android.net.wifi.rtt.ResponderConfig):
- android.net.wifi.rtt.RangingRequest does not declare a `getResponders()` method matching method android.net.wifi.rtt.RangingRequest.Builder.addResponder(android.net.wifi.rtt.ResponderConfig)
+
+
MissingNullability: android.net.wifi.rtt.RangingRequest.Builder#addResponder(android.net.wifi.rtt.ResponderConfig):
+
+
+MutableBareField: android.net.wifi.WifiConfiguration#subscriptionId:
+ Bare field subscriptionId must be marked final, or moved behind accessors if mutable
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index fc6c59a882cf..7c2556d8cffd 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -35,6 +35,8 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
@@ -881,6 +883,14 @@ public class WifiConfiguration implements Parcelable {
public int carrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
/**
+ * The subscription ID identifies the SIM card for which this network configuration is valid.
+ * See {@link SubscriptionInfo#getSubscriptionId()}
+ * @hide
+ */
+ @SystemApi
+ public int subscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+ /**
* @hide
* Auto-join is allowed by user for this network.
* Default true.
@@ -2617,6 +2627,25 @@ public class WifiConfiguration implements Parcelable {
return key;
}
+ /**
+ * Get a key for this WifiConfig to generate Persist random Mac Address.
+ * @hide
+ */
+ public String getMacRandomKey() {
+ // Passpoint ephemeral networks have their unique identifier set. Return it as is to be
+ // able to match internally.
+ if (mPasspointUniqueId != null) {
+ return mPasspointUniqueId;
+ }
+
+ String key = getSsidAndSecurityTypeString();
+ if (!shared) {
+ key += "-" + UserHandle.getUserHandleForUid(creatorUid).getIdentifier();
+ }
+
+ return key;
+ }
+
/** @hide
* return the SSID + security type in String format.
*/
@@ -2871,6 +2900,7 @@ public class WifiConfiguration implements Parcelable {
requirePmf = source.requirePmf;
updateIdentifier = source.updateIdentifier;
carrierId = source.carrierId;
+ subscriptionId = source.subscriptionId;
mPasspointUniqueId = source.mPasspointUniqueId;
}
}
@@ -2946,6 +2976,7 @@ public class WifiConfiguration implements Parcelable {
dest.writeLong(randomizedMacLastModifiedTimeMs);
dest.writeInt(carrierId);
dest.writeString(mPasspointUniqueId);
+ dest.writeInt(subscriptionId);
}
/** Implement the Parcelable interface {@hide} */
@@ -3022,6 +3053,7 @@ public class WifiConfiguration implements Parcelable {
config.randomizedMacLastModifiedTimeMs = in.readLong();
config.carrierId = in.readInt();
config.mPasspointUniqueId = in.readString();
+ config.subscriptionId = in.readInt();
return config;
}
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 9162c5f3e0d9..c1f900519fc5 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -29,6 +29,8 @@ import android.net.wifi.hotspot2.PasspointConfiguration;
import android.net.wifi.util.SdkLevelUtil;
import android.os.Parcel;
import android.os.Parcelable;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -121,6 +123,12 @@ public final class WifiNetworkSuggestion implements Parcelable {
private int mCarrierId;
/**
+ * The Subscription ID identifies the SIM card for which this network configuration is
+ * valid.
+ */
+ private int mSubscriptionId;
+
+ /**
* Whether this network is shared credential with user to allow user manually connect.
*/
private boolean mIsSharedWithUser;
@@ -185,6 +193,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
mIsNetworkOemPaid = false;
mPriorityGroup = 0;
mIsEnhancedMacRandomizationEnabled = false;
+ mSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
}
/**
@@ -353,6 +362,27 @@ public final class WifiNetworkSuggestion implements Parcelable {
}
/**
+ * Set the subscription ID of the SIM card for which this suggestion is targeted.
+ * The suggestion will only apply to that SIM card.
+ * <p>
+ * The subscription ID must belong to a carrier ID which meets either of the following
+ * conditions:
+ * <li>The carrier ID specified by the cross carrier provider, or</li>
+ * <li>The carrier ID which is used to validate the suggesting carrier-privileged app, see
+ * {@link TelephonyManager#hasCarrierPrivileges()}</li>
+ *
+ * @param subId subscription ID see {@link SubscriptionInfo#getSubscriptionId()}
+ * @return Instance of {@link Builder} to enable chaining of the builder method.
+ */
+ public @NonNull Builder setSubscriptionId(int subId) {
+ if (!SdkLevelUtil.isAtLeastS()) {
+ throw new UnsupportedOperationException();
+ }
+ mSubscriptionId = subId;
+ return this;
+ }
+
+ /**
* Set the priority group ID, {@link #setPriority(int)} will only impact the network
* suggestions from the same priority group within the same app.
*
@@ -360,6 +390,9 @@ public final class WifiNetworkSuggestion implements Parcelable {
* @return Instance of {@link Builder} to enable chaining of the builder method.
*/
public @NonNull Builder setPriorityGroup(int priorityGroup) {
+ if (!SdkLevelUtil.isAtLeastS()) {
+ throw new UnsupportedOperationException();
+ }
mPriorityGroup = priorityGroup;
return this;
}
@@ -675,6 +708,7 @@ public final class WifiNetworkSuggestion implements Parcelable {
wifiConfiguration.macRandomizationSetting = mIsEnhancedMacRandomizationEnabled
? WifiConfiguration.RANDOMIZATION_ENHANCED
: WifiConfiguration.RANDOMIZATION_PERSISTENT;
+ wifiConfiguration.subscriptionId = mSubscriptionId;
return wifiConfiguration;
}
@@ -704,7 +738,9 @@ public final class WifiNetworkSuggestion implements Parcelable {
wifiConfiguration.meteredOverride = mMeteredOverride;
wifiConfiguration.trusted = !mIsNetworkUntrusted;
wifiConfiguration.oemPaid = mIsNetworkOemPaid;
+ wifiConfiguration.subscriptionId = mSubscriptionId;
mPasspointConfiguration.setCarrierId(mCarrierId);
+ mPasspointConfiguration.setSubscriptionId(mSubscriptionId);
mPasspointConfiguration.setMeteredOverride(wifiConfiguration.meteredOverride);
wifiConfiguration.macRandomizationSetting = mIsEnhancedMacRandomizationEnabled
? WifiConfiguration.RANDOMIZATION_ENHANCED
@@ -946,7 +982,8 @@ public final class WifiNetworkSuggestion implements Parcelable {
@Override
public int hashCode() {
return Objects.hash(wifiConfiguration.SSID, wifiConfiguration.BSSID,
- wifiConfiguration.allowedKeyManagement, wifiConfiguration.getKey());
+ wifiConfiguration.allowedKeyManagement, wifiConfiguration.getKey(),
+ wifiConfiguration.subscriptionId, wifiConfiguration.carrierId);
}
/**
@@ -970,7 +1007,9 @@ public final class WifiNetworkSuggestion implements Parcelable {
&& Objects.equals(this.wifiConfiguration.allowedKeyManagement,
lhs.wifiConfiguration.allowedKeyManagement)
&& TextUtils.equals(this.wifiConfiguration.getKey(),
- lhs.wifiConfiguration.getKey());
+ lhs.wifiConfiguration.getKey())
+ && this.wifiConfiguration.carrierId == lhs.wifiConfiguration.carrierId
+ && this.wifiConfiguration.subscriptionId == lhs.wifiConfiguration.subscriptionId;
}
@Override
@@ -1123,6 +1162,19 @@ public final class WifiNetworkSuggestion implements Parcelable {
* @see Builder#setPriorityGroup(int)
*/
public int getPriorityGroup() {
+ if (!SdkLevelUtil.isAtLeastS()) {
+ throw new UnsupportedOperationException();
+ }
return priorityGroup;
}
+
+ /**
+ * @see Builder#setSubscriptionId(int)
+ */
+ public int getSubscriptionId() {
+ if (!SdkLevelUtil.isAtLeastS()) {
+ throw new UnsupportedOperationException();
+ }
+ return wifiConfiguration.subscriptionId;
+ }
}
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 61a6e16f9c43..357c5bcfa265 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -30,6 +30,8 @@ import android.net.wifi.hotspot2.pps.UpdateParameter;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
@@ -412,6 +414,12 @@ public final class PasspointConfiguration implements Parcelable {
private int mCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
/**
+ * The subscription ID identifies the SIM card who provides this network configuration.
+ * See {@link SubscriptionInfo#getSubscriptionId()}
+ */
+ private int mSubscriptionId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+ /**
* Set the carrier ID associated with current configuration.
* @param carrierId {@code mCarrierId}
* @hide
@@ -430,6 +438,24 @@ public final class PasspointConfiguration implements Parcelable {
}
/**
+ * Set the subscription ID associated with current configuration.
+ * @param subscriptionId {@code mSubscriptionId}
+ * @hide
+ */
+ public void setSubscriptionId(int subscriptionId) {
+ this.mSubscriptionId = subscriptionId;
+ }
+
+ /**
+ * Get the carrier ID associated with current configuration.
+ * @return {@code mSubscriptionId}
+ * @hide
+ */
+ public int getSubscriptionId() {
+ return mSubscriptionId;
+ }
+
+ /**
* The auto-join configuration specifies whether or not the Passpoint Configuration is
* considered for auto-connection. If true then yes, if false then it isn't considered as part
* of auto-connection - but can still be manually connected to.
@@ -604,6 +630,7 @@ public final class PasspointConfiguration implements Parcelable {
mServiceFriendlyNames = source.mServiceFriendlyNames;
mAaaServerTrustedNames = source.mAaaServerTrustedNames;
mCarrierId = source.mCarrierId;
+ mSubscriptionId = source.mSubscriptionId;
mIsAutojoinEnabled = source.mIsAutojoinEnabled;
mIsMacRandomizationEnabled = source.mIsMacRandomizationEnabled;
mIsEnhancedMacRandomizationEnabled = source.mIsEnhancedMacRandomizationEnabled;
@@ -641,6 +668,7 @@ public final class PasspointConfiguration implements Parcelable {
dest.writeBoolean(mIsMacRandomizationEnabled);
dest.writeBoolean(mIsEnhancedMacRandomizationEnabled);
dest.writeInt(mMeteredOverride);
+ dest.writeInt(mSubscriptionId);
}
@Override
@@ -671,6 +699,7 @@ public final class PasspointConfiguration implements Parcelable {
&& mUsageLimitDataLimit == that.mUsageLimitDataLimit
&& mUsageLimitTimeLimitInMinutes == that.mUsageLimitTimeLimitInMinutes
&& mCarrierId == that.mCarrierId
+ && mSubscriptionId == that.mSubscriptionId
&& mIsAutojoinEnabled == that.mIsAutojoinEnabled
&& mIsMacRandomizationEnabled == that.mIsMacRandomizationEnabled
&& mIsEnhancedMacRandomizationEnabled == that.mIsEnhancedMacRandomizationEnabled
@@ -686,7 +715,7 @@ public final class PasspointConfiguration implements Parcelable {
mSubscriptionExpirationTimeMillis, mUsageLimitUsageTimePeriodInMinutes,
mUsageLimitStartTimeInMillis, mUsageLimitDataLimit, mUsageLimitTimeLimitInMinutes,
mServiceFriendlyNames, mCarrierId, mIsAutojoinEnabled, mIsMacRandomizationEnabled,
- mIsEnhancedMacRandomizationEnabled, mMeteredOverride);
+ mIsEnhancedMacRandomizationEnabled, mMeteredOverride, mSubscriptionId);
}
@Override
@@ -740,6 +769,7 @@ public final class PasspointConfiguration implements Parcelable {
builder.append("ServiceFriendlyNames: ").append(mServiceFriendlyNames);
}
builder.append("CarrierId:" + mCarrierId);
+ builder.append("SubscriptionId:" + mSubscriptionId);
builder.append("IsAutojoinEnabled:" + mIsAutojoinEnabled);
builder.append("mIsMacRandomizationEnabled:" + mIsMacRandomizationEnabled);
builder.append("mIsEnhancedMacRandomizationEnabled:" + mIsEnhancedMacRandomizationEnabled);
@@ -853,6 +883,7 @@ public final class PasspointConfiguration implements Parcelable {
config.mIsMacRandomizationEnabled = in.readBoolean();
config.mIsEnhancedMacRandomizationEnabled = in.readBoolean();
config.mMeteredOverride = in.readInt();
+ config.mSubscriptionId = in.readInt();
return config;
}
diff --git a/wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java b/wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java
index fb58d3f99883..91d25f94be53 100644
--- a/wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java
+++ b/wifi/java/android/net/wifi/nl80211/WifiNl80211Manager.java
@@ -153,15 +153,23 @@ public class WifiNl80211Manager {
@Override
public void OnScanResultReady() {
Log.d(TAG, "Scan result ready event");
- Binder.clearCallingIdentity();
- mExecutor.execute(() -> mCallback.onScanResultReady());
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onScanResultReady());
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
@Override
public void OnScanFailed() {
Log.d(TAG, "Scan failed event");
- Binder.clearCallingIdentity();
- mExecutor.execute(() -> mCallback.onScanFailed());
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onScanFailed());
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
}
@@ -345,15 +353,23 @@ public class WifiNl80211Manager {
@Override
public void OnPnoNetworkFound() {
Log.d(TAG, "Pno scan result event");
- Binder.clearCallingIdentity();
- mExecutor.execute(() -> mCallback.onScanResultReady());
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onScanResultReady());
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
@Override
public void OnPnoScanFailed() {
Log.d(TAG, "Pno Scan failed event");
- Binder.clearCallingIdentity();
- mExecutor.execute(() -> mCallback.onScanFailed());
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onScanFailed());
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
}
@@ -376,15 +392,24 @@ public class WifiNl80211Manager {
+ client.getMacAddress() + " isConnected: " + isConnected);
}
- Binder.clearCallingIdentity();
- mExecutor.execute(() -> mSoftApListener.onConnectedClientsChanged(client, isConnected));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(
+ () -> mSoftApListener.onConnectedClientsChanged(client, isConnected));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
@Override
public void onSoftApChannelSwitched(int frequency, int bandwidth) {
- Binder.clearCallingIdentity();
- mExecutor.execute(() -> mSoftApListener.onSoftApChannelSwitched(frequency,
- toFrameworkBandwidth(bandwidth)));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mSoftApListener.onSoftApChannelSwitched(frequency,
+ toFrameworkBandwidth(bandwidth)));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
private @WifiAnnotations.Bandwidth int toFrameworkBandwidth(int bandwidth) {
@@ -437,8 +462,12 @@ public class WifiNl80211Manager {
if (mVerboseLoggingEnabled) {
Log.e(TAG, "Timed out waiting for ACK");
}
- Binder.clearCallingIdentity();
- mExecutor.execute(() -> mCallback.onFailure(SEND_MGMT_FRAME_ERROR_TIMEOUT));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onFailure(SEND_MGMT_FRAME_ERROR_TIMEOUT));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
});
mWasCalled = false;
@@ -453,8 +482,12 @@ public class WifiNl80211Manager {
// post to main thread
mEventHandler.post(() -> runIfFirstCall(() -> {
mAlarmManager.cancel(mTimeoutCallback);
- Binder.clearCallingIdentity();
- mExecutor.execute(() -> mCallback.onAck(elapsedTimeMs));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onAck(elapsedTimeMs));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}));
}
@@ -464,8 +497,12 @@ public class WifiNl80211Manager {
// post to main thread
mEventHandler.post(() -> runIfFirstCall(() -> {
mAlarmManager.cancel(mTimeoutCallback);
- Binder.clearCallingIdentity();
- mExecutor.execute(() -> mCallback.onFailure(reason));
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mCallback.onFailure(reason));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}));
}
}
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 8af75002c029..b82c67b658aa 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -48,6 +48,7 @@ import org.junit.Test;
*/
@SmallTest
public class WifiConfigurationTest {
+ private static final String TEST_PASSPOINT_UNIQUE_ID = "uniqueId";
@Before
public void setUp() {
@@ -73,6 +74,8 @@ public class WifiConfigurationTest {
config.fromWifiNetworkSuggestion = true;
config.setRandomizedMacAddress(MacAddressUtils.createRandomUnicastAddress());
MacAddress macBeforeParcel = config.getRandomizedMacAddress();
+ config.subscriptionId = 1;
+ config.carrierId = 1189;
Parcel parcelW = Parcel.obtain();
config.writeToParcel(parcelW, 0);
byte[] bytes = parcelW.marshall();
@@ -389,6 +392,79 @@ public class WifiConfigurationTest {
}
/**
+ * Verifies that getMacRandomKey returns the correct String for networks of
+ * various different security types, the result should be stable.
+ */
+ @Test
+ public void testGetMacRandomKeyString() {
+ WifiConfiguration config = new WifiConfiguration();
+ final String mSsid = "TestAP";
+ config.SSID = mSsid;
+
+ // Test various combinations
+ config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
+ assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.WPA_PSK],
+ config.getMacRandomKey());
+
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
+ assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.WPA_EAP],
+ config.getMacRandomKey());
+
+ config.wepKeys[0] = "TestWep";
+ config.allowedKeyManagement.clear();
+ assertEquals(mSsid + "WEP", config.getMacRandomKey());
+
+ // set WEP key and give a valid index.
+ config.wepKeys[0] = null;
+ config.wepKeys[2] = "TestWep";
+ config.wepTxKeyIndex = 2;
+ config.allowedKeyManagement.clear();
+ assertEquals(mSsid + "WEP", config.getMacRandomKey());
+
+ // set WEP key but does not give a valid index.
+ config.wepKeys[0] = null;
+ config.wepKeys[2] = "TestWep";
+ config.wepTxKeyIndex = 0;
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.OWE);
+ assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.OWE], config.getMacRandomKey());
+
+ config.wepKeys[0] = null;
+ config.wepTxKeyIndex = 0;
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.OWE);
+ assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.OWE], config.getMacRandomKey());
+
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.SAE);
+ assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.SAE], config.getMacRandomKey());
+
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.SUITE_B_192);
+ assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.SUITE_B_192],
+ config.getMacRandomKey());
+
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.NONE);
+ assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.NONE], config.getMacRandomKey());
+
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.WAPI_PSK);
+ assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.WAPI_PSK],
+ config.getMacRandomKey());
+
+ config.allowedKeyManagement.clear();
+ config.allowedKeyManagement.set(KeyMgmt.WAPI_CERT);
+ assertEquals(mSsid + KeyMgmt.strings[KeyMgmt.WAPI_CERT],
+ config.getMacRandomKey());
+
+ config.allowedKeyManagement.clear();
+ config.setPasspointUniqueId(TEST_PASSPOINT_UNIQUE_ID);
+ assertEquals(TEST_PASSPOINT_UNIQUE_ID, config.getMacRandomKey());
+ }
+
+ /**
* Ensure that the {@link NetworkSelectionStatus.DisableReasonInfo}s are populated in
* {@link NetworkSelectionStatus#DISABLE_REASON_INFOS} for reason codes from 0 to
* {@link NetworkSelectionStatus#NETWORK_SELECTION_DISABLED_MAX} - 1.
diff --git a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
index 6e08ca42f25f..3f9ce5b675ff 100644
--- a/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiNetworkSuggestionTest.java
@@ -764,6 +764,32 @@ public class WifiNetworkSuggestionTest {
}
/**
+ * Verify that the builder creates the appropriate SIM credential suggestion with SubId, also
+ * verify {@link WifiNetworkSuggestion#equals(Object)} consider suggestion with different SubId
+ * as different suggestions.
+ */
+ @Test
+ public void testSimCredentialNetworkWithSubId() {
+ assumeTrue(SdkLevelUtil.isAtLeastS());
+ WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
+ enterpriseConfig.setEapMethod(WifiEnterpriseConfig.Eap.SIM);
+ enterpriseConfig.setPhase2Method(WifiEnterpriseConfig.Phase2.NONE);
+ WifiNetworkSuggestion suggestion1 = new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setWpa2EnterpriseConfig(enterpriseConfig)
+ .setSubscriptionId(1)
+ .build();
+ assertEquals(1, suggestion1.getSubscriptionId());
+ WifiNetworkSuggestion suggestion2 = new WifiNetworkSuggestion.Builder()
+ .setSsid(TEST_SSID)
+ .setWpa2EnterpriseConfig(enterpriseConfig)
+ .setSubscriptionId(2)
+ .build();
+ assertEquals(2, suggestion2.getSubscriptionId());
+ assertNotEquals(suggestion1, suggestion2);
+ }
+
+ /**
* Check that parcel marshalling/unmarshalling works
*/
@Test
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointTestUtils.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointTestUtils.java
index 8d55acb87f15..5830a1e84e13 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointTestUtils.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointTestUtils.java
@@ -30,6 +30,7 @@ import java.util.Map;
public class PasspointTestUtils {
private static final int CERTIFICATE_FINGERPRINT_BYTES = 32;
+ private static final int TEST_SUB_ID = 1;
/**
* Utility function for creating a {@link android.net.wifi.hotspot2.pps.HomeSP}.
@@ -156,6 +157,7 @@ public class PasspointTestUtils {
friendlyNames.put("en", "ServiceName1");
friendlyNames.put("kr", "ServiceName2");
config.setServiceFriendlyNames(friendlyNames);
+ config.setSubscriptionId(TEST_SUB_ID);
return config;
}