summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt1
-rw-r--r--api/removed.txt13
-rw-r--r--api/system-current.txt10
-rw-r--r--api/system-removed.txt9
-rw-r--r--api/test-current.txt7
-rw-r--r--cmds/statsd/src/atoms.proto3
-rw-r--r--cmds/statsd/src/external/GpuStatsPuller.cpp1
-rw-r--r--cmds/statsd/tests/external/GpuStatsPuller_test.cpp5
-rw-r--r--core/java/android/app/ActivityView.java1
-rw-r--r--core/java/android/app/AppOpsManager.java31
-rw-r--r--core/java/android/app/ApplicationPackageManager.java87
-rw-r--r--core/java/android/app/IActivityTaskManager.aidl9
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java78
-rw-r--r--core/java/android/app/servertransaction/NewIntentItem.java15
-rw-r--r--core/java/android/content/Context.java2
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java3
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl30
-rw-r--r--core/java/android/content/pm/PackageManager.java3
-rw-r--r--core/java/android/content/pm/PackageManagerInternal.java7
-rw-r--r--core/java/android/content/res/AssetManager.java7
-rw-r--r--core/java/android/hardware/face/FaceManager.java16
-rw-r--r--core/java/android/hardware/face/IFaceService.aidl11
-rw-r--r--core/java/android/hardware/hdmi/HdmiControlManager.java81
-rw-r--r--core/java/android/os/BatteryStats.java14
-rw-r--r--core/java/android/os/RedactingFileDescriptor.java26
-rw-r--r--core/java/android/os/ZygoteProcess.java10
-rw-r--r--core/java/android/permission/IPermissionManager.aidl16
-rw-r--r--core/java/android/provider/DeviceConfig.java20
-rw-r--r--core/java/android/provider/Settings.java21
-rw-r--r--core/java/android/view/SurfaceView.java230
-rw-r--r--core/java/android/view/ThreadedRenderer.java5
-rw-r--r--core/java/android/view/View.java2
-rw-r--r--core/java/android/view/ViewTreeObserver.java2
-rw-r--r--core/java/android/view/accessibility/AccessibilityRecord.java16
-rw-r--r--core/java/android/view/inputmethod/InputMethodSystemProperty.java26
-rw-r--r--core/java/android/view/textclassifier/ActionsModelParamsSupplier.java4
-rw-r--r--core/java/android/view/textclassifier/ConversationActions.java26
-rw-r--r--core/java/android/view/textclassifier/SelectionEvent.java22
-rw-r--r--core/java/android/view/textclassifier/SystemTextClassifier.java13
-rw-r--r--core/java/android/view/textclassifier/TextClassification.java26
-rw-r--r--core/java/android/view/textclassifier/TextClassificationContext.java29
-rw-r--r--core/java/android/view/textclassifier/TextLanguage.java26
-rw-r--r--core/java/android/view/textclassifier/TextLinks.java26
-rw-r--r--core/java/android/view/textclassifier/TextSelection.java26
-rw-r--r--core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java24
-rw-r--r--core/java/android/widget/AnalogClock.java38
-rw-r--r--core/java/android/widget/DateTimeView.java125
-rw-r--r--core/java/android/widget/HorizontalScrollView.java2
-rw-r--r--core/java/android/widget/ScrollView.java2
-rw-r--r--core/java/android/widget/TextView.java12
-rw-r--r--core/java/com/android/internal/app/PlatLogoActivity.java505
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java3
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java9
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java7
-rw-r--r--core/java/com/android/internal/policy/PipSnapAlgorithm.java10
-rw-r--r--core/java/com/android/internal/policy/ScreenDecorationsUtils.java9
-rw-r--r--core/jni/Android.bp22
-rw-r--r--core/jni/LayoutlibLoader.cpp6
-rw-r--r--core/jni/android_os_Debug.cpp2
-rw-r--r--core/jni/android_view_InputEventSender.cpp1
-rw-r--r--core/jni/android_view_MotionEvent.cpp1
-rw-r--r--core/jni/android_view_ThreadedRenderer.cpp1
-rw-r--r--core/proto/android/server/jobscheduler.proto17
-rw-r--r--core/res/AndroidManifest.xml99
-rw-r--r--core/res/res/anim/lock_screen_behind_enter_subtle.xml2
-rw-r--r--core/res/res/drawable-nodpi/android_logotype.xml42
-rw-r--r--core/res/res/drawable-nodpi/platlogo.xml26
-rw-r--r--core/res/res/layout/platlogo_layout.xml50
-rw-r--r--core/res/res/values-af/strings.xml17
-rw-r--r--core/res/res/values-am/strings.xml17
-rw-r--r--core/res/res/values-ar/strings.xml17
-rw-r--r--core/res/res/values-as/strings.xml17
-rw-r--r--core/res/res/values-az/strings.xml17
-rw-r--r--core/res/res/values-b+sr+Latn/strings.xml17
-rw-r--r--core/res/res/values-be/strings.xml17
-rw-r--r--core/res/res/values-bg/strings.xml17
-rw-r--r--core/res/res/values-bn/strings.xml17
-rw-r--r--core/res/res/values-bs/strings.xml25
-rw-r--r--core/res/res/values-ca/strings.xml17
-rw-r--r--core/res/res/values-cs/strings.xml17
-rw-r--r--core/res/res/values-da/strings.xml17
-rw-r--r--core/res/res/values-de/strings.xml35
-rw-r--r--core/res/res/values-el/strings.xml17
-rw-r--r--core/res/res/values-en-rAU/strings.xml17
-rw-r--r--core/res/res/values-en-rCA/strings.xml17
-rw-r--r--core/res/res/values-en-rGB/strings.xml17
-rw-r--r--core/res/res/values-en-rIN/strings.xml17
-rw-r--r--core/res/res/values-en-rXC/strings.xml2
-rw-r--r--core/res/res/values-es-rUS/strings.xml21
-rw-r--r--core/res/res/values-es/strings.xml17
-rw-r--r--core/res/res/values-et/strings.xml17
-rw-r--r--core/res/res/values-eu/strings.xml29
-rw-r--r--core/res/res/values-fa/strings.xml17
-rw-r--r--core/res/res/values-fi/strings.xml17
-rw-r--r--core/res/res/values-fr-rCA/strings.xml17
-rw-r--r--core/res/res/values-fr/strings.xml17
-rw-r--r--core/res/res/values-gl/strings.xml17
-rw-r--r--core/res/res/values-gu/strings.xml17
-rw-r--r--core/res/res/values-hi/strings.xml25
-rw-r--r--core/res/res/values-hr/strings.xml17
-rw-r--r--core/res/res/values-hu/strings.xml17
-rw-r--r--core/res/res/values-hy/strings.xml43
-rw-r--r--core/res/res/values-in/strings.xml19
-rw-r--r--core/res/res/values-is/strings.xml17
-rw-r--r--core/res/res/values-it/strings.xml75
-rw-r--r--core/res/res/values-iw/strings.xml17
-rw-r--r--core/res/res/values-ja/strings.xml17
-rw-r--r--core/res/res/values-ka/strings.xml17
-rw-r--r--core/res/res/values-kk/strings.xml17
-rw-r--r--core/res/res/values-km/strings.xml17
-rw-r--r--core/res/res/values-kn/strings.xml17
-rw-r--r--core/res/res/values-ko/strings.xml17
-rw-r--r--core/res/res/values-ky/strings.xml17
-rw-r--r--core/res/res/values-lo/strings.xml17
-rw-r--r--core/res/res/values-lt/strings.xml17
-rw-r--r--core/res/res/values-lv/strings.xml17
-rw-r--r--core/res/res/values-mk/strings.xml17
-rw-r--r--core/res/res/values-ml/strings.xml17
-rw-r--r--core/res/res/values-mn/strings.xml17
-rw-r--r--core/res/res/values-mr/strings.xml17
-rw-r--r--core/res/res/values-ms/strings.xml17
-rw-r--r--core/res/res/values-my/strings.xml17
-rw-r--r--core/res/res/values-nb/strings.xml17
-rw-r--r--core/res/res/values-ne/strings.xml19
-rw-r--r--core/res/res/values-nl/strings.xml17
-rw-r--r--core/res/res/values-or/strings.xml17
-rw-r--r--core/res/res/values-pa/strings.xml17
-rw-r--r--core/res/res/values-pl/strings.xml17
-rw-r--r--core/res/res/values-pt-rBR/strings.xml17
-rw-r--r--core/res/res/values-pt-rPT/strings.xml17
-rw-r--r--core/res/res/values-pt/strings.xml17
-rw-r--r--core/res/res/values-ro/strings.xml17
-rw-r--r--core/res/res/values-ru/strings.xml17
-rw-r--r--core/res/res/values-si/strings.xml17
-rw-r--r--core/res/res/values-sk/strings.xml17
-rw-r--r--core/res/res/values-sl/strings.xml17
-rw-r--r--core/res/res/values-sq/strings.xml17
-rw-r--r--core/res/res/values-sr/strings.xml17
-rw-r--r--core/res/res/values-sv/strings.xml17
-rw-r--r--core/res/res/values-sw/strings.xml17
-rw-r--r--core/res/res/values-ta/strings.xml17
-rw-r--r--core/res/res/values-te/strings.xml17
-rw-r--r--core/res/res/values-th/strings.xml17
-rw-r--r--core/res/res/values-tl/strings.xml17
-rw-r--r--core/res/res/values-tr/strings.xml17
-rw-r--r--core/res/res/values-uk/strings.xml19
-rw-r--r--core/res/res/values-ur/strings.xml17
-rw-r--r--core/res/res/values-uz/strings.xml17
-rw-r--r--core/res/res/values-vi/strings.xml17
-rw-r--r--core/res/res/values-zh-rCN/strings.xml21
-rw-r--r--core/res/res/values-zh-rHK/strings.xml17
-rw-r--r--core/res/res/values-zh-rTW/strings.xml17
-rw-r--r--core/res/res/values-zu/strings.xml17
-rw-r--r--core/res/res/values/config.xml12
-rw-r--r--core/res/res/values/dimens.xml18
-rw-r--r--core/res/res/values/strings.xml2
-rw-r--r--core/res/res/values/symbols.xml12
-rw-r--r--core/tests/coretests/src/android/app/activity/ActivityThreadTest.java35
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java6
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java2
-rw-r--r--core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java21
-rw-r--r--core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java80
-rw-r--r--core/tests/coretests/src/android/view/textclassifier/logging/SmartSelectionEventTrackerTest.java43
-rw-r--r--data/etc/hiddenapi-package-whitelist.xml8
-rw-r--r--data/etc/privapp-permissions-platform.xml2
-rw-r--r--keystore/java/android/security/KeyStore.java2
-rw-r--r--libs/hwui/Android.bp8
-rw-r--r--libs/hwui/Animator.cpp2
-rw-r--r--libs/hwui/RootRenderNode.cpp22
-rw-r--r--libs/hwui/RootRenderNode.h5
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp152
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.h50
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp2
-rwxr-xr-xlibs/hwui/tests/scripts/skp-capture.sh70
-rw-r--r--location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java687
-rw-r--r--media/apex/java/android/media/MediaController2.java22
-rw-r--r--media/apex/java/android/media/MediaSession2.java29
-rw-r--r--media/apex/java/android/media/MediaSession2Service.java13
-rw-r--r--media/apex/java/android/media/Session2Command.java15
-rw-r--r--media/apex/java/android/media/Session2CommandGroup.java14
-rw-r--r--media/apex/java/android/media/Session2Token.java10
-rw-r--r--media/java/android/media/IMediaRoute2Provider.aidl7
-rw-r--r--media/java/android/media/IMediaRoute2ProviderClient.aidl1
-rw-r--r--media/java/android/media/IMediaRouter2Manager.aidl4
-rw-r--r--media/java/android/media/IMediaRouterService.aidl12
-rw-r--r--media/java/android/media/MediaMetadataRetriever.java2
-rw-r--r--media/java/android/media/MediaRoute2Info.java27
-rw-r--r--media/java/android/media/MediaRoute2ProviderService.java61
-rw-r--r--media/java/android/media/MediaRouter2Manager.java87
-rw-r--r--media/java/android/media/ThumbnailUtils.java10
-rw-r--r--media/java/android/media/session/ISessionManager.aidl3
-rw-r--r--media/java/android/media/session/MediaSessionManager.java194
-rw-r--r--media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java22
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java98
-rw-r--r--packages/CarSystemUI/Android.bp2
-rw-r--r--packages/CarSystemUI/res/values-night/colors.xml3
-rw-r--r--packages/CarSystemUI/res/values/colors.xml2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java4
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java3
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java20
-rw-r--r--packages/EasterEgg/AndroidManifest.xml40
-rw-r--r--packages/EasterEgg/res/drawable/icon_bg.xml2
-rw-r--r--packages/EasterEgg/res/drawable/p_icon.xml (renamed from packages/EasterEgg/res/drawable/icon.xml)0
-rw-r--r--packages/EasterEgg/res/drawable/pixel_bg.xml27
-rw-r--r--packages/EasterEgg/res/drawable/q.xml27
-rw-r--r--packages/EasterEgg/res/drawable/q_icon.xml19
-rw-r--r--packages/EasterEgg/res/drawable/q_smaller.xml23
-rw-r--r--packages/EasterEgg/res/layout/activity_quares.xml46
-rw-r--r--packages/EasterEgg/res/values-night/q_colors.xml22
-rw-r--r--packages/EasterEgg/res/values/q_colors.xml31
-rw-r--r--packages/EasterEgg/res/values/q_puzzles.xml214
-rw-r--r--packages/EasterEgg/res/values/strings.xml11
-rw-r--r--packages/EasterEgg/res/values/styles.xml12
-rw-r--r--packages/EasterEgg/src/com/android/egg/quares/Quare.kt168
-rw-r--r--packages/EasterEgg/src/com/android/egg/quares/QuaresActivity.kt312
-rw-r--r--packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml2
-rw-r--r--packages/SettingsLib/AppPreference/res/layout/preference_app.xml1
-rw-r--r--packages/SettingsLib/OWNERS16
-rw-r--r--packages/SettingsLib/res/values-en-rAU/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-en-rCA/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-en-rGB/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-en-rIN/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-in/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-sq/strings.xml2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java2
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java25
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java19
-rw-r--r--packages/Shell/AndroidManifest.xml2
-rw-r--r--packages/SystemUI/AndroidManifest.xml4
-rw-r--r--packages/SystemUI/docs/dagger.md9
-rw-r--r--packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackView.java11
-rw-r--r--packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java5
-rw-r--r--packages/SystemUI/res/values/config.xml6
-rw-r--r--packages/SystemUI/res/values/ids.xml6
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java36
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java37
-rw-r--r--packages/SystemUI/src/com/android/systemui/ContextComponentHelper.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/ContextComponentResolver.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/ImageWallpaper.java48
-rw-r--r--packages/SystemUI/src/com/android/systemui/ServiceBinder.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java76
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIApplication.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIFactory.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java68
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/ui/CircularCornerPathRenderer.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/ui/PathSpecCornerPathRenderer.java124
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/ui/PerimeterPathGuide.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFactory.java44
-rw-r--r--packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java242
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeService.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java61
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt147
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java129
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java64
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java62
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java12
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java50
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java60
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java33
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java10
-rw-r--r--packages/overlays/AccentColorBlackOverlay/Android.mk2
-rw-r--r--packages/overlays/AccentColorCinnamonOverlay/Android.mk2
-rw-r--r--packages/overlays/AccentColorGreenOverlay/Android.mk2
-rw-r--r--packages/overlays/AccentColorOceanOverlay/Android.mk2
-rw-r--r--packages/overlays/AccentColorOrchidOverlay/Android.mk2
-rw-r--r--packages/overlays/AccentColorPurpleOverlay/Android.mk2
-rw-r--r--packages/overlays/AccentColorSpaceOverlay/Android.mk2
-rw-r--r--packages/overlays/DisplayCutoutEmulationCornerOverlay/Android.mk2
-rw-r--r--packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.mk2
-rw-r--r--packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.mk2
-rw-r--r--packages/overlays/DisplayCutoutEmulationTallOverlay/Android.mk2
-rw-r--r--packages/overlays/DisplayCutoutEmulationWideOverlay/Android.mk2
-rw-r--r--packages/overlays/FontNotoSerifSourceOverlay/Android.mk2
-rw-r--r--packages/overlays/IconPackCircularAndroidOverlay/Android.mk2
-rw-r--r--packages/overlays/IconPackCircularLauncherOverlay/Android.mk2
-rw-r--r--packages/overlays/IconPackCircularSettingsOverlay/Android.mk2
-rw-r--r--packages/overlays/IconPackCircularSystemUIOverlay/Android.mk2
-rw-r--r--packages/overlays/IconPackCircularThemePickerOverlay/Android.mk2
-rw-r--r--packages/overlays/IconPackFilledAndroidOverlay/Android.mk2
-rw-r--r--packages/overlays/IconPackFilledLauncherOverlay/Android.mk2
-rw-r--r--packages/overlays/IconPackFilledSettingsOverlay/Android.mk2
-rw-r--r--packages/overlays/IconPackFilledSystemUIOverlay/Android.mk2
-rw-r--r--packages/overlays/IconPackFilledThemePickerOverlay/Android.mk2
-rw-r--r--packages/overlays/IconPackRoundedAndroidOverlay/Android.mk2
-rw-r--r--packages/overlays/IconPackRoundedLauncherOverlay/Android.mk2
-rw-r--r--packages/overlays/IconPackRoundedSettingsOverlay/Android.mk2
-rw-r--r--packages/overlays/IconPackRoundedSystemUIOverlay/Android.mk2
-rw-r--r--packages/overlays/IconPackRoundedThemePickerOverlay/Android.mk2
-rw-r--r--packages/overlays/IconShapeRoundedRectOverlay/Android.mk2
-rw-r--r--packages/overlays/IconShapeSquareOverlay/Android.mk2
-rw-r--r--packages/overlays/IconShapeSquircleOverlay/Android.mk2
-rw-r--r--packages/overlays/IconShapeTeardropOverlay/Android.mk2
-rw-r--r--packages/overlays/NavigationBarMode2ButtonOverlay/Android.mk2
-rw-r--r--packages/overlays/NavigationBarMode3ButtonOverlay/Android.mk2
-rw-r--r--packages/overlays/NavigationBarModeGesturalOverlay/Android.mk2
-rw-r--r--packages/overlays/NavigationBarModeGesturalOverlayExtraWideBack/Android.mk2
-rw-r--r--packages/overlays/NavigationBarModeGesturalOverlayNarrowBack/Android.mk2
-rw-r--r--packages/overlays/NavigationBarModeGesturalOverlayWideBack/Android.mk2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java5
-rw-r--r--services/autofill/java/com/android/server/autofill/RemoteFillService.java5
-rw-r--r--services/backup/java/com/android/server/backup/encryption/chunking/DecryptedChunkFileOutput.java87
-rw-r--r--services/backup/java/com/android/server/backup/encryption/keys/TertiaryKeyGenerator.java2
-rw-r--r--services/backup/java/com/android/server/backup/encryption/tasks/BackupEncrypter.java90
-rw-r--r--services/backup/java/com/android/server/backup/encryption/tasks/BackupStreamEncrypter.java127
-rw-r--r--services/backup/java/com/android/server/backup/encryption/tasks/DecryptedChunkOutput.java54
-rw-r--r--services/backup/java/com/android/server/backup/encryption/tasks/EncryptedRestoreException.java32
-rw-r--r--services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java27
-rw-r--r--services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java59
-rw-r--r--services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java13
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java294
-rw-r--r--services/core/java/com/android/server/MmsServiceBroker.java22
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java10
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java10
-rw-r--r--services/core/java/com/android/server/Watchdog.java4
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueue.java4
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java480
-rw-r--r--services/core/java/com/android/server/audio/SoundEffectsHelper.java521
-rw-r--r--services/core/java/com/android/server/biometrics/face/FaceService.java43
-rw-r--r--services/core/java/com/android/server/compat/CompatChange.java139
-rw-r--r--services/core/java/com/android/server/compat/CompatConfig.java164
-rw-r--r--services/core/java/com/android/server/compat/PlatformCompat.java67
-rw-r--r--services/core/java/com/android/server/connectivity/Tethering.java63
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java6
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java8
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java30
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java3
-rw-r--r--services/core/java/com/android/server/infra/AbstractPerUserSystemService.java12
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java10
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodUtils.java21
-rw-r--r--services/core/java/com/android/server/job/JobSchedulerService.java128
-rw-r--r--services/core/java/com/android/server/job/controllers/JobStatus.java26
-rw-r--r--services/core/java/com/android/server/location/AbstractLocationProvider.java59
-rw-r--r--services/core/java/com/android/server/location/GeofenceManager.java26
-rw-r--r--services/core/java/com/android/server/location/GnssLocationProvider.java33
-rw-r--r--services/core/java/com/android/server/location/LocationProviderProxy.java8
-rw-r--r--services/core/java/com/android/server/location/MockProvider.java7
-rw-r--r--services/core/java/com/android/server/location/PassiveProvider.java8
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java58
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java47
-rw-r--r--services/core/java/com/android/server/media/MediaRouterService.java4
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java172
-rw-r--r--services/core/java/com/android/server/net/watchlist/NetworkWatchlistShellCommand.java11
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java121
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecord.java32
-rw-r--r--services/core/java/com/android/server/notification/NotificationUsageStats.java18
-rw-r--r--services/core/java/com/android/server/pm/ApexManager.java728
-rw-r--r--services/core/java/com/android/server/pm/BackgroundDexOptService.java15
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java118
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java15
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java23
-rw-r--r--services/core/java/com/android/server/pm/TEST_MAPPING8
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java14
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java300
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java40
-rw-r--r--services/core/java/com/android/server/pm/permission/TEST_MAPPING3
-rw-r--r--services/core/java/com/android/server/role/RoleManagerService.java17
-rw-r--r--services/core/java/com/android/server/role/RoleUserState.java7
-rw-r--r--services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java126
-rw-r--r--services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java108
-rw-r--r--services/core/java/com/android/server/textservices/LazyIntToIntMap.java64
-rw-r--r--services/core/java/com/android/server/textservices/TextServicesManagerService.java54
-rw-r--r--services/core/java/com/android/server/updates/CertificateTransparencyLogInstallReceiver.java29
-rw-r--r--services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java42
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java12
-rw-r--r--services/core/java/com/android/server/wm/ActivityDisplay.java93
-rw-r--r--services/core/java/com/android/server/wm/ActivityMetricsLogger.java12
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java32
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java8
-rw-r--r--services/core/java/com/android/server/wm/ActivityStackSupervisor.java8
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java8
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java135
-rw-r--r--services/core/java/com/android/server/wm/AppWarnings.java16
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java39
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java65
-rw-r--r--services/core/java/com/android/server/wm/DockedStackDividerController.java4
-rw-r--r--services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java100
-rw-r--r--services/core/java/com/android/server/wm/InputManagerCallback.java2
-rw-r--r--services/core/java/com/android/server/wm/PinnedStackController.java14
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimationController.java5
-rw-r--r--services/core/java/com/android/server/wm/RootActivityContainer.java15
-rw-r--r--services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java87
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java33
-rw-r--r--services/core/java/com/android/server/wm/utils/RegionUtils.java13
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp446
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java37
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java15
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/chunking/DecryptedChunkFileOutputTest.java134
-rw-r--r--services/robotests/backup/src/com/android/server/backup/encryption/tasks/BackupStreamEncrypterTest.java262
-rw-r--r--services/robotests/backup/src/com/android/server/backup/testing/RandomInputStream.java78
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java84
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java145
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/OverlayPackagesProviderTest.java14
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java12
-rw-r--r--services/tests/servicestests/src/com/android/server/textservices/LazyIntToIntMapTest.java92
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java100
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java65
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java179
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java26
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java3
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java2
-rw-r--r--startop/apps/ColorChanging/.gitignore13
-rw-r--r--startop/apps/ColorChanging/.idea/encodings.xml4
-rw-r--r--startop/apps/ColorChanging/.idea/gradle.xml15
-rw-r--r--startop/apps/ColorChanging/.idea/misc.xml9
-rw-r--r--startop/apps/ColorChanging/.idea/runConfigurations.xml12
-rw-r--r--startop/apps/ColorChanging/README.md5
-rw-r--r--startop/apps/ColorChanging/app/.gitignore1
-rw-r--r--startop/apps/ColorChanging/app/build.gradle29
-rw-r--r--startop/apps/ColorChanging/app/proguard-rules.pro21
-rw-r--r--startop/apps/ColorChanging/app/src/androidTest/java/com/android/startop/colorchanging/ExampleInstrumentedTest.java27
-rw-r--r--startop/apps/ColorChanging/app/src/main/AndroidManifest.xml21
-rw-r--r--startop/apps/ColorChanging/app/src/main/java/com/android/startop/colorchanging/MainActivity.java91
-rw-r--r--startop/apps/ColorChanging/app/src/main/res/drawable-v24/ic_launcher_foreground.xml34
-rw-r--r--startop/apps/ColorChanging/app/src/main/res/drawable/ic_launcher_background.xml170
-rw-r--r--startop/apps/ColorChanging/app/src/main/res/layout/activity_main.xml132
-rw-r--r--startop/apps/ColorChanging/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml5
-rw-r--r--startop/apps/ColorChanging/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml5
-rw-r--r--startop/apps/ColorChanging/app/src/main/res/mipmap-hdpi/ic_launcher.pngbin0 -> 2963 bytes
-rw-r--r--startop/apps/ColorChanging/app/src/main/res/mipmap-hdpi/ic_launcher_round.pngbin0 -> 4905 bytes
-rw-r--r--startop/apps/ColorChanging/app/src/main/res/mipmap-mdpi/ic_launcher.pngbin0 -> 2060 bytes
-rw-r--r--startop/apps/ColorChanging/app/src/main/res/mipmap-mdpi/ic_launcher_round.pngbin0 -> 2783 bytes
-rw-r--r--startop/apps/ColorChanging/app/src/main/res/mipmap-xhdpi/ic_launcher.pngbin0 -> 4490 bytes
-rw-r--r--startop/apps/ColorChanging/app/src/main/res/mipmap-xhdpi/ic_launcher_round.pngbin0 -> 6895 bytes
-rw-r--r--startop/apps/ColorChanging/app/src/main/res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 6387 bytes
-rw-r--r--startop/apps/ColorChanging/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.pngbin0 -> 10413 bytes
-rw-r--r--startop/apps/ColorChanging/app/src/main/res/mipmap-xxxhdpi/ic_launcher.pngbin0 -> 9128 bytes
-rw-r--r--startop/apps/ColorChanging/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.pngbin0 -> 15132 bytes
-rw-r--r--startop/apps/ColorChanging/app/src/main/res/values/colors.xml16
-rw-r--r--startop/apps/ColorChanging/app/src/main/res/values/strings.xml3
-rw-r--r--startop/apps/ColorChanging/app/src/main/res/values/styles.xml11
-rw-r--r--startop/apps/ColorChanging/app/src/test/java/com/android/startop/colorchanging/ExampleUnitTest.java17
-rw-r--r--startop/apps/ColorChanging/build.gradle24
-rw-r--r--startop/apps/ColorChanging/gradle.properties20
-rw-r--r--startop/apps/ColorChanging/gradle/wrapper/gradle-wrapper.jarbin0 -> 54329 bytes
-rw-r--r--startop/apps/ColorChanging/gradle/wrapper/gradle-wrapper.properties6
-rwxr-xr-xstartop/apps/ColorChanging/gradlew172
-rw-r--r--startop/apps/ColorChanging/gradlew.bat84
-rw-r--r--startop/apps/ColorChanging/settings.gradle1
-rw-r--r--startop/iorap/TEST_MAPPING (renamed from startop/iorap/DISABLED_TEST_MAPPING)0
-rw-r--r--startop/iorap/tests/AndroidTest.xml22
-rw-r--r--startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt7
-rw-r--r--startop/scripts/app_startup/lib/adb_utils.py48
-rw-r--r--startop/scripts/app_startup/lib/adb_utils_test.py16
-rw-r--r--startop/scripts/app_startup/run_app_with_prefetch.py104
-rw-r--r--startop/scripts/app_startup/run_app_with_prefetch_test.py128
-rw-r--r--startop/scripts/iorap/lib/iorapd_utils.py25
-rw-r--r--startop/scripts/lib/cmd_utils.py14
-rw-r--r--startop/scripts/lib/logcat_utils.py104
-rw-r--r--startop/scripts/lib/logcat_utils_test.py88
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java20
-rw-r--r--telephony/java/com/android/internal/telephony/SmsApplication.java93
-rw-r--r--test-mock/api/test-current.txt2
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java728
-rw-r--r--tests/net/java/com/android/server/connectivity/TetheringTest.java39
-rw-r--r--tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java11
-rw-r--r--tools/aapt2/optimize/ResourcePathShortener.cpp5
-rw-r--r--tools/aapt2/optimize/ResourcePathShortener_test.cpp4
496 files changed, 12023 insertions, 6177 deletions
diff --git a/api/current.txt b/api/current.txt
index 2cfdd872768f..25801cac203e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -38638,6 +38638,7 @@ package android.provider {
field public static final String ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS";
field public static final String ACTION_CAST_SETTINGS = "android.settings.CAST_SETTINGS";
field public static final String ACTION_CHANNEL_NOTIFICATION_SETTINGS = "android.settings.CHANNEL_NOTIFICATION_SETTINGS";
+ field public static final String ACTION_CONDITION_PROVIDER_SETTINGS = "android.settings.ACTION_CONDITION_PROVIDER_SETTINGS";
field public static final String ACTION_DATA_ROAMING_SETTINGS = "android.settings.DATA_ROAMING_SETTINGS";
field public static final String ACTION_DATA_USAGE_SETTINGS = "android.settings.DATA_USAGE_SETTINGS";
field public static final String ACTION_DATE_SETTINGS = "android.settings.DATE_SETTINGS";
diff --git a/api/removed.txt b/api/removed.txt
index 8ebded13b5a4..7b1d241fdd6a 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -23,15 +23,6 @@ package android.app {
}
-package android.app.admin {
-
- public class DevicePolicyManager {
- method @Deprecated @Nullable public android.os.UserHandle createAndInitializeUser(@NonNull android.content.ComponentName, String, String, @NonNull android.content.ComponentName, android.os.Bundle);
- method @Deprecated @Nullable public android.os.UserHandle createUser(@NonNull android.content.ComponentName, String);
- }
-
-}
-
package android.app.slice {
public final class Slice implements android.os.Parcelable {
@@ -104,10 +95,6 @@ package android.content {
package android.content.pm {
- public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
- field @Deprecated public String volumeUuid;
- }
-
public class PackageInfo implements android.os.Parcelable {
field public static final int REQUESTED_PERMISSION_REQUIRED = 1; // 0x1
}
diff --git a/api/system-current.txt b/api/system-current.txt
index ce7df5ecd794..6fcf0559aec6 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3693,8 +3693,18 @@ package android.media.audiopolicy {
package android.media.session {
public final class MediaSessionManager {
+ method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void registerCallback(@NonNull android.media.session.MediaSessionManager.Callback, @Nullable android.os.Handler);
method @RequiresPermission(android.Manifest.permission.SET_MEDIA_KEY_LISTENER) public void setOnMediaKeyListener(android.media.session.MediaSessionManager.OnMediaKeyListener, @Nullable android.os.Handler);
method @RequiresPermission(android.Manifest.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER) public void setOnVolumeKeyLongPressListener(android.media.session.MediaSessionManager.OnVolumeKeyLongPressListener, @Nullable android.os.Handler);
+ method @RequiresPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL) public void unregisterCallback(@NonNull android.media.session.MediaSessionManager.Callback);
+ }
+
+ public abstract static class MediaSessionManager.Callback {
+ ctor public MediaSessionManager.Callback();
+ method public abstract void onAddressedPlayerChanged(android.media.session.MediaSession.Token);
+ method public abstract void onAddressedPlayerChanged(android.content.ComponentName);
+ method public abstract void onMediaKeyEventDispatched(android.view.KeyEvent, android.media.session.MediaSession.Token);
+ method public abstract void onMediaKeyEventDispatched(android.view.KeyEvent, android.content.ComponentName);
}
public static interface MediaSessionManager.OnMediaKeyListener {
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 3e26a9baba19..07b896905986 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -23,15 +23,6 @@ package android.app {
}
-package android.app.admin {
-
- public class DevicePolicyManager {
- method @Deprecated @Nullable public String getDeviceInitializerApp();
- method @Deprecated @Nullable public android.content.ComponentName getDeviceInitializerComponent();
- }
-
-}
-
package android.app.backup {
public class RestoreSession {
diff --git a/api/test-current.txt b/api/test-current.txt
index 14c70e30cea4..050ec520059c 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -700,6 +700,7 @@ package android.content.pm {
}
public abstract class PackageManager {
+ method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void addOnPermissionsChangeListener(@NonNull android.content.pm.PackageManager.OnPermissionsChangedListener);
method public abstract boolean arePermissionsIndividuallyControlled();
method @Nullable @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract String getDefaultBrowserPackageNameAsUser(int);
method @Nullable public String getIncidentReportApproverPackageName();
@@ -713,6 +714,7 @@ package android.content.pm {
method @NonNull public abstract String getSharedSystemSharedLibraryPackageName();
method @Nullable public String getWellbeingPackageName();
method @RequiresPermission("android.permission.GRANT_RUNTIME_PERMISSIONS") public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
+ method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void removeOnPermissionsChangeListener(@NonNull android.content.pm.PackageManager.OnPermissionsChangedListener);
method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS"}) public abstract void updatePermissionFlags(@NonNull String, @NonNull String, int, int, @NonNull android.os.UserHandle);
field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
@@ -735,6 +737,10 @@ package android.content.pm {
field public static final String SYSTEM_SHARED_LIBRARY_SHARED = "android.ext.shared";
}
+ public static interface PackageManager.OnPermissionsChangedListener {
+ method public void onPermissionsChanged(int);
+ }
+
public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
field public static final int FLAG_REMOVED = 2; // 0x2
field public static final int PROTECTION_FLAG_APP_PREDICTOR = 2097152; // 0x200000
@@ -2320,6 +2326,7 @@ package android.provider {
}
public static interface DeviceConfig.WindowManager {
+ field public static final String KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE = "system_gestures_excluded_by_pre_q_sticky_immersive";
field public static final String KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP = "system_gesture_exclusion_limit_dp";
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index ee500d7c362e..ceabd39aee8b 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -6360,6 +6360,9 @@ message GpuStatsAppInfo {
// CPU Vulkan implementation is in use.
optional bool cpu_vulkan_in_use = 6;
+
+ // App is not doing pre-rotation correctly.
+ optional bool false_prerotation = 7;
}
/*
diff --git a/cmds/statsd/src/external/GpuStatsPuller.cpp b/cmds/statsd/src/external/GpuStatsPuller.cpp
index 0d3aca05e0e5..bbdb5405ca05 100644
--- a/cmds/statsd/src/external/GpuStatsPuller.cpp
+++ b/cmds/statsd/src/external/GpuStatsPuller.cpp
@@ -96,6 +96,7 @@ static bool pullGpuStatsAppInfo(const sp<IGpuService>& gpuService,
if (!event->write(int64VectorToProtoByteString(info.vkDriverLoadingTime))) return false;
if (!event->write(int64VectorToProtoByteString(info.angleDriverLoadingTime))) return false;
if (!event->write(info.cpuVulkanInUse)) return false;
+ if (!event->write(info.falsePrerotation)) return false;
event->init();
data->emplace_back(event);
}
diff --git a/cmds/statsd/tests/external/GpuStatsPuller_test.cpp b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
index bdc52b0af34c..e91fb0d4b27c 100644
--- a/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
+++ b/cmds/statsd/tests/external/GpuStatsPuller_test.cpp
@@ -56,8 +56,9 @@ static const int32_t VULKAN_VERSION = 1;
static const int32_t CPU_VULKAN_VERSION = 2;
static const int32_t GLES_VERSION = 3;
static const bool CPU_VULKAN_IN_USE = true;
+static const bool FALSE_PREROTATION = true;
static const size_t NUMBER_OF_VALUES_GLOBAL = 13;
-static const size_t NUMBER_OF_VALUES_APP = 6;
+static const size_t NUMBER_OF_VALUES_APP = 7;
// clang-format on
class MockGpuStatsPuller : public GpuStatsPuller {
@@ -150,6 +151,7 @@ TEST_F(GpuStatsPuller_test, PullGpuStatsAppInfo) {
EXPECT_TRUE(event->write(int64VectorToProtoByteString(vkDriverLoadingTime)));
EXPECT_TRUE(event->write(int64VectorToProtoByteString(angleDriverLoadingTime)));
EXPECT_TRUE(event->write(CPU_VULKAN_IN_USE));
+ EXPECT_TRUE(event->write(FALSE_PREROTATION));
event->init();
inData.emplace_back(event);
MockGpuStatsPuller mockPuller(android::util::GPU_STATS_APP_INFO, &inData);
@@ -168,6 +170,7 @@ TEST_F(GpuStatsPuller_test, PullGpuStatsAppInfo) {
EXPECT_EQ(int64VectorToProtoByteString(angleDriverLoadingTime),
outData[0]->getValues()[4].mValue.str_value);
EXPECT_EQ(CPU_VULKAN_IN_USE, outData[0]->getValues()[5].mValue.int_value);
+ EXPECT_EQ(FALSE_PREROTATION, outData[0]->getValues()[6].mValue.int_value);
}
} // namespace statsd
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 3bf659b663b0..755f0476d9ba 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -120,6 +120,7 @@ public class ActivityView extends ViewGroup {
mActivityTaskManager = ActivityTaskManager.getService();
mSurfaceView = new SurfaceView(context);
+ mSurfaceView.setUseAlpha();
mSurfaceView.setAlpha(0f);
mSurfaceCallback = new SurfaceCallback();
mSurfaceView.getHolder().addCallback(mSurfaceCallback);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 60f1424220f6..fb72e651cebd 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -240,7 +240,8 @@ public class AppOpsManager {
public @interface UidState {}
/**
- * Uid state: The UID is a foreground persistent app.
+ * Uid state: The UID is a foreground persistent app. The lower the UID
+ * state the more important the UID is for the user.
* @hide
*/
@TestApi
@@ -248,7 +249,8 @@ public class AppOpsManager {
public static final int UID_STATE_PERSISTENT = 100;
/**
- * Uid state: The UID is top foreground app.
+ * Uid state: The UID is top foreground app. The lower the UID
+ * state the more important the UID is for the user.
* @hide
*/
@TestApi
@@ -257,6 +259,7 @@ public class AppOpsManager {
/**
* Uid state: The UID is running a foreground service of location type.
+ * The lower the UID state the more important the UID is for the user.
* @hide
*/
@TestApi
@@ -264,7 +267,8 @@ public class AppOpsManager {
public static final int UID_STATE_FOREGROUND_SERVICE_LOCATION = 300;
/**
- * Uid state: The UID is running a foreground service.
+ * Uid state: The UID is running a foreground service. The lower the UID
+ * state the more important the UID is for the user.
* @hide
*/
@TestApi
@@ -279,7 +283,8 @@ public class AppOpsManager {
public static final int UID_STATE_MAX_LAST_NON_RESTRICTED = UID_STATE_FOREGROUND_SERVICE;
/**
- * Uid state: The UID is a foreground app.
+ * Uid state: The UID is a foreground app. The lower the UID
+ * state the more important the UID is for the user.
* @hide
*/
@TestApi
@@ -287,7 +292,8 @@ public class AppOpsManager {
public static final int UID_STATE_FOREGROUND = 500;
/**
- * Uid state: The UID is a background app.
+ * Uid state: The UID is a background app. The lower the UID
+ * state the more important the UID is for the user.
* @hide
*/
@TestApi
@@ -295,7 +301,8 @@ public class AppOpsManager {
public static final int UID_STATE_BACKGROUND = 600;
/**
- * Uid state: The UID is a cached app.
+ * Uid state: The UID is a cached app. The lower the UID
+ * state the more important the UID is for the user.
* @hide
*/
@TestApi
@@ -2507,7 +2514,7 @@ public class AppOpsManager {
}
/**
- * @return The duration of the operation in milliseconds.
+ * @return The duration of the operation in milliseconds. The duration is in wall time.
*/
public long getDuration() {
return getLastDuration(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, OP_FLAGS_ALL);
@@ -2515,7 +2522,7 @@ public class AppOpsManager {
/**
* Return the duration in milliseconds the app accessed this op while
- * in the foreground.
+ * in the foreground. The duration is in wall time.
*
* @param flags The flags which are any combination of
* {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
@@ -2534,7 +2541,7 @@ public class AppOpsManager {
/**
* Return the duration in milliseconds the app accessed this op while
- * in the background.
+ * in the background. The duration is in wall time.
*
* @param flags The flags which are any combination of
* {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
@@ -2553,7 +2560,7 @@ public class AppOpsManager {
/**
* Return the duration in milliseconds the app accessed this op for
- * a given range of UID states.
+ * a given range of UID states. The duration is in wall time.
*
* @param fromUidState The UID state for which to query. Could be one of
* {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
@@ -3968,6 +3975,7 @@ public class AppOpsManager {
/**
* Gets the total duration the app op was accessed (performed) in the foreground.
+ * The duration is in wall time.
*
* @param flags The flags which are any combination of
* {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
@@ -3986,6 +3994,7 @@ public class AppOpsManager {
/**
* Gets the total duration the app op was accessed (performed) in the background.
+ * The duration is in wall time.
*
* @param flags The flags which are any combination of
* {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
@@ -4004,7 +4013,7 @@ public class AppOpsManager {
/**
* Gets the total duration the app op was accessed (performed) for a given
- * range of UID states.
+ * range of UID states. The duration is in wall time.
*
* @param fromUidState The UID state from which to query. Could be one of
* {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 1c123dec1c10..1641afb3d65c 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -321,30 +321,60 @@ public class ApplicationPackageManager extends PackageManager {
}
@Override
- public PermissionInfo getPermissionInfo(String name, int flags)
+ @SuppressWarnings("unchecked")
+ public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
+ try {
+ final ParceledListSlice<PermissionGroupInfo> parceledList =
+ mPermissionManager.getAllPermissionGroups(flags);
+ if (parceledList == null) {
+ return Collections.emptyList();
+ }
+ return parceledList.getList();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags)
throws NameNotFoundException {
try {
- PermissionInfo pi = mPM.getPermissionInfo(name,
- mContext.getOpPackageName(), flags);
+ final PermissionGroupInfo pgi =
+ mPermissionManager.getPermissionGroupInfo(groupName, flags);
+ if (pgi != null) {
+ return pgi;
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ throw new NameNotFoundException(groupName);
+ }
+
+ @Override
+ public PermissionInfo getPermissionInfo(String permName, int flags)
+ throws NameNotFoundException {
+ try {
+ final String packageName = mContext.getOpPackageName();
+ final PermissionInfo pi =
+ mPermissionManager.getPermissionInfo(permName, packageName, flags);
if (pi != null) {
return pi;
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
-
- throw new NameNotFoundException(name);
+ throw new NameNotFoundException(permName);
}
@Override
@SuppressWarnings("unchecked")
- public List<PermissionInfo> queryPermissionsByGroup(String group, int flags)
+ public List<PermissionInfo> queryPermissionsByGroup(String groupName, int flags)
throws NameNotFoundException {
try {
- ParceledListSlice<PermissionInfo> parceledList =
- mPM.queryPermissionsByGroup(group, flags);
+ final ParceledListSlice<PermissionInfo> parceledList =
+ mPermissionManager.queryPermissionsByGroup(groupName, flags);
if (parceledList != null) {
- List<PermissionInfo> pi = parceledList.getList();
+ final List<PermissionInfo> pi = parceledList.getList();
if (pi != null) {
return pi;
}
@@ -352,8 +382,7 @@ public class ApplicationPackageManager extends PackageManager {
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
-
- throw new NameNotFoundException(group);
+ throw new NameNotFoundException(groupName);
}
@Override
@@ -369,36 +398,6 @@ public class ApplicationPackageManager extends PackageManager {
}
@Override
- public PermissionGroupInfo getPermissionGroupInfo(String name,
- int flags) throws NameNotFoundException {
- try {
- PermissionGroupInfo pgi = mPM.getPermissionGroupInfo(name, flags);
- if (pgi != null) {
- return pgi;
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
-
- throw new NameNotFoundException(name);
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
- try {
- ParceledListSlice<PermissionGroupInfo> parceledList =
- mPM.getAllPermissionGroups(flags);
- if (parceledList == null) {
- return Collections.emptyList();
- }
- return parceledList.getList();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- @Override
public ApplicationInfo getApplicationInfo(String packageName, int flags)
throws NameNotFoundException {
return getApplicationInfoAsUser(packageName, flags, getUserId());
@@ -662,7 +661,7 @@ public class ApplicationPackageManager extends PackageManager {
@Override
public boolean addPermission(PermissionInfo info) {
try {
- return mPM.addPermission(info);
+ return mPermissionManager.addPermission(info, false);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -671,7 +670,7 @@ public class ApplicationPackageManager extends PackageManager {
@Override
public boolean addPermissionAsync(PermissionInfo info) {
try {
- return mPM.addPermissionAsync(info);
+ return mPermissionManager.addPermission(info, true);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -680,7 +679,7 @@ public class ApplicationPackageManager extends PackageManager {
@Override
public void removePermission(String name) {
try {
- mPM.removePermission(name);
+ mPermissionManager.removePermission(name);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 26720fca4df8..2957309094f6 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -386,15 +386,6 @@ interface IActivityTaskManager {
*/
void resizePinnedStack(in Rect pinnedBounds, in Rect tempPinnedTaskBounds);
- /**
- * Updates override configuration applied to specific display.
- * @param values Update values for display configuration. If null is passed it will request the
- * Window Manager to compute new config for the specified display.
- * @param displayId Id of the display to apply the config to.
- * @throws RemoteException
- * @return Returns true if the configuration was updated.
- */
- boolean updateDisplayOverrideConfiguration(in Configuration values, int displayId);
void dismissKeyguard(in IBinder token, in IKeyguardDismissCallback callback,
in CharSequence message);
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 441ff6ba4643..5624ba54077a 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -6066,30 +6066,6 @@ public class DevicePolicyManager {
/**
* @hide
- * @deprecated Do not use
- * @removed
- */
- @Deprecated
- @SystemApi
- @SuppressLint("Doclava125")
- public @Nullable String getDeviceInitializerApp() {
- return null;
- }
-
- /**
- * @hide
- * @deprecated Do not use
- * @removed
- */
- @Deprecated
- @SystemApi
- @SuppressLint("Doclava125")
- public @Nullable ComponentName getDeviceInitializerComponent() {
- return null;
- }
-
- /**
- * @hide
* @deprecated Use #ACTION_SET_PROFILE_OWNER
* Sets the given component as an active admin and registers the package as the profile
* owner for this user. The package must already be installed and there shouldn't be
@@ -7394,60 +7370,6 @@ public class DevicePolicyManager {
}
/**
- * Called by a device owner to create a user with the specified name. The UserHandle returned
- * by this method should not be persisted as user handles are recycled as users are removed and
- * created. If you need to persist an identifier for this user, use
- * {@link UserManager#getSerialNumberForUser}.
- *
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
- * @param name the user's name
- * @see UserHandle
- * @return the {@link android.os.UserHandle} object for the created user, or {@code null} if the
- * user could not be created.
- *
- * @deprecated From {@link android.os.Build.VERSION_CODES#M}
- * @removed From {@link android.os.Build.VERSION_CODES#N}
- */
- @Deprecated
- public @Nullable UserHandle createUser(@NonNull ComponentName admin, String name) {
- return null;
- }
-
- /**
- * Called by a device owner to create a user with the specified name. The UserHandle returned
- * by this method should not be persisted as user handles are recycled as users are removed and
- * created. If you need to persist an identifier for this user, use
- * {@link UserManager#getSerialNumberForUser}. The new user will be started in the background
- * immediately.
- *
- * <p> profileOwnerComponent is the {@link DeviceAdminReceiver} to be the profile owner as well
- * as registered as an active admin on the new user. The profile owner package will be
- * installed on the new user if it already is installed on the device.
- *
- * <p>If the optionalInitializeData is not null, then the extras will be passed to the
- * profileOwnerComponent when onEnable is called.
- *
- * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
- * @param name the user's name
- * @param ownerName the human readable name of the organisation associated with this DPM.
- * @param profileOwnerComponent The {@link DeviceAdminReceiver} that will be an active admin on
- * the user.
- * @param adminExtras Extras that will be passed to onEnable of the admin receiver
- * on the new user.
- * @see UserHandle
- * @return the {@link android.os.UserHandle} object for the created user, or {@code null} if the
- * user could not be created.
- *
- * @deprecated From {@link android.os.Build.VERSION_CODES#M}
- * @removed From {@link android.os.Build.VERSION_CODES#N}
- */
- @Deprecated
- public @Nullable UserHandle createAndInitializeUser(@NonNull ComponentName admin, String name,
- String ownerName, @NonNull ComponentName profileOwnerComponent, Bundle adminExtras) {
- return null;
- }
-
- /**
* Flag used by {@link #createAndManageUser} to skip setup wizard after creating a new user.
*/
public static final int SKIP_SETUP_WIZARD = 0x0001;
diff --git a/core/java/android/app/servertransaction/NewIntentItem.java b/core/java/android/app/servertransaction/NewIntentItem.java
index 2d1883836d02..bb775fc4a5fb 100644
--- a/core/java/android/app/servertransaction/NewIntentItem.java
+++ b/core/java/android/app/servertransaction/NewIntentItem.java
@@ -17,6 +17,7 @@
package android.app.servertransaction;
import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME;
+import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED;
import android.annotation.UnsupportedAppUsage;
import android.app.ClientTransactionHandler;
@@ -38,10 +39,11 @@ public class NewIntentItem extends ClientTransactionItem {
@UnsupportedAppUsage
private List<ReferrerIntent> mIntents;
+ private boolean mResume;
@Override
public int getPostExecutionState() {
- return ON_RESUME;
+ return mResume ? ON_RESUME : UNDEFINED;
}
@Override
@@ -58,12 +60,13 @@ public class NewIntentItem extends ClientTransactionItem {
private NewIntentItem() {}
/** Obtain an instance initialized with provided params. */
- public static NewIntentItem obtain(List<ReferrerIntent> intents) {
+ public static NewIntentItem obtain(List<ReferrerIntent> intents, boolean resume) {
NewIntentItem instance = ObjectPool.obtain(NewIntentItem.class);
if (instance == null) {
instance = new NewIntentItem();
}
instance.mIntents = intents;
+ instance.mResume = resume;
return instance;
}
@@ -71,6 +74,7 @@ public class NewIntentItem extends ClientTransactionItem {
@Override
public void recycle() {
mIntents = null;
+ mResume = false;
ObjectPool.recycle(this);
}
@@ -80,11 +84,13 @@ public class NewIntentItem extends ClientTransactionItem {
/** Write to Parcel. */
@Override
public void writeToParcel(Parcel dest, int flags) {
+ dest.writeBoolean(mResume);
dest.writeTypedList(mIntents, flags);
}
/** Read from Parcel. */
private NewIntentItem(Parcel in) {
+ mResume = in.readBoolean();
mIntents = in.createTypedArrayList(ReferrerIntent.CREATOR);
}
@@ -108,18 +114,19 @@ public class NewIntentItem extends ClientTransactionItem {
return false;
}
final NewIntentItem other = (NewIntentItem) o;
- return Objects.equals(mIntents, other.mIntents);
+ return mResume == other.mResume && Objects.equals(mIntents, other.mIntents);
}
@Override
public int hashCode() {
int result = 17;
+ result = 31 * result + (mResume ? 1 : 0);
result = 31 * result + mIntents.hashCode();
return result;
}
@Override
public String toString() {
- return "NewIntentItem{intents=" + mIntents + "}";
+ return "NewIntentItem{intents=" + mIntents + ",resume=" + mResume + "}";
}
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index c3dd82729d6d..341fc26e2b96 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3067,7 +3067,7 @@ public abstract class Context {
* @hide
*/
@RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(trackingBug = 136728678)
public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
Handler handler, UserHandle user) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 9bc5f8055617..f75cd236eb36 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -783,8 +783,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
*/
public float minAspectRatio;
- /** @removed */
- @Deprecated
+ /** @hide */
public String volumeUuid;
/**
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index bd6ee7651916..277e41dc7e01 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -78,15 +78,6 @@ interface IPackageManager {
@UnsupportedAppUsage
String[] canonicalToCurrentPackageNames(in String[] names);
- PermissionInfo getPermissionInfo(String name, String packageName, int flags);
-
- ParceledListSlice queryPermissionsByGroup(String group, int flags);
-
- @UnsupportedAppUsage
- PermissionGroupInfo getPermissionGroupInfo(String name, int flags);
-
- ParceledListSlice getAllPermissionGroups(int flags);
-
@UnsupportedAppUsage
ApplicationInfo getApplicationInfo(String packageName, int flags ,int userId);
@@ -111,12 +102,6 @@ interface IPackageManager {
int checkUidPermission(String permName, int uid);
@UnsupportedAppUsage
- boolean addPermission(in PermissionInfo info);
-
- @UnsupportedAppUsage
- void removePermission(String name);
-
- @UnsupportedAppUsage
void grantRuntimePermission(String packageName, String permissionName, int userId);
void revokeRuntimePermission(String packageName, String permissionName, int userId);
@@ -623,9 +608,6 @@ interface IPackageManager {
int movePackage(in String packageName, in String volumeUuid);
int movePrimaryStorage(in String volumeUuid);
- @UnsupportedAppUsage
- boolean addPermissionAsync(in PermissionInfo info);
-
boolean setInstallLocation(int loc);
@UnsupportedAppUsage
int getInstallLocation();
@@ -777,4 +759,16 @@ interface IPackageManager {
//------------------------------------------------------------------------
@UnsupportedAppUsage
String[] getAppOpPermissionPackages(String permissionName);
+
+ @UnsupportedAppUsage
+ PermissionGroupInfo getPermissionGroupInfo(String name, int flags);
+
+ @UnsupportedAppUsage
+ boolean addPermission(in PermissionInfo info);
+
+ @UnsupportedAppUsage
+ boolean addPermissionAsync(in PermissionInfo info);
+
+ @UnsupportedAppUsage
+ void removePermission(String name);
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e08f4a28e77c..b845a37b0342 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -105,6 +105,7 @@ public abstract class PackageManager {
* @hide
*/
@SystemApi
+ @TestApi
public interface OnPermissionsChangedListener {
/**
@@ -6413,6 +6414,7 @@ public abstract class PackageManager {
* @hide
*/
@SystemApi
+ @TestApi
@RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS)
public abstract void addOnPermissionsChangeListener(
@NonNull OnPermissionsChangedListener listener);
@@ -6425,6 +6427,7 @@ public abstract class PackageManager {
* @hide
*/
@SystemApi
+ @TestApi
@RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS)
public abstract void removeOnPermissionsChangeListener(
@NonNull OnPermissionsChangedListener listener);
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 672994e79134..1c1d7095d913 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -999,4 +999,11 @@ public abstract class PackageManagerInternal {
* Migrates legacy obb data to its new location.
*/
public abstract void migrateLegacyObbData();
+
+ /**
+ * Writes all package manager settings to disk. If {@code async} is {@code true}, the
+ * settings are written at some point in the future. Otherwise, the call blocks until
+ * the settings have been written.
+ */
+ public abstract void writeSettings(boolean async);
}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index e5ef67b7d4bd..2420a6109155 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -1157,8 +1157,11 @@ public final class AssetManager implements AutoCloseable {
}
}
- if (mObject != 0) {
- nativeDestroy(mObject);
+ synchronized (this) {
+ if (mObject != 0) {
+ nativeDestroy(mObject);
+ mObject = 0;
+ }
}
}
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index c8f0e094b631..12b285a0f0ab 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -262,7 +262,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
* @hide
*/
@RequiresPermission(MANAGE_BIOMETRIC)
- public void enroll(byte[] token, CancellationSignal cancel,
+ public void enroll(int userId, byte[] token, CancellationSignal cancel,
EnrollmentCallback callback, int[] disabledFeatures) {
if (callback == null) {
throw new IllegalArgumentException("Must supply an enrollment callback");
@@ -281,7 +281,7 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
try {
mEnrollmentCallback = callback;
Trace.beginSection("FaceManager#enroll");
- mService.enroll(mToken, token, mServiceReceiver,
+ mService.enroll(userId, mToken, token, mServiceReceiver,
mContext.getOpPackageName(), disabledFeatures);
} catch (RemoteException e) {
Log.w(TAG, "Remote exception in enroll: ", e);
@@ -339,12 +339,13 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
* @hide
*/
@RequiresPermission(MANAGE_BIOMETRIC)
- public void setFeature(int feature, boolean enabled, byte[] token,
+ public void setFeature(int userId, int feature, boolean enabled, byte[] token,
SetFeatureCallback callback) {
if (mService != null) {
try {
mSetFeatureCallback = callback;
- mService.setFeature(feature, enabled, token, mServiceReceiver);
+ mService.setFeature(userId, feature, enabled, token, mServiceReceiver,
+ mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -355,11 +356,11 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
* @hide
*/
@RequiresPermission(MANAGE_BIOMETRIC)
- public void getFeature(int feature, GetFeatureCallback callback) {
+ public void getFeature(int userId, int feature, GetFeatureCallback callback) {
if (mService != null) {
try {
mGetFeatureCallback = callback;
- mService.getFeature(feature, mServiceReceiver);
+ mService.getFeature(userId, feature, mServiceReceiver, mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -414,7 +415,8 @@ public class FaceManager implements BiometricAuthenticator, BiometricFaceConstan
try {
mRemovalCallback = callback;
mRemovalFace = face;
- mService.remove(mToken, face.getBiometricId(), userId, mServiceReceiver);
+ mService.remove(mToken, face.getBiometricId(), userId, mServiceReceiver,
+ mContext.getOpPackageName());
} catch (RemoteException e) {
Log.w(TAG, "Remote exception in remove: ", e);
if (callback != null) {
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index 601be7595581..b6a0afbf716c 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -50,14 +50,15 @@ interface IFaceService {
int callingUid, int callingPid, int callingUserId, boolean fromClient);
// Start face enrollment
- void enroll(IBinder token, in byte [] cryptoToken, IFaceServiceReceiver receiver,
+ void enroll(int userId, IBinder token, in byte [] cryptoToken, IFaceServiceReceiver receiver,
String opPackageName, in int [] disabledFeatures);
// Cancel enrollment in progress
void cancelEnrollment(IBinder token);
// Any errors resulting from this call will be returned to the listener
- void remove(IBinder token, int faceId, int userId, IFaceServiceReceiver receiver);
+ void remove(IBinder token, int faceId, int userId, IFaceServiceReceiver receiver,
+ String opPackageName);
// Rename the face specified by faceId to the given name
void rename(int faceId, String name);
@@ -98,10 +99,10 @@ interface IFaceService {
// Enumerate all faces
void enumerate(IBinder token, int userId, IFaceServiceReceiver receiver);
- void setFeature(int feature, boolean enabled, in byte [] token,
- IFaceServiceReceiver receiver);
+ void setFeature(int userId, int feature, boolean enabled, in byte [] token,
+ IFaceServiceReceiver receiver, String opPackageName);
- void getFeature(int feature, IFaceServiceReceiver receiver);
+ void getFeature(int userId, int feature, IFaceServiceReceiver receiver, String opPackageName);
void userActivity();
}
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index d05ba799205c..972ae2a06e5f 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -35,8 +35,10 @@ import android.os.SystemProperties;
import android.util.ArrayMap;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -61,7 +63,31 @@ public final class HdmiControlManager {
private static final int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
- private int mPhysicalAddress = INVALID_PHYSICAL_ADDRESS;
+ /**
+ * A cache of the current device's physical address. When device's HDMI out port
+ * is not connected to any device, it is set to {@link #INVALID_PHYSICAL_ADDRESS}.
+ *
+ * <p>Otherwise it is updated by the {@link ClientHotplugEventListener} registered
+ * with {@link com.android.server.hdmi.HdmiControlService} by the
+ * {@link #addHotplugEventListener(HotplugEventListener)} and the address is from
+ * {@link com.android.server.hdmi.HdmiControlService#getPortInfo()}
+ */
+ @GuardedBy("mLock")
+ private int mLocalPhysicalAddress = INVALID_PHYSICAL_ADDRESS;
+
+ private void setLocalPhysicalAddress(int physicalAddress) {
+ synchronized (mLock) {
+ mLocalPhysicalAddress = physicalAddress;
+ }
+ }
+
+ private int getLocalPhysicalAddress() {
+ synchronized (mLock) {
+ return mLocalPhysicalAddress;
+ }
+ }
+
+ private final Object mLock = new Object();
/**
* Broadcast Action: Display OSD message.
@@ -318,6 +344,37 @@ public final class HdmiControlManager {
mHasSwitchDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH);
mIsSwitchDevice = SystemProperties.getBoolean(
PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH, false);
+ addHotplugEventListener(new ClientHotplugEventListener());
+ }
+
+ private final class ClientHotplugEventListener implements HotplugEventListener {
+
+ @Override
+ public void onReceived(HdmiHotplugEvent event) {
+ List<HdmiPortInfo> ports = new ArrayList<>();
+ try {
+ ports = mService.getPortInfo();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ if (ports.isEmpty()) {
+ Log.e(TAG, "Can't find port info, not updating connected status. "
+ + "Hotplug event:" + event);
+ return;
+ }
+ // If the HDMI OUT port is plugged or unplugged, update the mLocalPhysicalAddress
+ for (HdmiPortInfo port : ports) {
+ if (port.getId() == event.getPort()) {
+ if (port.getType() == HdmiPortInfo.PORT_OUTPUT) {
+ setLocalPhysicalAddress(
+ event.isConnected()
+ ? port.getAddress()
+ : INVALID_PHYSICAL_ADDRESS);
+ }
+ break;
+ }
+ }
+ }
}
private static boolean hasDeviceType(int[] types, int type) {
@@ -616,15 +673,7 @@ public final class HdmiControlManager {
*/
@SystemApi
public int getPhysicalAddress() {
- if (mPhysicalAddress != INVALID_PHYSICAL_ADDRESS) {
- return mPhysicalAddress;
- }
- try {
- mPhysicalAddress = mService.getPhysicalAddress();
- return mPhysicalAddress;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getLocalPhysicalAddress();
}
/**
@@ -641,15 +690,15 @@ public final class HdmiControlManager {
@SystemApi
public boolean isDeviceConnected(@NonNull HdmiDeviceInfo targetDevice) {
Preconditions.checkNotNull(targetDevice);
- mPhysicalAddress = getPhysicalAddress();
- if (mPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
+ int physicalAddress = getLocalPhysicalAddress();
+ if (physicalAddress == INVALID_PHYSICAL_ADDRESS) {
return false;
}
int targetPhysicalAddress = targetDevice.getPhysicalAddress();
if (targetPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
return false;
}
- return HdmiUtils.getLocalPortFromPhysicalAddress(targetPhysicalAddress, mPhysicalAddress)
+ return HdmiUtils.getLocalPortFromPhysicalAddress(targetPhysicalAddress, physicalAddress)
!= HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE;
}
@@ -662,15 +711,15 @@ public final class HdmiControlManager {
@SystemApi
public boolean isRemoteDeviceConnected(@NonNull HdmiDeviceInfo targetDevice) {
Preconditions.checkNotNull(targetDevice);
- mPhysicalAddress = getPhysicalAddress();
- if (mPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
+ int physicalAddress = getLocalPhysicalAddress();
+ if (physicalAddress == INVALID_PHYSICAL_ADDRESS) {
return false;
}
int targetPhysicalAddress = targetDevice.getPhysicalAddress();
if (targetPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
return false;
}
- return HdmiUtils.getLocalPortFromPhysicalAddress(targetPhysicalAddress, mPhysicalAddress)
+ return HdmiUtils.getLocalPortFromPhysicalAddress(targetPhysicalAddress, physicalAddress)
!= HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE;
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index ecd16dd1f612..caa6a43e521c 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1554,7 +1554,10 @@ public abstract class BatteryStats implements Parcelable {
}
}
- public final static class HistoryItem implements Parcelable {
+ /**
+ * Battery history record.
+ */
+ public static final class HistoryItem {
public HistoryItem next;
// The time of this event in milliseconds, as per SystemClock.elapsedRealtime().
@@ -1789,16 +1792,10 @@ public abstract class BatteryStats implements Parcelable {
public HistoryItem() {
}
- public HistoryItem(long time, Parcel src) {
- this.time = time;
- numReadInts = 2;
+ public HistoryItem(Parcel src) {
readFromParcel(src);
}
- public int describeContents() {
- return 0;
- }
-
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(time);
int bat = (((int)cmd)&0xff)
@@ -1835,6 +1832,7 @@ public abstract class BatteryStats implements Parcelable {
public void readFromParcel(Parcel src) {
int start = src.dataPosition();
+ time = src.readLong();
int bat = src.readInt();
cmd = (byte)(bat&0xff);
batteryLevel = (byte)((bat>>8)&0xff);
diff --git a/core/java/android/os/RedactingFileDescriptor.java b/core/java/android/os/RedactingFileDescriptor.java
index 4e5eaac3442f..a1ed2146b38e 100644
--- a/core/java/android/os/RedactingFileDescriptor.java
+++ b/core/java/android/os/RedactingFileDescriptor.java
@@ -35,7 +35,7 @@ import java.util.Arrays;
/**
* Variant of {@link FileDescriptor} that allows its creator to specify regions
- * that should be redacted (appearing as zeros to the reader).
+ * that should be redacted.
*
* @hide
*/
@@ -44,13 +44,16 @@ public class RedactingFileDescriptor {
private static final boolean DEBUG = true;
private volatile long[] mRedactRanges;
+ private volatile long[] mFreeOffsets;
private FileDescriptor mInner = null;
private ParcelFileDescriptor mOuter = null;
- private RedactingFileDescriptor(Context context, File file, int mode, long[] redactRanges)
+ private RedactingFileDescriptor(
+ Context context, File file, int mode, long[] redactRanges, long[] freeOffsets)
throws IOException {
mRedactRanges = checkRangesArgument(redactRanges);
+ mFreeOffsets = freeOffsets;
try {
try {
@@ -88,13 +91,17 @@ public class RedactingFileDescriptor {
*
* @param file The underlying file to open.
* @param mode The {@link ParcelFileDescriptor} mode to open with.
- * @param redactRanges List of file offsets that should be redacted, stored
+ * @param redactRanges List of file ranges that should be redacted, stored
* as {@code [start1, end1, start2, end2, ...]}. Start values are
* inclusive and end values are exclusive.
+ * @param freePositions List of file offsets at which the four byte value 'free' should be
+ * written instead of zeros within parts of the file covered by {@code redactRanges}.
+ * Non-redacted bytes will not be modified even if covered by a 'free'. This is
+ * useful for overwriting boxes in ISOBMFF files with padding data.
*/
public static ParcelFileDescriptor open(Context context, File file, int mode,
- long[] redactRanges) throws IOException {
- return new RedactingFileDescriptor(context, file, mode, redactRanges).mOuter;
+ long[] redactRanges, long[] freePositions) throws IOException {
+ return new RedactingFileDescriptor(context, file, mode, redactRanges, freePositions).mOuter;
}
/**
@@ -169,6 +176,15 @@ public class RedactingFileDescriptor {
for (long j = start; j < end; j++) {
data[(int) (j - offset)] = 0;
}
+ // Overwrite data at 'free' offsets within the redaction ranges.
+ for (long freeOffset : mFreeOffsets) {
+ final long freeEnd = freeOffset + 4;
+ final long redactFreeStart = Math.max(freeOffset, start);
+ final long redactFreeEnd = Math.min(freeEnd, end);
+ for (long j = redactFreeStart; j < redactFreeEnd; j++) {
+ data[(int) (j - offset)] = (byte) "free".charAt((int) (j - freeOffset));
+ }
+ }
}
return n;
}
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index a32b7c6021bb..cdd0d45624b7 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -671,16 +671,6 @@ public class ZygoteProcess {
private boolean fetchUsapPoolEnabledPropWithMinInterval() {
final long currentTimestamp = SystemClock.elapsedRealtime();
- if (SystemProperties.get("dalvik.vm.boot-image", "").endsWith("apex.art")) {
- // TODO(b/119800099): In jitzygote mode, we want to start using USAP processes
- // only once the boot classpath has been compiled. There is currently no callback
- // from the runtime to notify the zygote about end of compilation, so for now just
- // arbitrarily start USAP processes 15 seconds after boot.
- if (currentTimestamp <= 15000) {
- return false;
- }
- }
-
if (mIsFirstPropCheck
|| (currentTimestamp - mLastPropCheckTimestamp >= Zygote.PROPERTY_CHECK_INTERVAL)) {
mIsFirstPropCheck = false;
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 67176e45c534..3b69b122ca1d 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -16,6 +16,10 @@
package android.permission;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+
/**
* Interface to communicate directly with the permission manager service.
* @see PermissionManager
@@ -23,4 +27,16 @@ package android.permission;
*/
interface IPermissionManager {
String[] getAppOpPermissionPackages(String permName);
+
+ ParceledListSlice getAllPermissionGroups(int flags);
+
+ PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags);
+
+ PermissionInfo getPermissionInfo(String permName, String packageName, int flags);
+
+ ParceledListSlice queryPermissionsByGroup(String groupName, int flags);
+
+ boolean addPermission(in PermissionInfo info, boolean async);
+
+ void removePermission(String name);
}
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 48faf114d2d7..d0401e38e927 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -333,6 +333,26 @@ public final class DeviceConfig {
*/
@TestApi
String KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP = "system_gesture_exclusion_limit_dp";
+
+ /**
+ * Key for controlling whether system gestures are implicitly excluded by windows requesting
+ * sticky immersive mode from apps that are targeting an SDK prior to Q.
+ *
+ * @see android.provider.DeviceConfig#NAMESPACE_WINDOW_MANAGER
+ * @hide
+ */
+ @TestApi
+ String KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE =
+ "system_gestures_excluded_by_pre_q_sticky_immersive";
+
+ /**
+ * Key for controlling which packages are explicitly blocked from running at refresh rates
+ * higher than 90hz.
+ *
+ * @see android.provider.DeviceConfig#NAMESPACE_WINDOW_MANAGER
+ * @hide
+ */
+ String KEY_HIGH_REFRESH_RATE_BLACKLIST = "high_refresh_rate_blacklist";
}
private static final Object sLock = new Object();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 01058f936d9b..5308cd3a0926 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -42,6 +42,7 @@ import android.annotation.UserIdInt;
import android.app.ActivityThread;
import android.app.AppOpsManager;
import android.app.Application;
+import android.app.AutomaticZenRule;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.SearchManager;
@@ -89,7 +90,6 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.MemoryIntArray;
import android.view.Display;
-import android.view.inputmethod.InputMethodSystemProperty;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.widget.ILockSettings;
@@ -1313,7 +1313,17 @@ public final class Settings {
"android.settings.NOTIFICATION_POLICY_ACCESS_DETAIL_SETTINGS";
/**
- * @hide
+ * Activity Action: Show the automatic do not disturb rule listing page
+ * <p>
+ * Users can add, enable, disable, and remove automatic do not disturb rules from this
+ * screen. See {@link NotificationManager#addAutomaticZenRule(AutomaticZenRule)} for more
+ * details.
+ * </p>
+ * <p>
+ * Input: Nothing
+ * Output: Nothing
+ * </p>
+ *
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_CONDITION_PROVIDER_SETTINGS
@@ -9287,13 +9297,6 @@ public final class Settings {
CLONE_TO_MANAGED_PROFILE.add(LOCATION_MODE);
CLONE_TO_MANAGED_PROFILE.add(LOCATION_PROVIDERS_ALLOWED);
CLONE_TO_MANAGED_PROFILE.add(SHOW_IME_WITH_HARD_KEYBOARD);
- if (!InputMethodSystemProperty.PER_PROFILE_IME_ENABLED) {
- CLONE_TO_MANAGED_PROFILE.add(DEFAULT_INPUT_METHOD);
- CLONE_TO_MANAGED_PROFILE.add(ENABLED_INPUT_METHODS);
- CLONE_TO_MANAGED_PROFILE.add(SELECTED_INPUT_METHOD_SUBTYPE);
- CLONE_TO_MANAGED_PROFILE.add(SELECTED_SPELL_CHECKER);
- CLONE_TO_MANAGED_PROFILE.add(SELECTED_SPELL_CHECKER_SUBTYPE);
- }
}
/** @hide */
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 6563e03853fb..9cc6b287431e 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -99,6 +99,7 @@ import java.util.concurrent.locks.ReentrantLock;
public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallback {
private static final String TAG = "SurfaceView";
private static final boolean DEBUG = false;
+ private static final boolean DEBUG_POSITION = false;
@UnsupportedAppUsage
final ArrayList<SurfaceHolder.Callback> mCallbacks = new ArrayList<>();
@@ -124,6 +125,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
// we need to preserve the old one until the new one has drawn.
SurfaceControl mDeferredDestroySurfaceControl;
SurfaceControl mBackgroundControl;
+ final Object mSurfaceControlLock = new Object();
final Rect mTmpRect = new Rect();
Paint mRoundedViewportPaint;
@@ -161,6 +163,9 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
@UnsupportedAppUsage
int mRequestedFormat = PixelFormat.RGB_565;
+ boolean mUseAlpha = false;
+ float mSurfaceAlpha = 1f;
+
@UnsupportedAppUsage
boolean mHaveFrame = false;
boolean mSurfaceCreated = false;
@@ -276,6 +281,152 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
updateSurface();
}
+ /**
+ * Make alpha value of this view reflect onto the surface. This can only be called from at most
+ * one SurfaceView within a view tree.
+ *
+ * <p class="note"><strong>Note:</strong> Alpha value of the view is ignored and the underlying
+ * surface is rendered opaque by default.</p>
+ *
+ * @hide
+ */
+ public void setUseAlpha() {
+ if (!mUseAlpha) {
+ mUseAlpha = true;
+ updateSurfaceAlpha();
+ }
+ }
+
+ @Override
+ public void setAlpha(float alpha) {
+ // Sets the opacity of the view to a value, where 0 means the view is completely transparent
+ // and 1 means the view is completely opaque.
+ //
+ // Note: Alpha value of this view is ignored by default. To enable alpha blending, you need
+ // to call setUseAlpha() as well.
+ // This view doesn't support translucent opacity if the view is located z-below, since the
+ // logic to punch a hole in the view hierarchy cannot handle such case. See also
+ // #clearSurfaceViewPort(Canvas)
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this)
+ + " setAlpha: mUseAlpha = " + mUseAlpha + " alpha=" + alpha);
+ }
+ super.setAlpha(alpha);
+ updateSurfaceAlpha();
+ }
+
+ private float getFixedAlpha() {
+ // Compute alpha value to be set on the underlying surface.
+ final float alpha = getAlpha();
+ return mUseAlpha && (mSubLayer > 0 || alpha == 0f) ? alpha : 1f;
+ }
+
+ private void updateSurfaceAlpha() {
+ if (!mUseAlpha) {
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this)
+ + " updateSurfaceAlpha: setUseAlpha() is not called, ignored.");
+ }
+ return;
+ }
+ final float viewAlpha = getAlpha();
+ if (mSubLayer < 0 && 0f < viewAlpha && viewAlpha < 1f) {
+ Log.w(TAG, System.identityHashCode(this)
+ + " updateSurfaceAlpha:"
+ + " translucent color is not supported for a surface placed z-below.");
+ }
+ if (!mHaveFrame) {
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this)
+ + " updateSurfaceAlpha: has no surface.");
+ }
+ return;
+ }
+ final ViewRootImpl viewRoot = getViewRootImpl();
+ if (viewRoot == null) {
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this)
+ + " updateSurfaceAlpha: ViewRootImpl not available.");
+ }
+ return;
+ }
+ if (mSurfaceControl == null) {
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this)
+ + "updateSurfaceAlpha:"
+ + " surface is not yet created, or already released.");
+ }
+ return;
+ }
+ final Surface parent = viewRoot.mSurface;
+ if (parent == null || !parent.isValid()) {
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this)
+ + " updateSurfaceAlpha: ViewRootImpl has no valid surface");
+ }
+ return;
+ }
+ final float alpha = getFixedAlpha();
+ if (alpha != mSurfaceAlpha) {
+ if (isHardwareAccelerated()) {
+ /*
+ * Schedule a callback that reflects an alpha value onto the underlying surfaces.
+ * This gets called on a RenderThread worker thread, so members accessed here must
+ * be protected by a lock.
+ */
+ viewRoot.registerRtFrameCallback(frame -> {
+ try {
+ final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ synchronized (mSurfaceControlLock) {
+ if (!parent.isValid()) {
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this)
+ + " updateSurfaceAlpha RT:"
+ + " ViewRootImpl has no valid surface");
+ }
+ return;
+ }
+ if (mSurfaceControl == null) {
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this)
+ + "updateSurfaceAlpha RT:"
+ + " mSurfaceControl has already released");
+ }
+ return;
+ }
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this)
+ + " updateSurfaceAlpha RT: set alpha=" + alpha);
+ }
+ t.setAlpha(mSurfaceControl, alpha);
+ t.deferTransactionUntilSurface(mSurfaceControl, parent, frame);
+ }
+ // It's possible that mSurfaceControl is released in the UI thread before
+ // the transaction completes. If that happens, an exception is thrown, which
+ // must be caught immediately.
+ t.apply();
+ } catch (Exception e) {
+ Log.e(TAG, System.identityHashCode(this)
+ + "updateSurfaceAlpha RT: Exception during surface transaction", e);
+ }
+ });
+ damageInParent();
+ } else {
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this)
+ + " updateSurfaceAlpha: set alpha=" + alpha);
+ }
+ SurfaceControl.openTransaction();
+ try {
+ mSurfaceControl.setAlpha(alpha);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+ mSurfaceAlpha = alpha;
+ }
+ }
+
private void performDrawFinished() {
if (mPendingReportDraws > 0) {
mDrawFinished = true;
@@ -326,11 +477,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
mRequestedVisible = false;
updateSurface();
- if (mSurfaceControl != null) {
- mTmpTransaction.remove(mSurfaceControl).apply();
- }
- mSurfaceControl = null;
-
+ releaseSurfaces();
mHaveFrame = false;
super.onDetachedFromWindow();
@@ -499,15 +646,6 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
}
}
- private Rect getParentSurfaceInsets() {
- final ViewRootImpl root = getViewRootImpl();
- if (root == null) {
- return null;
- } else {
- return root.mWindowAttributes.surfaceInsets;
- }
- }
-
private void updateBackgroundVisibilityInTransaction(SurfaceControl viewRoot) {
if (mBackgroundControl == null) {
return;
@@ -521,24 +659,34 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
}
private void releaseSurfaces() {
- if (mSurfaceControl != null) {
- mTmpTransaction.remove(mSurfaceControl);
- mSurfaceControl = null;
- }
- if (mBackgroundControl != null) {
- mTmpTransaction.remove(mBackgroundControl);
- mBackgroundControl = null;
+ synchronized (mSurfaceControlLock) {
+ if (mSurfaceControl != null) {
+ mTmpTransaction.remove(mSurfaceControl);
+ mSurfaceControl = null;
+ }
+ if (mBackgroundControl != null) {
+ mTmpTransaction.remove(mBackgroundControl);
+ mBackgroundControl = null;
+ }
+ mTmpTransaction.apply();
}
- mTmpTransaction.apply();
+ mSurfaceAlpha = 1f;
}
/** @hide */
protected void updateSurface() {
if (!mHaveFrame) {
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this) + " updateSurface: has no frame");
+ }
return;
}
ViewRootImpl viewRoot = getViewRootImpl();
if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
+ if (DEBUG) {
+ Log.d(TAG, System.identityHashCode(this)
+ + " updateSurface: no valid surface");
+ }
return;
}
@@ -552,20 +700,25 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
int myHeight = mRequestedHeight;
if (myHeight <= 0) myHeight = getHeight();
+ final float alpha = getFixedAlpha();
final boolean formatChanged = mFormat != mRequestedFormat;
final boolean visibleChanged = mVisible != mRequestedVisible;
+ final boolean alphaChanged = mSurfaceAlpha != alpha;
final boolean creating = (mSurfaceControl == null || formatChanged || visibleChanged)
&& mRequestedVisible;
final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
boolean redrawNeeded = false;
- if (creating || formatChanged || sizeChanged || visibleChanged || windowVisibleChanged) {
+ if (creating || formatChanged || sizeChanged || visibleChanged || (mUseAlpha
+ && alphaChanged) || windowVisibleChanged) {
getLocationInWindow(mLocation);
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "Changes: creating=" + creating
+ " format=" + formatChanged + " size=" + sizeChanged
+ + " visible=" + visibleChanged + " alpha=" + alphaChanged
+ + " mUseAlpha=" + mUseAlpha
+ " visible=" + visibleChanged
+ " left=" + (mWindowSpaceLeft != mLocation[0])
+ " top=" + (mWindowSpaceTop != mLocation[1]));
@@ -587,7 +740,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
translator.translateRectInAppWindowToScreen(mScreenRect);
}
- final Rect surfaceInsets = getParentSurfaceInsets();
+ final Rect surfaceInsets = viewRoot.mWindowAttributes.surfaceInsets;
mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
if (creating) {
@@ -636,6 +789,10 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
mSurfaceControl.hide();
}
updateBackgroundVisibilityInTransaction(viewRoot.getSurfaceControl());
+ if (mUseAlpha) {
+ mSurfaceControl.setAlpha(alpha);
+ mSurfaceAlpha = alpha;
+ }
// While creating the surface, we will set it's initial
// geometry. Outside of that though, we should generally
@@ -692,7 +849,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
try {
redrawNeeded |= visible && !mDrawFinished;
- SurfaceHolder.Callback callbacks[] = null;
+ SurfaceHolder.Callback[] callbacks = null;
final boolean surfaceChanged = creating;
if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
@@ -778,7 +935,6 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
mIsCreating = false;
if (mSurfaceControl != null && !mSurfaceCreated) {
mSurface.release();
-
releaseSurfaces();
}
}
@@ -818,10 +974,13 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
try {
- if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition UI, " +
- "postion = [%d, %d, %d, %d]", System.identityHashCode(this),
- mScreenRect.left, mScreenRect.top,
- mScreenRect.right, mScreenRect.bottom));
+ if (DEBUG_POSITION) {
+ Log.d(TAG, String.format("%d updateSurfacePosition UI, "
+ + "position = [%d, %d, %d, %d]",
+ System.identityHashCode(this),
+ mScreenRect.left, mScreenRect.top,
+ mScreenRect.right, mScreenRect.bottom));
+ }
setParentSpaceRectangle(mScreenRect, -1);
} catch (Exception ex) {
Log.e(TAG, "Exception configuring surface", ex);
@@ -842,9 +1001,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
mDeferredDestroySurfaceControl = null;
}
- runOnUiThread(() -> {
- performDrawFinished();
- });
+ runOnUiThread(this::performDrawFinished);
}
/**
@@ -874,7 +1031,6 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
if (mViewVisibility) {
mRtTransaction.show(surface);
}
-
}
private void setParentSpaceRectangle(Rect position, long frameNumber) {
@@ -915,10 +1071,10 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
return;
}
try {
- if (DEBUG) {
+ if (DEBUG_POSITION) {
Log.d(TAG, String.format(
"%d updateSurfacePosition RenderWorker, frameNr = %d, "
- + "postion = [%d, %d, %d, %d]",
+ + "position = [%d, %d, %d, %d]",
System.identityHashCode(this), frameNumber,
left, top, right, bottom));
}
@@ -954,7 +1110,7 @@ public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallb
};
private SurfaceHolder.Callback[] getSurfaceCallbacks() {
- SurfaceHolder.Callback callbacks[];
+ SurfaceHolder.Callback[] callbacks;
synchronized (mCallbacks) {
callbacks = new SurfaceHolder.Callback[mCallbacks.size()];
mCallbacks.toArray(callbacks);
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index f18aa81b95e5..a01e15e7ce46 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -288,9 +288,6 @@ public final class ThreadedRenderer extends HardwareRenderer {
// applied as translation when updating the root render node.
private int mInsetTop, mInsetLeft;
- // Whether the surface has insets. Used to protect opacity.
- private boolean mHasInsets;
-
// Light properties specified by the theme.
private final float mLightY;
private final float mLightZ;
@@ -480,7 +477,6 @@ public final class ThreadedRenderer extends HardwareRenderer {
if (surfaceInsets != null && (surfaceInsets.left != 0 || surfaceInsets.right != 0
|| surfaceInsets.top != 0 || surfaceInsets.bottom != 0)) {
- mHasInsets = true;
mInsetLeft = surfaceInsets.left;
mInsetTop = surfaceInsets.top;
mSurfaceWidth = width + mInsetLeft + surfaceInsets.right;
@@ -489,7 +485,6 @@ public final class ThreadedRenderer extends HardwareRenderer {
// If the surface has insets, it can't be opaque.
setOpaque(false);
} else {
- mHasInsets = false;
mInsetLeft = 0;
mInsetTop = 0;
mSurfaceWidth = width;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 02666142e4dd..69884dc62fb3 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8273,6 +8273,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
event.setPackageName(getContext().getPackageName());
event.setEnabled(isEnabled());
event.setContentDescription(mContentDescription);
+ event.setScrollX(getScrollX());
+ event.setScrollY(getScrollY());
switch (event.getEventType()) {
case AccessibilityEvent.TYPE_VIEW_FOCUSED: {
diff --git a/core/java/android/view/ViewTreeObserver.java b/core/java/android/view/ViewTreeObserver.java
index c50a3aa8ac7c..9a5f4c9cc8b9 100644
--- a/core/java/android/view/ViewTreeObserver.java
+++ b/core/java/android/view/ViewTreeObserver.java
@@ -1074,7 +1074,7 @@ public final class ViewTreeObserver {
* be called manually if you are forcing the drawing on a View or a hierarchy of Views
* that are not attached to a Window or in the GONE state.
*
- * @return True if the current draw should be canceled and resceduled, false otherwise.
+ * @return True if the current draw should be canceled and rescheduled, false otherwise.
*/
@SuppressWarnings("unchecked")
public final boolean dispatchOnPreDraw() {
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index b382a1863af3..42275a3e3165 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -90,13 +90,13 @@ public class AccessibilityRecord {
int mItemCount = UNDEFINED;
int mFromIndex = UNDEFINED;
int mToIndex = UNDEFINED;
- int mScrollX = UNDEFINED;
- int mScrollY = UNDEFINED;
+ int mScrollX = 0;
+ int mScrollY = 0;
int mScrollDeltaX = UNDEFINED;
int mScrollDeltaY = UNDEFINED;
- int mMaxScrollX = UNDEFINED;
- int mMaxScrollY = UNDEFINED;
+ int mMaxScrollX = 0;
+ int mMaxScrollY = 0;
int mAddedCount= UNDEFINED;
int mRemovedCount = UNDEFINED;
@@ -878,10 +878,10 @@ public class AccessibilityRecord {
mItemCount = UNDEFINED;
mFromIndex = UNDEFINED;
mToIndex = UNDEFINED;
- mScrollX = UNDEFINED;
- mScrollY = UNDEFINED;
- mMaxScrollX = UNDEFINED;
- mMaxScrollY = UNDEFINED;
+ mScrollX = 0;
+ mScrollY = 0;
+ mMaxScrollX = 0;
+ mMaxScrollY = 0;
mAddedCount = UNDEFINED;
mRemovedCount = UNDEFINED;
mClassName = null;
diff --git a/core/java/android/view/inputmethod/InputMethodSystemProperty.java b/core/java/android/view/inputmethod/InputMethodSystemProperty.java
index 05143a18415c..0689806bf832 100644
--- a/core/java/android/view/inputmethod/InputMethodSystemProperty.java
+++ b/core/java/android/view/inputmethod/InputMethodSystemProperty.java
@@ -43,17 +43,6 @@ public class InputMethodSystemProperty {
*/
private static final String PROP_DEBUG_MULTI_CLIENT_IME = "persist.debug.multi_client_ime";
- /**
- * System property key for debugging purpose. The value must be empty, "1", or "0".
- *
- * <p>Values 'y', 'yes', '1', 'true' or 'on' are considered true.</p>
- *
- * <p>To set, run "adb root && adb shell setprop persist.debug.per_profile_ime 1".</p>
- *
- * <p>This value will be ignored when {@link Build#IS_DEBUGGABLE} returns {@code false}.</p>
- */
- private static final String PROP_DEBUG_PER_PROFILE_IME = "persist.debug.per_profile_ime";
-
@Nullable
private static ComponentName getMultiClientImeComponentName() {
if (Build.IS_DEBUGGABLE) {
@@ -91,19 +80,4 @@ public class InputMethodSystemProperty {
*/
@TestApi
public static final boolean MULTI_CLIENT_IME_ENABLED = (sMultiClientImeComponentName != null);
-
- /**
- * {@code true} when per-profile IME is enabled.
- * @hide
- */
- public static final boolean PER_PROFILE_IME_ENABLED;
- static {
- if (MULTI_CLIENT_IME_ENABLED) {
- PER_PROFILE_IME_ENABLED = true;
- } else if (Build.IS_DEBUGGABLE) {
- PER_PROFILE_IME_ENABLED = SystemProperties.getBoolean(PROP_DEBUG_PER_PROFILE_IME, true);
- } else {
- PER_PROFILE_IME_ENABLED = true;
- }
- }
}
diff --git a/core/java/android/view/textclassifier/ActionsModelParamsSupplier.java b/core/java/android/view/textclassifier/ActionsModelParamsSupplier.java
index 6b90588f8d25..31645672f049 100644
--- a/core/java/android/view/textclassifier/ActionsModelParamsSupplier.java
+++ b/core/java/android/view/textclassifier/ActionsModelParamsSupplier.java
@@ -60,7 +60,9 @@ public final class ActionsModelParamsSupplier implements
private boolean mParsed = true;
public ActionsModelParamsSupplier(Context context, @Nullable Runnable onChangedListener) {
- mAppContext = Preconditions.checkNotNull(context).getApplicationContext();
+ final Context appContext = Preconditions.checkNotNull(context).getApplicationContext();
+ // Some contexts don't have an app context.
+ mAppContext = appContext != null ? appContext : context;
mOnChangedListener = onChangedListener == null ? () -> {} : onChangedListener;
mSettingsObserver = new SettingsObserver(mAppContext, () -> {
synchronized (mLock) {
diff --git a/core/java/android/view/textclassifier/ConversationActions.java b/core/java/android/view/textclassifier/ConversationActions.java
index aeb99b896b11..f7f503ab60ec 100644
--- a/core/java/android/view/textclassifier/ConversationActions.java
+++ b/core/java/android/view/textclassifier/ConversationActions.java
@@ -21,10 +21,12 @@ import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
+import android.annotation.UserIdInt;
import android.app.Person;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.UserHandle;
import android.text.SpannedString;
import com.android.internal.annotations.VisibleForTesting;
@@ -316,6 +318,8 @@ public final class ConversationActions implements Parcelable {
private final List<String> mHints;
@Nullable
private String mCallingPackageName;
+ @UserIdInt
+ private int mUserId = UserHandle.USER_NULL;
@NonNull
private Bundle mExtras;
@@ -340,6 +344,7 @@ public final class ConversationActions implements Parcelable {
List<String> hints = new ArrayList<>();
in.readStringList(hints);
String callingPackageName = in.readString();
+ int userId = in.readInt();
Bundle extras = in.readBundle();
Request request = new Request(
conversation,
@@ -348,6 +353,7 @@ public final class ConversationActions implements Parcelable {
hints,
extras);
request.setCallingPackageName(callingPackageName);
+ request.setUserId(userId);
return request;
}
@@ -358,6 +364,7 @@ public final class ConversationActions implements Parcelable {
parcel.writeInt(mMaxSuggestions);
parcel.writeStringList(mHints);
parcel.writeString(mCallingPackageName);
+ parcel.writeInt(mUserId);
parcel.writeBundle(mExtras);
}
@@ -428,6 +435,25 @@ public final class ConversationActions implements Parcelable {
}
/**
+ * Sets the id of the user that sent this request.
+ * <p>
+ * Package-private for SystemTextClassifier's use.
+ * @hide
+ */
+ void setUserId(@UserIdInt int userId) {
+ mUserId = userId;
+ }
+
+ /**
+ * Returns the id of the user that sent this request.
+ * @hide
+ */
+ @UserIdInt
+ public int getUserId() {
+ return mUserId;
+ }
+
+ /**
* Returns the extended data related to this request.
*
* <p><b>NOTE: </b>Do not modify this bundle.
diff --git a/core/java/android/view/textclassifier/SelectionEvent.java b/core/java/android/view/textclassifier/SelectionEvent.java
index 374e66724ec6..80c728f662c6 100644
--- a/core/java/android/view/textclassifier/SelectionEvent.java
+++ b/core/java/android/view/textclassifier/SelectionEvent.java
@@ -19,8 +19,10 @@ package android.view.textclassifier;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.UserHandle;
import android.view.textclassifier.TextClassifier.EntityType;
import android.view.textclassifier.TextClassifier.WidgetType;
@@ -127,6 +129,7 @@ public final class SelectionEvent implements Parcelable {
private String mWidgetType = TextClassifier.WIDGET_TYPE_UNKNOWN;
private @InvocationMethod int mInvocationMethod;
@Nullable private String mWidgetVersion;
+ private @UserIdInt int mUserId = UserHandle.USER_NULL;
@Nullable private String mResultId;
private long mEventTime;
private long mDurationSinceSessionStart;
@@ -158,6 +161,7 @@ public final class SelectionEvent implements Parcelable {
mEntityType = in.readString();
mWidgetVersion = in.readInt() > 0 ? in.readString() : null;
mPackageName = in.readString();
+ mUserId = in.readInt();
mWidgetType = in.readString();
mInvocationMethod = in.readInt();
mResultId = in.readString();
@@ -184,6 +188,7 @@ public final class SelectionEvent implements Parcelable {
dest.writeString(mWidgetVersion);
}
dest.writeString(mPackageName);
+ dest.writeInt(mUserId);
dest.writeString(mWidgetType);
dest.writeInt(mInvocationMethod);
dest.writeString(mResultId);
@@ -405,6 +410,15 @@ public final class SelectionEvent implements Parcelable {
}
/**
+ * Returns the id of this event's user.
+ * @hide
+ */
+ @UserIdInt
+ public int getUserId() {
+ return mUserId;
+ }
+
+ /**
* Returns the type of widget that was involved in triggering this event.
*/
@WidgetType
@@ -430,6 +444,7 @@ public final class SelectionEvent implements Parcelable {
mPackageName = context.getPackageName();
mWidgetType = context.getWidgetType();
mWidgetVersion = context.getWidgetVersion();
+ mUserId = context.getUserId();
}
/**
@@ -616,7 +631,7 @@ public final class SelectionEvent implements Parcelable {
@Override
public int hashCode() {
return Objects.hash(mAbsoluteStart, mAbsoluteEnd, mEventType, mEntityType,
- mWidgetVersion, mPackageName, mWidgetType, mInvocationMethod, mResultId,
+ mWidgetVersion, mPackageName, mUserId, mWidgetType, mInvocationMethod, mResultId,
mEventTime, mDurationSinceSessionStart, mDurationSincePreviousEvent,
mEventIndex, mSessionId, mStart, mEnd, mSmartStart, mSmartEnd);
}
@@ -637,6 +652,7 @@ public final class SelectionEvent implements Parcelable {
&& Objects.equals(mEntityType, other.mEntityType)
&& Objects.equals(mWidgetVersion, other.mWidgetVersion)
&& Objects.equals(mPackageName, other.mPackageName)
+ && mUserId == other.mUserId
&& Objects.equals(mWidgetType, other.mWidgetType)
&& mInvocationMethod == other.mInvocationMethod
&& Objects.equals(mResultId, other.mResultId)
@@ -656,12 +672,12 @@ public final class SelectionEvent implements Parcelable {
return String.format(Locale.US,
"SelectionEvent {absoluteStart=%d, absoluteEnd=%d, eventType=%d, entityType=%s, "
+ "widgetVersion=%s, packageName=%s, widgetType=%s, invocationMethod=%s, "
- + "resultId=%s, eventTime=%d, durationSinceSessionStart=%d, "
+ + "userId=%d, resultId=%s, eventTime=%d, durationSinceSessionStart=%d, "
+ "durationSincePreviousEvent=%d, eventIndex=%d,"
+ "sessionId=%s, start=%d, end=%d, smartStart=%d, smartEnd=%d}",
mAbsoluteStart, mAbsoluteEnd, mEventType, mEntityType,
mWidgetVersion, mPackageName, mWidgetType, mInvocationMethod,
- mResultId, mEventTime, mDurationSinceSessionStart,
+ mUserId, mResultId, mEventTime, mDurationSinceSessionStart,
mDurationSincePreviousEvent, mEventIndex,
mSessionId, mStart, mEnd, mSmartStart, mSmartEnd);
}
diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java
index 8f8766e3f783..b5f972aea1d4 100644
--- a/core/java/android/view/textclassifier/SystemTextClassifier.java
+++ b/core/java/android/view/textclassifier/SystemTextClassifier.java
@@ -18,6 +18,7 @@ package android.view.textclassifier;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.content.Context;
import android.os.Bundle;
@@ -50,6 +51,10 @@ public final class SystemTextClassifier implements TextClassifier {
private final TextClassificationConstants mSettings;
private final TextClassifier mFallback;
private final String mPackageName;
+ // NOTE: Always set this before sending a request to the manager service otherwise the manager
+ // service will throw a remote exception.
+ @UserIdInt
+ private final int mUserId;
private TextClassificationSessionId mSessionId;
public SystemTextClassifier(Context context, TextClassificationConstants settings)
@@ -60,6 +65,7 @@ public final class SystemTextClassifier implements TextClassifier {
mFallback = context.getSystemService(TextClassificationManager.class)
.getTextClassifier(TextClassifier.LOCAL);
mPackageName = Preconditions.checkNotNull(context.getOpPackageName());
+ mUserId = context.getUserId();
}
/**
@@ -72,6 +78,7 @@ public final class SystemTextClassifier implements TextClassifier {
Utils.checkMainThread();
try {
request.setCallingPackageName(mPackageName);
+ request.setUserId(mUserId);
final BlockingCallback<TextSelection> callback =
new BlockingCallback<>("textselection");
mManagerService.onSuggestSelection(mSessionId, request, callback);
@@ -95,6 +102,7 @@ public final class SystemTextClassifier implements TextClassifier {
Utils.checkMainThread();
try {
request.setCallingPackageName(mPackageName);
+ request.setUserId(mUserId);
final BlockingCallback<TextClassification> callback =
new BlockingCallback<>("textclassification");
mManagerService.onClassifyText(mSessionId, request, callback);
@@ -123,6 +131,7 @@ public final class SystemTextClassifier implements TextClassifier {
try {
request.setCallingPackageName(mPackageName);
+ request.setUserId(mUserId);
final BlockingCallback<TextLinks> callback =
new BlockingCallback<>("textlinks");
mManagerService.onGenerateLinks(mSessionId, request, callback);
@@ -167,6 +176,7 @@ public final class SystemTextClassifier implements TextClassifier {
try {
request.setCallingPackageName(mPackageName);
+ request.setUserId(mUserId);
final BlockingCallback<TextLanguage> callback =
new BlockingCallback<>("textlanguage");
mManagerService.onDetectLanguage(mSessionId, request, callback);
@@ -187,6 +197,7 @@ public final class SystemTextClassifier implements TextClassifier {
try {
request.setCallingPackageName(mPackageName);
+ request.setUserId(mUserId);
final BlockingCallback<ConversationActions> callback =
new BlockingCallback<>("conversation-actions");
mManagerService.onSuggestConversationActions(mSessionId, request, callback);
@@ -228,6 +239,7 @@ public final class SystemTextClassifier implements TextClassifier {
printWriter.printPair("mFallback", mFallback);
printWriter.printPair("mPackageName", mPackageName);
printWriter.printPair("mSessionId", mSessionId);
+ printWriter.printPair("mUserId", mUserId);
printWriter.decreaseIndent();
printWriter.println();
}
@@ -243,6 +255,7 @@ public final class SystemTextClassifier implements TextClassifier {
@NonNull TextClassificationSessionId sessionId) {
mSessionId = Preconditions.checkNotNull(sessionId);
try {
+ classificationContext.setUserId(mUserId);
mManagerService.onCreateTextClassificationSession(classificationContext, mSessionId);
} catch (RemoteException e) {
Log.e(LOG_TAG, "Error starting a new classification session.", e);
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 63210516b3e1..93f7103c3d8d 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -21,6 +21,7 @@ import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.PendingIntent;
import android.app.RemoteAction;
import android.content.Context;
@@ -35,6 +36,7 @@ import android.os.Bundle;
import android.os.LocaleList;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.UserHandle;
import android.text.SpannedString;
import android.util.ArrayMap;
import android.view.View.OnClickListener;
@@ -551,6 +553,8 @@ public final class TextClassification implements Parcelable {
@Nullable private final ZonedDateTime mReferenceTime;
@NonNull private final Bundle mExtras;
@Nullable private String mCallingPackageName;
+ @UserIdInt
+ private int mUserId = UserHandle.USER_NULL;
private Request(
CharSequence text,
@@ -631,6 +635,25 @@ public final class TextClassification implements Parcelable {
}
/**
+ * Sets the id of the user that sent this request.
+ * <p>
+ * Package-private for SystemTextClassifier's use.
+ * @hide
+ */
+ void setUserId(@UserIdInt int userId) {
+ mUserId = userId;
+ }
+
+ /**
+ * Returns the id of the user that sent this request.
+ * @hide
+ */
+ @UserIdInt
+ public int getUserId() {
+ return mUserId;
+ }
+
+ /**
* Returns the extended data.
*
* <p><b>NOTE: </b>Do not modify this bundle.
@@ -730,6 +753,7 @@ public final class TextClassification implements Parcelable {
dest.writeParcelable(mDefaultLocales, flags);
dest.writeString(mReferenceTime == null ? null : mReferenceTime.toString());
dest.writeString(mCallingPackageName);
+ dest.writeInt(mUserId);
dest.writeBundle(mExtras);
}
@@ -742,11 +766,13 @@ public final class TextClassification implements Parcelable {
final ZonedDateTime referenceTime = referenceTimeString == null
? null : ZonedDateTime.parse(referenceTimeString);
final String callingPackageName = in.readString();
+ final int userId = in.readInt();
final Bundle extras = in.readBundle();
final Request request = new Request(text, startIndex, endIndex,
defaultLocales, referenceTime, extras);
request.setCallingPackageName(callingPackageName);
+ request.setUserId(userId);
return request;
}
diff --git a/core/java/android/view/textclassifier/TextClassificationContext.java b/core/java/android/view/textclassifier/TextClassificationContext.java
index 3bf8e9bd2bf0..e4baaac9a300 100644
--- a/core/java/android/view/textclassifier/TextClassificationContext.java
+++ b/core/java/android/view/textclassifier/TextClassificationContext.java
@@ -18,8 +18,10 @@ package android.view.textclassifier;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.UserHandle;
import android.view.textclassifier.TextClassifier.WidgetType;
import com.android.internal.util.Preconditions;
@@ -35,6 +37,8 @@ public final class TextClassificationContext implements Parcelable {
private final String mPackageName;
private final String mWidgetType;
@Nullable private final String mWidgetVersion;
+ @UserIdInt
+ private int mUserId = UserHandle.USER_NULL;
private TextClassificationContext(
String packageName,
@@ -54,6 +58,25 @@ public final class TextClassificationContext implements Parcelable {
}
/**
+ * Sets the id of this context's user.
+ * <p>
+ * Package-private for SystemTextClassifier's use.
+ * @hide
+ */
+ void setUserId(@UserIdInt int userId) {
+ mUserId = userId;
+ }
+
+ /**
+ * Returns the id of this context's user.
+ * @hide
+ */
+ @UserIdInt
+ public int getUserId() {
+ return mUserId;
+ }
+
+ /**
* Returns the widget type for this classification context.
*/
@NonNull
@@ -75,8 +98,8 @@ public final class TextClassificationContext implements Parcelable {
@Override
public String toString() {
return String.format(Locale.US, "TextClassificationContext{"
- + "packageName=%s, widgetType=%s, widgetVersion=%s}",
- mPackageName, mWidgetType, mWidgetVersion);
+ + "packageName=%s, widgetType=%s, widgetVersion=%s, userId=%d}",
+ mPackageName, mWidgetType, mWidgetVersion, mUserId);
}
/**
@@ -133,12 +156,14 @@ public final class TextClassificationContext implements Parcelable {
parcel.writeString(mPackageName);
parcel.writeString(mWidgetType);
parcel.writeString(mWidgetVersion);
+ parcel.writeInt(mUserId);
}
private TextClassificationContext(Parcel in) {
mPackageName = in.readString();
mWidgetType = in.readString();
mWidgetVersion = in.readString();
+ mUserId = in.readInt();
}
public static final @android.annotation.NonNull Parcelable.Creator<TextClassificationContext> CREATOR =
diff --git a/core/java/android/view/textclassifier/TextLanguage.java b/core/java/android/view/textclassifier/TextLanguage.java
index 6c75ffbea0cd..cc9109e6e9bb 100644
--- a/core/java/android/view/textclassifier/TextLanguage.java
+++ b/core/java/android/view/textclassifier/TextLanguage.java
@@ -20,10 +20,12 @@ import android.annotation.FloatRange;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.icu.util.ULocale;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.UserHandle;
import android.util.ArrayMap;
import com.android.internal.annotations.VisibleForTesting;
@@ -226,6 +228,8 @@ public final class TextLanguage implements Parcelable {
private final CharSequence mText;
private final Bundle mExtra;
@Nullable private String mCallingPackageName;
+ @UserIdInt
+ private int mUserId = UserHandle.USER_NULL;
private Request(CharSequence text, Bundle bundle) {
mText = text;
@@ -260,6 +264,25 @@ public final class TextLanguage implements Parcelable {
}
/**
+ * Sets the id of the user that sent this request.
+ * <p>
+ * Package-private for SystemTextClassifier's use.
+ * @hide
+ */
+ void setUserId(@UserIdInt int userId) {
+ mUserId = userId;
+ }
+
+ /**
+ * Returns the id of the user that sent this request.
+ * @hide
+ */
+ @UserIdInt
+ public int getUserId() {
+ return mUserId;
+ }
+
+ /**
* Returns a bundle containing non-structured extra information about this request.
*
* <p><b>NOTE: </b>Do not modify this bundle.
@@ -278,16 +301,19 @@ public final class TextLanguage implements Parcelable {
public void writeToParcel(Parcel dest, int flags) {
dest.writeCharSequence(mText);
dest.writeString(mCallingPackageName);
+ dest.writeInt(mUserId);
dest.writeBundle(mExtra);
}
private static Request readFromParcel(Parcel in) {
final CharSequence text = in.readCharSequence();
final String callingPackageName = in.readString();
+ final int userId = in.readInt();
final Bundle extra = in.readBundle();
final Request request = new Request(text, extra);
request.setCallingPackageName(callingPackageName);
+ request.setUserId(userId);
return request;
}
diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java
index f3e0dc1ed843..bbb7f07e0fdc 100644
--- a/core/java/android/view/textclassifier/TextLinks.java
+++ b/core/java/android/view/textclassifier/TextLinks.java
@@ -20,11 +20,13 @@ import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.content.Context;
import android.os.Bundle;
import android.os.LocaleList;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.UserHandle;
import android.text.Spannable;
import android.text.method.MovementMethod;
import android.text.style.ClickableSpan;
@@ -339,6 +341,8 @@ public final class TextLinks implements Parcelable {
private final boolean mLegacyFallback;
@Nullable private String mCallingPackageName;
private final Bundle mExtras;
+ @UserIdInt
+ private int mUserId = UserHandle.USER_NULL;
private Request(
CharSequence text,
@@ -410,6 +414,25 @@ public final class TextLinks implements Parcelable {
}
/**
+ * Sets the id of the user that sent this request.
+ * <p>
+ * Package-private for SystemTextClassifier's use.
+ * @hide
+ */
+ void setUserId(@UserIdInt int userId) {
+ mUserId = userId;
+ }
+
+ /**
+ * Returns the id of the user that sent this request.
+ * @hide
+ */
+ @UserIdInt
+ public int getUserId() {
+ return mUserId;
+ }
+
+ /**
* Returns the extended data.
*
* <p><b>NOTE: </b>Do not modify this bundle.
@@ -509,6 +532,7 @@ public final class TextLinks implements Parcelable {
dest.writeParcelable(mDefaultLocales, flags);
dest.writeParcelable(mEntityConfig, flags);
dest.writeString(mCallingPackageName);
+ dest.writeInt(mUserId);
dest.writeBundle(mExtras);
}
@@ -517,11 +541,13 @@ public final class TextLinks implements Parcelable {
final LocaleList defaultLocales = in.readParcelable(null);
final EntityConfig entityConfig = in.readParcelable(null);
final String callingPackageName = in.readString();
+ final int userId = in.readInt();
final Bundle extras = in.readBundle();
final Request request = new Request(text, defaultLocales, entityConfig,
/* legacyFallback= */ true, extras);
request.setCallingPackageName(callingPackageName);
+ request.setUserId(userId);
return request;
}
diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
index 75c27bdbc1d5..0c8974956a7a 100644
--- a/core/java/android/view/textclassifier/TextSelection.java
+++ b/core/java/android/view/textclassifier/TextSelection.java
@@ -20,10 +20,12 @@ import android.annotation.FloatRange;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.os.Bundle;
import android.os.LocaleList;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.UserHandle;
import android.text.SpannedString;
import android.util.ArrayMap;
import android.view.textclassifier.TextClassifier.EntityType;
@@ -211,6 +213,8 @@ public final class TextSelection implements Parcelable {
private final boolean mDarkLaunchAllowed;
private final Bundle mExtras;
@Nullable private String mCallingPackageName;
+ @UserIdInt
+ private int mUserId = UserHandle.USER_NULL;
private Request(
CharSequence text,
@@ -292,6 +296,25 @@ public final class TextSelection implements Parcelable {
}
/**
+ * Sets the id of the user that sent this request.
+ * <p>
+ * Package-private for SystemTextClassifier's use.
+ * @hide
+ */
+ void setUserId(@UserIdInt int userId) {
+ mUserId = userId;
+ }
+
+ /**
+ * Returns the id of the user that sent this request.
+ * @hide
+ */
+ @UserIdInt
+ public int getUserId() {
+ return mUserId;
+ }
+
+ /**
* Returns the extended data.
*
* <p><b>NOTE: </b>Do not modify this bundle.
@@ -394,6 +417,7 @@ public final class TextSelection implements Parcelable {
dest.writeInt(mEndIndex);
dest.writeParcelable(mDefaultLocales, flags);
dest.writeString(mCallingPackageName);
+ dest.writeInt(mUserId);
dest.writeBundle(mExtras);
}
@@ -403,11 +427,13 @@ public final class TextSelection implements Parcelable {
final int endIndex = in.readInt();
final LocaleList defaultLocales = in.readParcelable(null);
final String callingPackageName = in.readString();
+ final int userId = in.readInt();
final Bundle extras = in.readBundle();
final Request request = new Request(text, startIndex, endIndex, defaultLocales,
/* darkLaunchAllowed= */ false, extras);
request.setCallingPackageName(callingPackageName);
+ request.setUserId(userId);
return request;
}
diff --git a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
index b530ddfe86d6..157c43597a44 100644
--- a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
+++ b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
@@ -27,6 +27,7 @@ import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassifier;
import android.view.textclassifier.TextSelection;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.Preconditions;
@@ -100,7 +101,7 @@ public final class SmartSelectionEventTracker {
private boolean mSmartSelectionTriggered;
private String mModelName;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(trackingBug = 136637107)
public SmartSelectionEventTracker(@NonNull Context context, @WidgetType int widgetType) {
mWidgetType = widgetType;
mWidgetVersion = null;
@@ -119,7 +120,7 @@ public final class SmartSelectionEventTracker {
*
* @param event the selection event
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(trackingBug = 136637107)
public void logEvent(@NonNull SelectionEvent event) {
Preconditions.checkNotNull(event);
@@ -443,7 +444,7 @@ public final class SmartSelectionEventTracker {
*
* @param start the word index of the selected word
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(trackingBug = 136637107)
public static SelectionEvent selectionStarted(int start) {
return new SelectionEvent(
start, start + 1, EventType.SELECTION_STARTED,
@@ -457,7 +458,7 @@ public final class SmartSelectionEventTracker {
* @param start the start word (inclusive) index of the selection
* @param end the end word (exclusive) index of the selection
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(trackingBug = 136637107)
public static SelectionEvent selectionModified(int start, int end) {
return new SelectionEvent(
start, end, EventType.SELECTION_MODIFIED,
@@ -473,7 +474,7 @@ public final class SmartSelectionEventTracker {
* @param classification the TextClassification object returned by the TextClassifier that
* classified the selected text
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(trackingBug = 136637107)
public static SelectionEvent selectionModified(
int start, int end, @NonNull TextClassification classification) {
final String entityType = classification.getEntityCount() > 0
@@ -493,7 +494,7 @@ public final class SmartSelectionEventTracker {
* @param selection the TextSelection object returned by the TextClassifier for the
* specified selection
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(trackingBug = 136637107)
public static SelectionEvent selectionModified(
int start, int end, @NonNull TextSelection selection) {
final boolean smartSelection = getSourceClassifier(selection.getId())
@@ -522,7 +523,7 @@ public final class SmartSelectionEventTracker {
* @param end the end word (exclusive) index of the selection
* @param actionType the action that was performed on the selection
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(trackingBug = 136637107)
public static SelectionEvent selectionAction(
int start, int end, @ActionType int actionType) {
return new SelectionEvent(
@@ -540,7 +541,7 @@ public final class SmartSelectionEventTracker {
* @param classification the TextClassification object returned by the TextClassifier that
* classified the selected text
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(trackingBug = 136637107)
public static SelectionEvent selectionAction(
int start, int end, @ActionType int actionType,
@NonNull TextClassification classification) {
@@ -551,10 +552,11 @@ public final class SmartSelectionEventTracker {
return new SelectionEvent(start, end, actionType, entityType, versionTag);
}
- private static String getVersionInfo(String signature) {
- final int start = signature.indexOf("|");
+ @VisibleForTesting
+ public static String getVersionInfo(String signature) {
+ final int start = signature.indexOf("|") + 1;
final int end = signature.indexOf("|", start);
- if (start >= 0 && end >= start) {
+ if (start >= 1 && end >= start) {
return signature.substring(start, end);
}
return "";
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index 339947ac8d5a..67a70b48b534 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -26,12 +26,14 @@ import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.text.format.DateUtils;
-import android.text.format.Time;
import android.util.AttributeSet;
import android.view.View;
import android.widget.RemoteViews.RemoteView;
-import java.util.TimeZone;
+import java.time.Clock;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
/**
* This widget display an analogic clock with two hands for hours and
@@ -45,7 +47,7 @@ import java.util.TimeZone;
@RemoteView
@Deprecated
public class AnalogClock extends View {
- private Time mCalendar;
+ private Clock mClock;
@UnsupportedAppUsage
private Drawable mHourHand;
@@ -99,7 +101,7 @@ public class AnalogClock extends View {
mMinuteHand = context.getDrawable(com.android.internal.R.drawable.clock_hand_minute);
}
- mCalendar = new Time();
+ mClock = Clock.systemDefaultZone();
mDialWidth = mDial.getIntrinsicWidth();
mDialHeight = mDial.getIntrinsicHeight();
@@ -132,7 +134,7 @@ public class AnalogClock extends View {
// in the main thread, therefore the receiver can't run before this method returns.
// The time zone may have changed while the receiver wasn't registered, so update the Time
- mCalendar = new Time();
+ mClock = Clock.systemDefaultZone();
// Make sure we update to the current time
onTimeChanged();
@@ -241,17 +243,18 @@ public class AnalogClock extends View {
}
private void onTimeChanged() {
- mCalendar.setToNow();
+ long nowMillis = mClock.millis();
+ LocalDateTime localDateTime = toLocalDateTime(nowMillis, mClock.getZone());
- int hour = mCalendar.hour;
- int minute = mCalendar.minute;
- int second = mCalendar.second;
+ int hour = localDateTime.getHour();
+ int minute = localDateTime.getMinute();
+ int second = localDateTime.getSecond();
mMinutes = minute + second / 60.0f;
mHour = hour + mMinutes / 60.0f;
mChanged = true;
- updateContentDescription(mCalendar);
+ updateContentDescription(nowMillis);
}
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@@ -259,7 +262,7 @@ public class AnalogClock extends View {
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
String tz = intent.getStringExtra("time-zone");
- mCalendar = new Time(TimeZone.getTimeZone(tz).getID());
+ mClock = Clock.system(ZoneId.of(tz));
}
onTimeChanged();
@@ -268,10 +271,17 @@ public class AnalogClock extends View {
}
};
- private void updateContentDescription(Time time) {
+ private void updateContentDescription(long timeMillis) {
final int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_24HOUR;
- String contentDescription = DateUtils.formatDateTime(mContext,
- time.toMillis(false), flags);
+ String contentDescription = DateUtils.formatDateTime(mContext, timeMillis, flags);
setContentDescription(contentDescription);
}
+
+ private static LocalDateTime toLocalDateTime(long timeMillis, ZoneId zoneId) {
+ // java.time types like LocalDateTime / Instant can support the full range of "long millis"
+ // with room to spare so we do not need to worry about overflow / underflow and the
+ // resulting exceptions while the input to this class is a long.
+ Instant instant = Instant.ofEpochMilli(timeMillis);
+ return LocalDateTime.ofInstant(instant, zoneId);
+ }
}
diff --git a/core/java/android/widget/DateTimeView.java b/core/java/android/widget/DateTimeView.java
index 0469dbd00dc9..2864ad0b7932 100644
--- a/core/java/android/widget/DateTimeView.java
+++ b/core/java/android/widget/DateTimeView.java
@@ -20,7 +20,6 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.YEAR_IN_MILLIS;
-import static android.text.format.Time.getJulianDay;
import android.annotation.UnsupportedAppUsage;
import android.app.ActivityThread;
@@ -32,7 +31,6 @@ import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.os.Handler;
-import android.text.format.Time;
import android.util.AttributeSet;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.inspector.InspectableProperty;
@@ -41,10 +39,14 @@ import android.widget.RemoteViews.RemoteView;
import com.android.internal.R;
import java.text.DateFormat;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.temporal.JulianFields;
import java.util.ArrayList;
-import java.util.Calendar;
import java.util.Date;
-import java.util.TimeZone;
//
// TODO
@@ -63,8 +65,9 @@ public class DateTimeView extends TextView {
private static final int SHOW_TIME = 0;
private static final int SHOW_MONTH_DAY_YEAR = 1;
- Date mTime;
- long mTimeMillis;
+ private long mTimeMillis;
+ // The LocalDateTime equivalent of mTimeMillis but truncated to minute, i.e. no seconds / nanos.
+ private LocalDateTime mLocalTime;
int mLastDisplay = -1;
DateFormat mLastFormat;
@@ -128,11 +131,10 @@ public class DateTimeView extends TextView {
@android.view.RemotableViewMethod
@UnsupportedAppUsage
- public void setTime(long time) {
- Time t = new Time();
- t.set(time);
- mTimeMillis = t.toMillis(false);
- mTime = new Date(t.year-1900, t.month, t.monthDay, t.hour, t.minute, 0);
+ public void setTime(long timeMillis) {
+ mTimeMillis = timeMillis;
+ LocalDateTime dateTime = toLocalDateTime(timeMillis, ZoneId.systemDefault());
+ mLocalTime = dateTime.withSecond(0);
update();
}
@@ -165,7 +167,7 @@ public class DateTimeView extends TextView {
@UnsupportedAppUsage
void update() {
- if (mTime == null || getVisibility() == GONE) {
+ if (mLocalTime == null || getVisibility() == GONE) {
return;
}
if (mShowRelativeTime) {
@@ -174,31 +176,27 @@ public class DateTimeView extends TextView {
}
int display;
- Date time = mTime;
-
- Time t = new Time();
- t.set(mTimeMillis);
- t.second = 0;
-
- t.hour -= 12;
- long twelveHoursBefore = t.toMillis(false);
- t.hour += 12;
- long twelveHoursAfter = t.toMillis(false);
- t.hour = 0;
- t.minute = 0;
- long midnightBefore = t.toMillis(false);
- t.monthDay++;
- long midnightAfter = t.toMillis(false);
-
- long nowMillis = System.currentTimeMillis();
- t.set(nowMillis);
- t.second = 0;
- nowMillis = t.normalize(false);
+ ZoneId zoneId = ZoneId.systemDefault();
+
+ // localTime is the local time for mTimeMillis but at zero seconds past the minute.
+ LocalDateTime localTime = mLocalTime;
+ LocalDateTime localStartOfDay =
+ LocalDateTime.of(localTime.toLocalDate(), LocalTime.MIDNIGHT);
+ LocalDateTime localTomorrowStartOfDay = localStartOfDay.plusDays(1);
+ // now is current local time but at zero seconds past the minute.
+ LocalDateTime localNow = LocalDateTime.now(zoneId).withSecond(0);
+
+ long twelveHoursBefore = toEpochMillis(localTime.minusHours(12), zoneId);
+ long twelveHoursAfter = toEpochMillis(localTime.plusHours(12), zoneId);
+ long midnightBefore = toEpochMillis(localStartOfDay, zoneId);
+ long midnightAfter = toEpochMillis(localTomorrowStartOfDay, zoneId);
+ long time = toEpochMillis(localTime, zoneId);
+ long now = toEpochMillis(localNow, zoneId);
// Choose the display mode
choose_display: {
- if ((nowMillis >= midnightBefore && nowMillis < midnightAfter)
- || (nowMillis >= twelveHoursBefore && nowMillis < twelveHoursAfter)) {
+ if ((now >= midnightBefore && now < midnightAfter)
+ || (now >= twelveHoursBefore && now < twelveHoursAfter)) {
display = SHOW_TIME;
break choose_display;
}
@@ -227,7 +225,7 @@ public class DateTimeView extends TextView {
}
// Set the text
- String text = format.format(mTime);
+ String text = format.format(new Date(time));
setText(text);
// Schedule the next update
@@ -236,7 +234,7 @@ public class DateTimeView extends TextView {
mUpdateTimeMillis = twelveHoursAfter > midnightAfter ? twelveHoursAfter : midnightAfter;
} else {
// Currently showing the date
- if (mTimeMillis < nowMillis) {
+ if (mTimeMillis < now) {
// If the time is in the past, don't schedule an update
mUpdateTimeMillis = 0;
} else {
@@ -277,15 +275,18 @@ public class DateTimeView extends TextView {
millisIncrease = HOUR_IN_MILLIS;
} else if (duration < YEAR_IN_MILLIS) {
// In weird cases it can become 0 because of daylight savings
- TimeZone timeZone = TimeZone.getDefault();
- count = Math.max(Math.abs(dayDistance(timeZone, mTimeMillis, now)), 1);
+ LocalDateTime localDateTime = mLocalTime;
+ ZoneId zoneId = ZoneId.systemDefault();
+ LocalDateTime localNow = toLocalDateTime(now, zoneId);
+
+ count = Math.max(Math.abs(dayDistance(localDateTime, localNow)), 1);
result = String.format(getContext().getResources().getQuantityString(past
? com.android.internal.R.plurals.duration_days_shortest
: com.android.internal.R.plurals.duration_days_shortest_future,
count),
count);
if (past || count != 1) {
- mUpdateTimeMillis = computeNextMidnight(timeZone);
+ mUpdateTimeMillis = computeNextMidnight(localNow, zoneId);
millisIncrease = -1;
} else {
millisIncrease = DAY_IN_MILLIS;
@@ -311,18 +312,13 @@ public class DateTimeView extends TextView {
}
/**
- * @param timeZone the timezone we are in
- * @return the timepoint in millis at UTC at midnight in the current timezone
+ * Returns the epoch millis for the next midnight in the specified timezone.
*/
- private long computeNextMidnight(TimeZone timeZone) {
- Calendar c = Calendar.getInstance();
- c.setTimeZone(timeZone);
- c.add(Calendar.DAY_OF_MONTH, 1);
- c.set(Calendar.HOUR_OF_DAY, 0);
- c.set(Calendar.MINUTE, 0);
- c.set(Calendar.SECOND, 0);
- c.set(Calendar.MILLISECOND, 0);
- return c.getTimeInMillis();
+ private static long computeNextMidnight(LocalDateTime time, ZoneId zoneId) {
+ // This ignores the chance of overflow: it should never happen.
+ LocalDate tomorrow = time.toLocalDate().plusDays(1);
+ LocalDateTime nextMidnight = LocalDateTime.of(tomorrow, LocalTime.MIDNIGHT);
+ return toEpochMillis(nextMidnight, zoneId);
}
@Override
@@ -340,11 +336,10 @@ public class DateTimeView extends TextView {
com.android.internal.R.string.now_string_shortest);
}
- // Return the date difference for the two times in a given timezone.
- private static int dayDistance(TimeZone timeZone, long startTime,
- long endTime) {
- return getJulianDay(endTime, timeZone.getOffset(endTime) / 1000)
- - getJulianDay(startTime, timeZone.getOffset(startTime) / 1000);
+ // Return the number of days between the two dates.
+ private static int dayDistance(LocalDateTime start, LocalDateTime end) {
+ return (int) (end.getLong(JulianFields.JULIAN_DAY)
+ - start.getLong(JulianFields.JULIAN_DAY));
}
private DateFormat getTimeFormat() {
@@ -389,8 +384,11 @@ public class DateTimeView extends TextView {
count);
} else if (duration < YEAR_IN_MILLIS) {
// In weird cases it can become 0 because of daylight savings
- TimeZone timeZone = TimeZone.getDefault();
- count = Math.max(Math.abs(dayDistance(timeZone, mTimeMillis, now)), 1);
+ LocalDateTime localDateTime = mLocalTime;
+ ZoneId zoneId = ZoneId.systemDefault();
+ LocalDateTime localNow = toLocalDateTime(now, zoneId);
+
+ count = Math.max(Math.abs(dayDistance(localDateTime, localNow)), 1);
result = String.format(getContext().getResources().getQuantityString(past
? com.android.internal.
R.plurals.duration_days_relative
@@ -526,4 +524,17 @@ public class DateTimeView extends TextView {
}
}
}
+
+ private static LocalDateTime toLocalDateTime(long timeMillis, ZoneId zoneId) {
+ // java.time types like LocalDateTime / Instant can support the full range of "long millis"
+ // with room to spare so we do not need to worry about overflow / underflow and the rsulting
+ // exceptions while the input to this class is a long.
+ Instant instant = Instant.ofEpochMilli(timeMillis);
+ return LocalDateTime.ofInstant(instant, zoneId);
+ }
+
+ private static long toEpochMillis(LocalDateTime time, ZoneId zoneId) {
+ Instant instant = time.toInstant(zoneId.getRules().getOffset(time));
+ return instant.toEpochMilli();
+ }
}
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 5921feb7a758..ec685f56befa 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -951,8 +951,6 @@ public class HorizontalScrollView extends FrameLayout {
public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
super.onInitializeAccessibilityEventInternal(event);
event.setScrollable(getScrollRange() > 0);
- event.setScrollX(mScrollX);
- event.setScrollY(mScrollY);
event.setMaxScrollX(getScrollRange());
event.setMaxScrollY(mScrollY);
}
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index a3e89c85fcbc..eb93fdf5e84a 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -1010,8 +1010,6 @@ public class ScrollView extends FrameLayout {
super.onInitializeAccessibilityEventInternal(event);
final boolean scrollable = getScrollRange() > 0;
event.setScrollable(scrollable);
- event.setScrollX(mScrollX);
- event.setScrollY(mScrollY);
event.setMaxScrollX(mScrollX);
event.setMaxScrollY(getScrollRange());
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 95cf9a914854..a4844eaa612c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -11283,6 +11283,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
@Nullable
+ final TextClassificationManager getTextClassificationManagerForUser() {
+ return getServiceManagerForUser(
+ getContext().getPackageName(), TextClassificationManager.class);
+ }
+
+ @Nullable
final <T> T getServiceManagerForUser(String packageName, Class<T> managerClazz) {
if (mTextOperationUser == null) {
return getContext().getSystemService(managerClazz);
@@ -12397,8 +12403,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@NonNull
public TextClassifier getTextClassifier() {
if (mTextClassifier == null) {
- final TextClassificationManager tcm =
- mContext.getSystemService(TextClassificationManager.class);
+ final TextClassificationManager tcm = getTextClassificationManagerForUser();
if (tcm != null) {
return tcm.getTextClassifier();
}
@@ -12414,8 +12419,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@NonNull
TextClassifier getTextClassificationSession() {
if (mTextClassificationSession == null || mTextClassificationSession.isDestroyed()) {
- final TextClassificationManager tcm =
- mContext.getSystemService(TextClassificationManager.class);
+ final TextClassificationManager tcm = getTextClassificationManagerForUser();
if (tcm != null) {
final String widgetType;
if (isTextEditable()) {
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index 57785443919e..157e0a74712b 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -16,252 +16,167 @@
package com.android.internal.app;
+import android.animation.ObjectAnimator;
import android.animation.TimeAnimator;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.Intent;
+import android.content.res.ColorStateList;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.ColorFilter;
+import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
+import android.graphics.PixelFormat;
+import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
+import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
-import android.view.MotionEvent.PointerCoords;
import android.view.View;
-import android.widget.FrameLayout;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+import com.android.internal.R;
import org.json.JSONObject;
+/**
+ * @hide
+ */
public class PlatLogoActivity extends Activity {
- FrameLayout layout;
- TimeAnimator anim;
- PBackground bg;
-
- private class PBackground extends Drawable {
- private float maxRadius, radius, x, y, dp;
- private int[] palette;
- private int darkest;
- private float offset;
-
- public PBackground() {
- randomizePalette();
- }
-
- /**
- * set inner radius of "p" logo
- */
- public void setRadius(float r) {
- this.radius = Math.max(48*dp, r);
- }
-
- /**
- * move the "p"
- */
- public void setPosition(float x, float y) {
- this.x = x;
- this.y = y;
- }
-
- /**
- * for animating the "p"
- */
- public void setOffset(float o) {
- this.offset = o;
- }
-
- /**
- * rough luminance calculation
- * https://www.w3.org/TR/AERT/#color-contrast
- */
- public float lum(int rgb) {
- return ((Color.red(rgb) * 299f) + (Color.green(rgb) * 587f) + (Color.blue(rgb) * 114f)) / 1000f;
- }
-
- /**
- * create a random evenly-spaced color palette
- * guaranteed to contrast!
- */
- public void randomizePalette() {
- final int slots = 2 + (int)(Math.random() * 2);
- float[] color = new float[] { (float) Math.random() * 360f, 1f, 1f };
- palette = new int[slots];
- darkest = 0;
- for (int i=0; i<slots; i++) {
- palette[i] = Color.HSVToColor(color);
- color[0] = (color[0] + 360f/slots) % 360f;
- if (lum(palette[i]) < lum(palette[darkest])) darkest = i;
- }
-
- final StringBuilder str = new StringBuilder();
- for (int c : palette) {
- str.append(String.format("#%08x ", c));
- }
- Log.v("PlatLogoActivity", "color palette: " + str);
- }
-
- @Override
- public void draw(Canvas canvas) {
- if (dp == 0) dp = getResources().getDisplayMetrics().density;
- final float width = canvas.getWidth();
- final float height = canvas.getHeight();
- if (radius == 0) {
- setPosition(width / 2, height / 2);
- setRadius(width / 6);
- }
- final float inner_w = radius * 0.667f;
-
- final Paint paint = new Paint();
- paint.setStrokeCap(Paint.Cap.BUTT);
- canvas.translate(x, y);
-
- Path p = new Path();
- p.moveTo(-radius, height);
- p.lineTo(-radius, 0);
- p.arcTo(-radius, -radius, radius, radius, -180, 270, false);
- p.lineTo(-radius, radius);
-
- float w = Math.max(canvas.getWidth(), canvas.getHeight()) * 1.414f;
- paint.setStyle(Paint.Style.FILL);
-
- int i=0;
- while (w > radius*2 + inner_w*2) {
- paint.setColor(0xFF000000 | palette[i % palette.length]);
- // for a slower but more complete version:
- // paint.setStrokeWidth(w);
- // canvas.drawPath(p, paint);
- canvas.drawOval(-w/2, -w/2, w/2, w/2, paint);
- w -= inner_w * (1.1f + Math.sin((i/20f + offset) * 3.14159f));
- i++;
- }
-
- // the innermost circle needs to be a constant color to avoid rapid flashing
- paint.setColor(0xFF000000 | palette[(darkest+1) % palette.length]);
- canvas.drawOval(-radius, -radius, radius, radius, paint);
-
- p.reset();
- p.moveTo(-radius, height);
- p.lineTo(-radius, 0);
- p.arcTo(-radius, -radius, radius, radius, -180, 270, false);
- p.lineTo(-radius + inner_w, radius);
-
- paint.setStyle(Paint.Style.STROKE);
- paint.setStrokeWidth(inner_w*2);
- paint.setColor(palette[darkest]);
- canvas.drawPath(p, paint);
- paint.setStrokeWidth(inner_w);
- paint.setColor(0xFFFFFFFF);
- canvas.drawPath(p, paint);
- }
-
- @Override
- public void setAlpha(int alpha) {
-
- }
-
- @Override
- public void setColorFilter(ColorFilter colorFilter) {
-
- }
+ ImageView mZeroView, mOneView;
+ BackslashDrawable mBackslash;
+ int mClicks;
+
+ static final Paint sPaint = new Paint();
+ static {
+ sPaint.setStyle(Paint.Style.STROKE);
+ sPaint.setStrokeWidth(4f);
+ sPaint.setStrokeCap(Paint.Cap.SQUARE);
+ }
- @Override
- public int getOpacity() {
- return 0;
+ @Override
+ protected void onPause() {
+ if (mBackslash != null) {
+ mBackslash.stopAnimating();
}
+ mClicks = 0;
+ super.onPause();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ final float dp = getResources().getDisplayMetrics().density;
- layout = new FrameLayout(this);
- setContentView(layout);
+ getWindow().getDecorView().setSystemUiVisibility(
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
+ getWindow().setNavigationBarColor(0);
+ getWindow().setStatusBarColor(0);
- bg = new PBackground();
- layout.setBackground(bg);
+ getActionBar().hide();
- final ContentResolver cr = getContentResolver();
+ setContentView(R.layout.platlogo_layout);
- layout.setOnTouchListener(new View.OnTouchListener() {
- final String TOUCH_STATS = "touch.stats";
+ mBackslash = new BackslashDrawable((int) (50 * dp));
- final PointerCoords pc0 = new PointerCoords();
- final PointerCoords pc1 = new PointerCoords();
+ mOneView = findViewById(R.id.one);
+ mOneView.setImageDrawable(new OneDrawable());
+ mZeroView = findViewById(R.id.zero);
+ mZeroView.setImageDrawable(new ZeroDrawable());
- double pressure_min, pressure_max;
- int maxPointers;
- int tapCount;
+ final ViewGroup root = (ViewGroup) mOneView.getParent();
+ root.setClipChildren(false);
+ root.setBackground(mBackslash);
+ root.getBackground().setAlpha(0x20);
+ View.OnTouchListener tl = new View.OnTouchListener() {
+ float mOffsetX, mOffsetY;
+ long mClickTime;
+ ObjectAnimator mRotAnim;
@Override
public boolean onTouch(View v, MotionEvent event) {
- final float pressure = event.getPressure();
+ measureTouchPressure(event);
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
- pressure_min = pressure_max = pressure;
- // fall through
- case MotionEvent.ACTION_MOVE:
- if (pressure < pressure_min) pressure_min = pressure;
- if (pressure > pressure_max) pressure_max = pressure;
- final int pc = event.getPointerCount();
- if (pc > maxPointers) maxPointers = pc;
- if (pc > 1) {
- event.getPointerCoords(0, pc0);
- event.getPointerCoords(1, pc1);
- bg.setRadius((float) Math.hypot(pc0.x - pc1.x, pc0.y - pc1.y) / 2f);
+ v.animate().scaleX(1.1f).scaleY(1.1f);
+ v.getParent().bringChildToFront(v);
+ mOffsetX = event.getRawX() - v.getX();
+ mOffsetY = event.getRawY() - v.getY();
+ long now = System.currentTimeMillis();
+ if (now - mClickTime < 350) {
+ mRotAnim = ObjectAnimator.ofFloat(v, View.ROTATION,
+ v.getRotation(), v.getRotation() + 3600);
+ mRotAnim.setDuration(10000);
+ mRotAnim.start();
+ mClickTime = 0;
+ } else {
+ mClickTime = now;
}
break;
- case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_MOVE:
+ v.setX(event.getRawX() - mOffsetX);
+ v.setY(event.getRawY() - mOffsetY);
+ v.performHapticFeedback(HapticFeedbackConstants.TEXT_HANDLE_MOVE);
+ break;
case MotionEvent.ACTION_UP:
- try {
- final String touchDataJson = Settings.System.getString(cr, TOUCH_STATS);
- final JSONObject touchData = new JSONObject(
- touchDataJson != null ? touchDataJson : "{}");
- if (touchData.has("min")) {
- pressure_min = Math.min(pressure_min, touchData.getDouble("min"));
- }
- if (touchData.has("max")) {
- pressure_max = Math.max(pressure_max, touchData.getDouble("max"));
- }
- touchData.put("min", pressure_min);
- touchData.put("max", pressure_max);
- Settings.System.putString(cr, TOUCH_STATS, touchData.toString());
- } catch (Exception e) {
- Log.e("PlatLogoActivity", "Can't write touch settings", e);
- }
-
- if (maxPointers == 1) {
- tapCount ++;
- if (tapCount < 7) {
- bg.randomizePalette();
- } else {
- launchNextStage();
- }
- } else {
- tapCount = 0;
- }
- maxPointers = 0;
+ v.performClick();
+ // fall through
+ case MotionEvent.ACTION_CANCEL:
+ v.animate().scaleX(1f).scaleY(1f);
+ if (mRotAnim != null) mRotAnim.cancel();
+ testOverlap();
break;
}
return true;
}
- });
+ };
+
+ findViewById(R.id.one).setOnTouchListener(tl);
+ findViewById(R.id.zero).setOnTouchListener(tl);
+ findViewById(R.id.text).setOnTouchListener(tl);
+ }
+
+ private void testOverlap() {
+ final float width = mZeroView.getWidth();
+ final float targetX = mZeroView.getX() + width * .2f;
+ final float targetY = mZeroView.getY() + width * .3f;
+ if (Math.hypot(targetX - mOneView.getX(), targetY - mOneView.getY()) < width * .2f
+ && Math.abs(mOneView.getRotation() % 360 - 315) < 15) {
+ mOneView.animate().x(mZeroView.getX() + width * .2f);
+ mOneView.animate().y(mZeroView.getY() + width * .3f);
+ mOneView.setRotation(mOneView.getRotation() % 360);
+ mOneView.animate().rotation(315);
+ mOneView.performHapticFeedback(HapticFeedbackConstants.CONFIRM);
+
+ mBackslash.startAnimating();
+
+ mClicks++;
+ if (mClicks >= 7) {
+ launchNextStage();
+ }
+ } else {
+ mBackslash.stopAnimating();
+ }
}
private void launchNextStage() {
final ContentResolver cr = getContentResolver();
- if (Settings.System.getLong(cr, Settings.System.EGG_MODE, 0) == 0) {
+ if (Settings.System.getLong(cr, "egg_mode" /* Settings.System.EGG_MODE */, 0) == 0) {
// For posterity: the moment this user unlocked the easter egg
try {
Settings.System.putLong(cr,
- Settings.System.EGG_MODE,
+ "egg_mode", // Settings.System.EGG_MODE,
System.currentTimeMillis());
} catch (RuntimeException e) {
- Log.e("PlatLogoActivity", "Can't write settings", e);
+ Log.e("com.android.internal.app.PlatLogoActivity", "Can't write settings", e);
}
}
try {
@@ -270,36 +185,206 @@ public class PlatLogoActivity extends Activity {
| Intent.FLAG_ACTIVITY_CLEAR_TASK)
.addCategory("com.android.internal.category.PLATLOGO"));
} catch (ActivityNotFoundException ex) {
- Log.e("PlatLogoActivity", "No more eggs.");
+ Log.e("com.android.internal.app.PlatLogoActivity", "No more eggs.");
}
finish();
}
+ static final String TOUCH_STATS = "touch.stats";
+ double mPressureMin = 0, mPressureMax = -1;
+
+ private void measureTouchPressure(MotionEvent event) {
+ final float pressure = event.getPressure();
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ if (mPressureMax < 0) {
+ mPressureMin = mPressureMax = pressure;
+ }
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (pressure < mPressureMin) mPressureMin = pressure;
+ if (pressure > mPressureMax) mPressureMax = pressure;
+ break;
+ }
+ }
+
+ private void syncTouchPressure() {
+ try {
+ final String touchDataJson = Settings.System.getString(
+ getContentResolver(), TOUCH_STATS);
+ final JSONObject touchData = new JSONObject(
+ touchDataJson != null ? touchDataJson : "{}");
+ if (touchData.has("min")) {
+ mPressureMin = Math.min(mPressureMin, touchData.getDouble("min"));
+ }
+ if (touchData.has("max")) {
+ mPressureMax = Math.max(mPressureMax, touchData.getDouble("max"));
+ }
+ if (mPressureMax >= 0) {
+ touchData.put("min", mPressureMin);
+ touchData.put("max", mPressureMax);
+ Settings.System.putString(getContentResolver(), TOUCH_STATS, touchData.toString());
+ }
+ } catch (Exception e) {
+ Log.e("com.android.internal.app.PlatLogoActivity", "Can't write touch settings", e);
+ }
+ }
+
@Override
public void onStart() {
super.onStart();
+ syncTouchPressure();
+ }
- bg.randomizePalette();
+ @Override
+ public void onStop() {
+ syncTouchPressure();
+ super.onStop();
+ }
- anim = new TimeAnimator();
- anim.setTimeListener(
- new TimeAnimator.TimeListener() {
- @Override
- public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
- bg.setOffset((float) totalTime / 60000f);
- bg.invalidateSelf();
- }
- });
+ static class ZeroDrawable extends Drawable {
+ int mTintColor;
+
+ @Override
+ public void draw(Canvas canvas) {
+ sPaint.setColor(mTintColor | 0xFF000000);
+
+ canvas.save();
+ canvas.scale(canvas.getWidth() / 24f, canvas.getHeight() / 24f);
+
+ canvas.drawCircle(12f, 12f, 10f, sPaint);
+ canvas.restore();
+ }
- anim.start();
+ @Override
+ public void setAlpha(int alpha) { }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) { }
+
+ @Override
+ public void setTintList(ColorStateList tint) {
+ mTintColor = tint.getDefaultColor();
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
}
- @Override
- public void onStop() {
- if (anim != null) {
- anim.cancel();
- anim = null;
+ static class OneDrawable extends Drawable {
+ int mTintColor;
+
+ @Override
+ public void draw(Canvas canvas) {
+ sPaint.setColor(mTintColor | 0xFF000000);
+
+ canvas.save();
+ canvas.scale(canvas.getWidth() / 24f, canvas.getHeight() / 24f);
+
+ final Path p = new Path();
+ p.moveTo(12f, 21.83f);
+ p.rLineTo(0f, -19.67f);
+ p.rLineTo(-5f, 0f);
+ canvas.drawPath(p, sPaint);
+ canvas.restore();
+ }
+
+ @Override
+ public void setAlpha(int alpha) { }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) { }
+
+ @Override
+ public void setTintList(ColorStateList tint) {
+ mTintColor = tint.getDefaultColor();
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+ }
+
+ private static class BackslashDrawable extends Drawable implements TimeAnimator.TimeListener {
+ Bitmap mTile;
+ Paint mPaint = new Paint();
+ BitmapShader mShader;
+ TimeAnimator mAnimator = new TimeAnimator();
+ Matrix mMatrix = new Matrix();
+
+ public void draw(Canvas canvas) {
+ canvas.drawPaint(mPaint);
+ }
+
+ BackslashDrawable(int width) {
+ mTile = Bitmap.createBitmap(width, width, Bitmap.Config.ALPHA_8);
+ mAnimator.setTimeListener(this);
+
+ final Canvas tileCanvas = new Canvas(mTile);
+ final float w = tileCanvas.getWidth();
+ final float h = tileCanvas.getHeight();
+
+ final Path path = new Path();
+ path.moveTo(0, 0);
+ path.lineTo(w / 2, 0);
+ path.lineTo(w, h / 2);
+ path.lineTo(w, h);
+ path.close();
+
+ path.moveTo(0, h / 2);
+ path.lineTo(w / 2, h);
+ path.lineTo(0, h);
+ path.close();
+
+ final Paint slashPaint = new Paint();
+ slashPaint.setAntiAlias(true);
+ slashPaint.setStyle(Paint.Style.FILL);
+ slashPaint.setColor(0xFF000000);
+ tileCanvas.drawPath(path, slashPaint);
+
+ //mPaint.setColor(0xFF0000FF);
+ mShader = new BitmapShader(mTile, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
+ mPaint.setShader(mShader);
+ }
+
+ public void startAnimating() {
+ if (!mAnimator.isStarted()) {
+ mAnimator.start();
+ }
+ }
+
+ public void stopAnimating() {
+ if (mAnimator.isStarted()) {
+ mAnimator.cancel();
+ }
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ mPaint.setAlpha(alpha);
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ mPaint.setColorFilter(colorFilter);
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+
+ @Override
+ public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
+ if (mShader != null) {
+ mMatrix.postTranslate(deltaTime / 4f, 0);
+ mShader.setLocalMatrix(mMatrix);
+ invalidateSelf();
+ }
}
- super.onStop();
}
}
+
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index f905ea2dc6f2..58ce03baa136 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -889,7 +889,8 @@ public class ResolverActivity extends Activity {
: mAdapterView.getCheckedItemPosition();
boolean hasIndexBeenFiltered = !mAdapter.hasFilteredItem();
ResolveInfo ri = mAdapter.resolveInfoForPosition(which, hasIndexBeenFiltered);
- if (!ri.handleAllWebDataURI && id == R.id.button_always) {
+ if (mUseLayoutForBrowsables
+ && !ri.handleAllWebDataURI && id == R.id.button_always) {
showSettingsForSelected(ri);
} else {
startSelected(which, id == R.id.button_always, hasIndexBeenFiltered);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 457308498398..88d0e8534a0a 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -3478,10 +3478,8 @@ public class BatteryStatsImpl extends BatteryStats {
if (deltaTimeToken < DELTA_TIME_ABS) {
cur.time += deltaTimeToken;
} else if (deltaTimeToken == DELTA_TIME_ABS) {
- cur.time = src.readLong();
- cur.numReadInts += 2;
- if (DEBUG) Slog.i(TAG, "READ DELTA: ABS time=" + cur.time);
cur.readFromParcel(src);
+ if (DEBUG) Slog.i(TAG, "READ DELTA: ABS time=" + cur.time);
return;
} else if (deltaTimeToken == DELTA_TIME_INT) {
int delta = src.readInt();
@@ -13459,9 +13457,8 @@ public class BatteryStatsImpl extends BatteryStats {
return;
}
mHistory = mHistoryEnd = mHistoryCache = null;
- long time;
- while (in.dataAvail() > 0 && (time=in.readLong()) >= 0) {
- HistoryItem rec = new HistoryItem(time, in);
+ while (in.dataAvail() > 0) {
+ HistoryItem rec = new HistoryItem(in);
addHistoryRecordLocked(rec);
}
}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 866cfb735bae..244d5da9968c 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -188,13 +188,6 @@ public class ZygoteInit {
System.loadLibrary("android");
System.loadLibrary("compiler_rt");
System.loadLibrary("jnigraphics");
-
- // tolerate missing sfplugin_ccodec which is only present on Codec 2 devices
- try {
- System.loadLibrary("sfplugin_ccodec");
- } catch (Error | RuntimeException e) {
- Log.w(TAG, "Problem preloading sfplugin_ccodec: " + e);
- }
}
native private static void nativePreloadAppProcessHALs();
diff --git a/core/java/com/android/internal/policy/PipSnapAlgorithm.java b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
index 5b6b619ed7d2..1afc67b3de9b 100644
--- a/core/java/com/android/internal/policy/PipSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
@@ -24,8 +24,6 @@ import android.graphics.PointF;
import android.graphics.Rect;
import android.util.Size;
import android.view.Gravity;
-import android.view.ViewConfiguration;
-import android.widget.Scroller;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -180,14 +178,6 @@ public class PipSnapAlgorithm {
// If we're not flinging along the current edge, find the closest point instead.
final double distanceVert = Math.hypot(vertPoint.x - x, vertPoint.y - y);
final double distanceHoriz = Math.hypot(horizPoint.x - x, horizPoint.y - y);
- // Ensure that we're actually going somewhere
- if (distanceVert == 0) {
- return horizPoint;
- }
- if (distanceHoriz == 0) {
- return vertPoint;
- }
- // Otherwise use the closest point
return Math.abs(distanceVert) > Math.abs(distanceHoriz) ? horizPoint : vertPoint;
}
diff --git a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
index adf7692adc56..52172cf04362 100644
--- a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
+++ b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
@@ -36,13 +36,16 @@ public class ScreenDecorationsUtils {
}
// Radius that should be used in case top or bottom aren't defined.
- float defaultRadius = resources.getDimension(R.dimen.rounded_corner_radius);
+ float defaultRadius = resources.getDimension(R.dimen.rounded_corner_radius)
+ - resources.getDimension(R.dimen.rounded_corner_radius_adjustment);
- float topRadius = resources.getDimension(R.dimen.rounded_corner_radius_top);
+ float topRadius = resources.getDimension(R.dimen.rounded_corner_radius_top)
+ - resources.getDimension(R.dimen.rounded_corner_radius_top_adjustment);
if (topRadius == 0f) {
topRadius = defaultRadius;
}
- float bottomRadius = resources.getDimension(R.dimen.rounded_corner_radius_bottom);
+ float bottomRadius = resources.getDimension(R.dimen.rounded_corner_radius_bottom)
+ - resources.getDimension(R.dimen.rounded_corner_radius_bottom_adjustment);
if (bottomRadius == 0f) {
bottomRadius = defaultRadius;
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 5eb840879e96..d42c43b53067 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -33,17 +33,14 @@ cc_library_shared {
srcs: [
"android_animation_PropertyValuesHolder.cpp",
- "android_content_res_ApkAssets.cpp",
"android_graphics_Canvas.cpp",
"android_graphics_ColorSpace.cpp",
"android_graphics_drawable_AnimatedVectorDrawable.cpp",
"android_graphics_drawable_VectorDrawable.cpp",
"android_graphics_Picture.cpp",
"android_nio_utils.cpp",
- "android_os_MessageQueue.cpp",
"android_os_SystemClock.cpp",
"android_os_SystemProperties.cpp",
- "android_os_Trace.cpp",
"android_util_EventLog.cpp",
"android_util_Log.cpp",
"android_util_PathParser.cpp",
@@ -76,9 +73,6 @@ cc_library_shared {
"android/graphics/fonts/FontFamily.cpp",
"android/graphics/text/LineBreaker.cpp",
"android/graphics/text/MeasuredText.cpp",
- "android_util_AssetManager.cpp",
- "android_util_StringBlock.cpp",
- "android_util_XmlBlock.cpp",
"com_android_internal_util_VirtualRefBasePtr.cpp",
"com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp",
],
@@ -176,18 +170,23 @@ cc_library_shared {
"android_os_HwRemoteBinder.cpp",
"android_os_NativeHandle.cpp",
"android_os_MemoryFile.cpp",
+ "android_os_MessageQueue.cpp",
"android_os_Parcel.cpp",
"android_os_SELinux.cpp",
"android_os_SharedMemory.cpp",
+ "android_os_Trace.cpp",
"android_os_UEventObserver.cpp",
"android_os_VintfObject.cpp",
"android_os_VintfRuntimeInfo.cpp",
"android_net_LocalSocketImpl.cpp",
"android_net_NetUtils.cpp",
+ "android_util_AssetManager.cpp",
"android_util_Binder.cpp",
"android_util_StatsLog.cpp",
"android_util_MemoryIntArray.cpp",
"android_util_Process.cpp",
+ "android_util_StringBlock.cpp",
+ "android_util_XmlBlock.cpp",
"android_util_jar_StrictJarFile.cpp",
"android/graphics/AnimatedImageDrawable.cpp",
"android/graphics/Camera.cpp",
@@ -243,6 +242,7 @@ cc_library_shared {
"android_backup_FileBackupHelperBase.cpp",
"android_backup_BackupHelperDispatcher.cpp",
"android_app_backup_FullBackup.cpp",
+ "android_content_res_ApkAssets.cpp",
"android_content_res_ObbScanner.cpp",
"android_content_res_Configuration.cpp",
"android_security_Scrypt.cpp",
@@ -355,5 +355,15 @@ cc_library_shared {
"libutils",
],
},
+ linux_glibc: {
+ srcs: [
+ "android_content_res_ApkAssets.cpp",
+ "android_os_MessageQueue.cpp",
+ "android_os_Trace.cpp",
+ "android_util_AssetManager.cpp",
+ "android_util_StringBlock.cpp",
+ "android_util_XmlBlock.cpp",
+ ],
+ },
},
}
diff --git a/core/jni/LayoutlibLoader.cpp b/core/jni/LayoutlibLoader.cpp
index eb700355ff0e..549fd4db8b76 100644
--- a/core/jni/LayoutlibLoader.cpp
+++ b/core/jni/LayoutlibLoader.cpp
@@ -91,10 +91,12 @@ struct RegJNIRec {
// The actual list of registered classes will be determined at runtime via the 'native_classes' System property
static const std::unordered_map<std::string, RegJNIRec> gRegJNIMap = {
{"android.animation.PropertyValuesHolder", REG_JNI(register_android_animation_PropertyValuesHolder)},
+#ifdef __linux__
{"android.content.AssetManager", REG_JNI(register_android_content_AssetManager)},
{"android.content.StringBlock", REG_JNI(register_android_content_StringBlock)},
{"android.content.XmlBlock", REG_JNI(register_android_content_XmlBlock)},
{"android.content.res.ApkAssets", REG_JNI(register_android_content_res_ApkAssets)},
+#endif
{"android.graphics.Bitmap", REG_JNI(register_android_graphics_Bitmap)},
{"android.graphics.BitmapFactory", REG_JNI(register_android_graphics_BitmapFactory)},
{"android.graphics.ByteBufferStreamAdaptor", REG_JNI(register_android_graphics_ByteBufferStreamAdaptor)},
@@ -125,10 +127,14 @@ static const std::unordered_map<std::string, RegJNIRec> gRegJNIMap = {
{"android.graphics.fonts.FontFamily", REG_JNI(register_android_graphics_fonts_FontFamily)},
{"android.graphics.text.LineBreaker", REG_JNI(register_android_graphics_text_LineBreaker)},
{"android.graphics.text.MeasuredText", REG_JNI(register_android_graphics_text_MeasuredText)},
+#ifdef __linux__
{"android.os.MessageQueue", REG_JNI(register_android_os_MessageQueue)},
+#endif
{"android.os.SystemClock", REG_JNI(register_android_os_SystemClock)},
{"android.os.SystemProperties", REG_JNI(register_android_os_SystemProperties)},
+#ifdef __linux__
{"android.os.Trace", REG_JNI(register_android_os_Trace)},
+#endif
{"android.util.EventLog", REG_JNI(register_android_util_EventLog)},
{"android.util.Log", REG_JNI(register_android_util_Log)},
{"android.util.PathParser", REG_JNI(register_android_util_PathParser)},
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 14dbabb1ce02..c3e7a36bef78 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -575,7 +575,7 @@ static void android_os_Debug_getMemInfo(JNIEnv *env, jobject clazz, jlongArray o
if (outArray != NULL) {
outLen = MEMINFO_COUNT;
for (int i = 0; i < outLen; i++) {
- if (i == MEMINFO_VMALLOC_USED) {
+ if (i == MEMINFO_VMALLOC_USED && mem[i] == 0) {
outArray[i] = smi.ReadVmallocInfo() / 1024;
continue;
}
diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp
index 2542286635e6..f90d1cf27d7c 100644
--- a/core/jni/android_view_InputEventSender.cpp
+++ b/core/jni/android_view_InputEventSender.cpp
@@ -141,6 +141,7 @@ status_t NativeInputEventSender::sendMotionEvent(uint32_t seq, const MotionEvent
event->getClassification(),
event->getXOffset(), event->getYOffset(),
event->getXPrecision(), event->getYPrecision(),
+ event->getRawXCursorPosition(), event->getRawYCursorPosition(),
event->getDownTime(), event->getHistoricalEventTime(i),
event->getPointerCount(), event->getPointerProperties(),
event->getHistoricalRawPointerCoords(0, i));
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 50cff5c46da3..8ddbe724217c 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -375,6 +375,7 @@ static jlong android_view_MotionEvent_nativeInitialize(JNIEnv* env, jclass clazz
event->initialize(deviceId, source, displayId, action, 0, flags, edgeFlags, metaState,
buttonState, static_cast<MotionClassification>(classification),
xOffset, yOffset, xPrecision, yPrecision,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
downTimeNanos, eventTimeNanos, pointerCount, pointerProperties, rawPointerCoords);
return reinterpret_cast<jlong>(event);
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index ccb840d122df..b0443a850550 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -42,7 +42,6 @@
#include <system/window.h>
#include <FrameInfo.h>
-#include <IContextFactory.h>
#include <Picture.h>
#include <Properties.h>
#include <RootRenderNode.h>
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 5a57163d0e4b..784e85414e00 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -175,6 +175,11 @@ message ConstantsProto {
// is now set to 1, to prevent any batching at this level. Since we now do
// batching through doze, that is a much better mechanism.
optional int32 min_ready_jobs_count = 7;
+ // Minimum # of non-ACTIVE jobs for which the JMS will be happy running some work early.
+ optional int32 min_ready_non_active_jobs_count = 29;
+ // Don't batch a non-ACTIVE job if it's been delayed due to force batching attempts for
+ // at least this amount of time.
+ optional int64 max_non_active_job_batch_delay_ms = 30;
// This is the job execution factor that is considered to be heavy use of
// the system.
optional double heavy_use_factor = 8;
@@ -307,6 +312,8 @@ message ConstantsProto {
// In this time after screen turns on, we increase job concurrency.
optional int32 screen_off_job_concurrency_increase_delay_ms = 28;
+
+ // Next tag: 31
}
// Next tag: 4
@@ -938,7 +945,15 @@ message JobStatusDumpProto {
optional int64 internal_flags = 24;
- // Next tag: 28
+ // Amount of time since this job was first deferred due to standby bucketing policy. Will be
+ // 0 if this job was never deferred.
+ optional int64 time_since_first_deferral_ms = 28;
+
+ // Amount of time since JobScheduler first tried to force batch this job. Will be 0 if there
+ // was no attempt.
+ optional int64 time_since_first_force_batch_attempt_ms = 29;
+
+ // Next tag: 30
}
// Dump from com.android.server.job.JobConcurrencyManager.
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index dea80920e11a..119d5ea33dc3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -724,6 +724,10 @@
<!-- Allows an application to send SMS messages.
<p>Protection level: dangerous
+
+ <p> This is a hard restricted permission which cannot be held by an app until
+ the installer on record did not whitelist the permission. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
-->
<permission android:name="android.permission.SEND_SMS"
android:permissionGroup="android.permission-group.UNDEFINED"
@@ -734,6 +738,10 @@
<!-- Allows an application to receive SMS messages.
<p>Protection level: dangerous
+
+ <p> This is a hard restricted permission which cannot be held by an app until
+ the installer on record did not whitelist the permission. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
-->
<permission android:name="android.permission.RECEIVE_SMS"
android:permissionGroup="android.permission-group.UNDEFINED"
@@ -744,6 +752,10 @@
<!-- Allows an application to read SMS messages.
<p>Protection level: dangerous
+
+ <p> This is a hard restricted permission which cannot be held by an app until
+ the installer on record did not whitelist the permission. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
-->
<permission android:name="android.permission.READ_SMS"
android:permissionGroup="android.permission-group.UNDEFINED"
@@ -754,6 +766,10 @@
<!-- Allows an application to receive WAP push messages.
<p>Protection level: dangerous
+
+ <p> This is a hard restricted permission which cannot be held by an app until
+ the installer on record did not whitelist the permission. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
-->
<permission android:name="android.permission.RECEIVE_WAP_PUSH"
android:permissionGroup="android.permission-group.UNDEFINED"
@@ -763,7 +779,11 @@
android:protectionLevel="dangerous" />
<!-- Allows an application to monitor incoming MMS messages.
- <p>Protection level: dangerous
+ <p>Protection level: dangerous
+
+ <p> This is a hard restricted permission which cannot be held by an app until
+ the installer on record did not whitelist the permission. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
-->
<permission android:name="android.permission.RECEIVE_MMS"
android:permissionGroup="android.permission-group.UNDEFINED"
@@ -783,6 +803,11 @@
when the alert is first received, and to delay presenting the info
to the user until after the initial alert dialog is dismissed.
<p>Protection level: dangerous
+
+ <p> This is a hard restricted permission which cannot be held by an app until
+ the installer on record did not whitelist the permission. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
+
@hide Pending API council approval -->
<permission android:name="android.permission.READ_CELL_BROADCASTS"
android:permissionGroup="android.permission-group.UNDEFINED"
@@ -805,30 +830,35 @@
android:priority="900" />
<!-- Allows an application to read from external storage.
- <p>Any app that declares the {@link #WRITE_EXTERNAL_STORAGE} permission is implicitly
- granted this permission.</p>
- <p>This permission is enforced starting in API level 19. Before API level 19, this
- permission is not enforced and all apps still have access to read from external storage.
- You can test your app with the permission enforced by enabling <em>Protect USB
- storage</em> under Developer options in the Settings app on a device running Android 4.1 or
- higher.</p>
- <p>Also starting in API level 19, this permission is <em>not</em> required to
- read/write files in your application-specific directories returned by
- {@link android.content.Context#getExternalFilesDir} and
- {@link android.content.Context#getExternalCacheDir}.
- <p class="note"><strong>Note:</strong> If <em>both</em> your <a
- href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
- minSdkVersion}</a> and <a
- href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
- targetSdkVersion}</a> values are set to 3 or lower, the system implicitly
- grants your app this permission. If you don't need this permission, be sure your <a
- href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
- targetSdkVersion}</a> is 4 or higher.
- <p>Is this permission is not whitelisted for an app that targets an API level before
- {@link android.os.Build.VERSION_CODES#Q} this permission cannot be granted to apps.</p>
- <p>Is this permission is not whitelisted for an app that targets an API level
- {@link android.os.Build.VERSION_CODES#Q} or later the app will be forced into isolated storage.
- </p>
+ <p>Any app that declares the {@link #WRITE_EXTERNAL_STORAGE} permission is implicitly
+ granted this permission.</p>
+ <p>This permission is enforced starting in API level 19. Before API level 19, this
+ permission is not enforced and all apps still have access to read from external storage.
+ You can test your app with the permission enforced by enabling <em>Protect USB
+ storage</em> under Developer options in the Settings app on a device running Android 4.1 or
+ higher.</p>
+ <p>Also starting in API level 19, this permission is <em>not</em> required to
+ read/write files in your application-specific directories returned by
+ {@link android.content.Context#getExternalFilesDir} and
+ {@link android.content.Context#getExternalCacheDir}.
+ <p class="note"><strong>Note:</strong> If <em>both</em> your <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
+ minSdkVersion}</a> and <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+ targetSdkVersion}</a> values are set to 3 or lower, the system implicitly
+ grants your app this permission. If you don't need this permission, be sure your <a
+ href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+ targetSdkVersion}</a> is 4 or higher.
+
+ <p> This is a soft restricted permission which cannot be held by an app it its
+ full form until the installer on record did not whitelist the permission.
+ Specifically, if the permission is whitelisted the holder app can access
+ external storage and the visual and aural media collections while if the
+ permission is not whitelisted the holder app can only access to the visual
+ and aural medial collections. Also the permission is immutably restricted
+ meaning that the whitelist state can be specified only at install time and
+ cannot change until the app is installed. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
-->
<permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:permissionGroup="android.permission-group.UNDEFINED"
@@ -916,6 +946,10 @@
{@link #ACCESS_FINE_LOCATION}. Requesting this permission by itself doesn't give you
location access.
<p>Protection level: dangerous
+
+ <p> This is a hard restricted permission which cannot be held by an app until
+ the installer on record did not whitelist the permission. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
-->
<permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"
android:permissionGroup="android.permission-group.UNDEFINED"
@@ -958,6 +992,10 @@
href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
targetSdkVersion}</a> is 16 or higher.</p>
<p>Protection level: dangerous
+
+ <p> This is a hard restricted permission which cannot be held by an app until
+ the installer on record did not whitelist the permission. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
-->
<permission android:name="android.permission.READ_CALL_LOG"
android:permissionGroup="android.permission-group.UNDEFINED"
@@ -978,6 +1016,10 @@
href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
targetSdkVersion}</a> is 16 or higher.</p>
<p>Protection level: dangerous
+
+ <p> This is a hard restricted permission which cannot be held by an app until
+ the installer on record did not whitelist the permission. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
-->
<permission android:name="android.permission.WRITE_CALL_LOG"
android:permissionGroup="android.permission-group.UNDEFINED"
@@ -991,6 +1033,10 @@
abort the call altogether.
<p>Protection level: dangerous
+ <p> This is a hard restricted permission which cannot be held by an app until
+ the installer on record did not whitelist the permission. For more details see
+ {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
+
@deprecated Applications should use {@link android.telecom.CallRedirectionService} instead
of the {@link android.content.Intent#ACTION_NEW_OUTGOING_CALL} broadcast.
-->
@@ -4610,8 +4656,9 @@
android:process=":ui">
</activity>
<activity android:name="com.android.internal.app.PlatLogoActivity"
- android:theme="@style/Theme.Wallpaper.NoTitleBar.Fullscreen"
+ android:theme="@style/Theme.DeviceDefault.DayNight"
android:configChanges="orientation|keyboardHidden"
+ android:icon="@drawable/platlogo"
android:process=":ui">
</activity>
<activity android:name="com.android.internal.app.DisableCarModeActivity"
diff --git a/core/res/res/anim/lock_screen_behind_enter_subtle.xml b/core/res/res/anim/lock_screen_behind_enter_subtle.xml
index 23b26b791a57..f9f69b12514c 100644
--- a/core/res/res/anim/lock_screen_behind_enter_subtle.xml
+++ b/core/res/res/anim/lock_screen_behind_enter_subtle.xml
@@ -23,9 +23,11 @@
android:fromAlpha="0.0" android:toAlpha="1.0"
android:fillEnabled="true" android:fillBefore="true"
android:interpolator="@interpolator/linear"
+ android:startOffset="80"
android:duration="233"/>
<translate android:fromYDelta="5%p" android:toYDelta="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/fast_out_slow_in"
+ android:startOffset="80"
android:duration="233" />
</set> \ No newline at end of file
diff --git a/core/res/res/drawable-nodpi/android_logotype.xml b/core/res/res/drawable-nodpi/android_logotype.xml
new file mode 100644
index 000000000000..bd298e48ef34
--- /dev/null
+++ b/core/res/res/drawable-nodpi/android_logotype.xml
@@ -0,0 +1,42 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="290dp"
+ android:height="64dp"
+ android:viewportWidth="290.0"
+ android:viewportHeight="64.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M21.81,28.91c-7.44,0,-12.45,5.85,-12.45,13.37c0,7.52,5.01,13.37,12.45,13.37s12.45,-5.85,12.45,-13.37 C34.26,34.76,29.24,28.91,21.81,28.91 M20.13,20.55c6.02,0,11.03,3.09,13.37,6.43v-5.6l9.19,0l0,41.78l-6.24,0 c-1.63,0,-2.95,-1.32,-2.95,-2.95v-2.65C31.17,60.91,26.15,64,20.14,64C8.69,64,0,54.23,0,42.28C0,30.33,8.69,20.55,20.13,20.55"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M53.13,21.39l9.19,0l0,5.68c2.5,-4.18,7.27,-6.52,12.7,-6.52c9.69,0,15.96,6.85,15.96,17.46l0,25.15l-6.24,0 c-1.63,0,-2.95,-1.32,-2.95,-2.95l0,-20.7c0,-6.6,-3.34,-10.61,-8.69,-10.61c-6.1,0,-10.78,4.76,-10.78,13.7l0,20.55l-6.25,0 c-1.63,0,-2.95,-1.32,-2.95,-2.95L53.13,21.39z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M120.06,28.91c-7.43,0,-12.45,5.85,-12.45,13.37c0,7.52,5.01,13.37,12.45,13.37c7.43,0,12.45,-5.85,12.45,-13.37 C132.51,34.76,127.5,28.91,120.06,28.91 M118.39,20.55c6.02,0,11.03,3.09,13.37,6.43l0,-26.49l9.19,0l0,62.66h-6.24 c-1.63,0,-2.95,-1.32,-2.95,-2.95v-2.65c-2.34,3.34,-7.35,6.43,-13.37,6.43c-11.45,0,-20.14,-9.77,-20.14,-21.72 C98.25,30.33,106.94,20.55,118.39,20.55"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M151.39,21.39l9.19,0v7.44c1.59,-4.76,6.27,-7.86,11.03,-7.86c1.17,0,2.34,0.08,3.59,0.34v9.44c-1.59,-0.5,-2.92,-0.75,-4.59,-0.75 c-5.26,0,-10.03,4.43,-10.03,12.78l0,20.39l-6.24,0c-1.63,0,-2.95,-1.32,-2.95,-2.95L151.39,21.39z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M199.98,55.48c7.35,0,12.53,-5.77,12.53,-13.2c0,-7.44,-5.18,-13.2,-12.53,-13.2c-7.44,0,-12.62,5.77,-12.62,13.2 C187.37,49.71,192.55,55.48,199.98,55.48 M199.98,64c-12.37,0,-21.89,-9.61,-21.89,-21.72c0,-12.12,9.52,-21.73,21.89,-21.73 c12.37,0,21.89,9.61,21.89,21.73C221.87,54.39,212.35,64,199.98,64"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M229.32,21.39l9.19,0l0,41.78l-6.24,0c-1.63,0,-2.95,-1.32,-2.95,-2.95L229.32,21.39z M233.92,12.28 c-3.34,0,-6.18,-2.76,-6.18,-6.18c0,-3.34,2.84,-6.1,6.18,-6.1c3.43,0,6.1,2.76,6.1,6.1C240.02,9.53,237.34,12.28,233.92,12.28"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M267.87,28.91c-7.43,0,-12.45,5.85,-12.45,13.37c0,7.52,5.01,13.37,12.45,13.37c7.44,0,12.45,-5.85,12.45,-13.37 C280.32,34.76,275.31,28.91,267.87,28.91 M266.2,20.55c6.02,0,11.03,3.09,13.37,6.43l0,-26.49l9.19,0l0,62.66l-6.24,0 c-1.63,0,-2.95,-1.32,-2.95,-2.95v-2.65c-2.34,3.34,-7.35,6.43,-13.37,6.43c-11.44,0,-20.14,-9.77,-20.14,-21.72S254.76,20.55,266.2,20.55"/>
+</vector>
diff --git a/core/res/res/drawable-nodpi/platlogo.xml b/core/res/res/drawable-nodpi/platlogo.xml
index f5bbadcce06b..19a296a0e46b 100644
--- a/core/res/res/drawable-nodpi/platlogo.xml
+++ b/core/res/res/drawable-nodpi/platlogo.xml
@@ -1,5 +1,5 @@
<!--
-Copyright (C) 2018 The Android Open Source Project
+Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,21 +13,15 @@ Copyright (C) 2018 The Android Open Source Project
See the License for the specific language governing permissions and
limitations under the License.
-->
-<vector
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:name="vector"
- android:width="640dp"
- android:height="640dp"
- android:viewportWidth="64"
- android:viewportHeight="64">
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
<path
- android:name="bg"
- android:pathData="M 27 43 L 32 43 C 38.075 43 43 38.075 43 32 C 43 25.925 38.075 21 32 21 C 25.925 21 21 25.925 21 32 L 21 64"
- android:strokeColor="#6823a1"
- android:strokeWidth="16"/>
+ android:fillColor="#FF000000"
+ android:pathData="M19.45,22.89l-10.250001,-10.249999l-2.6599998,2.6599998l-1.77,-1.7600002l4.43,-4.4300003l12.0199995,12.0199995l-1.7699986,1.7600002z"/>
<path
- android:name="fg"
- android:pathData="M 29 43 L 32 43 C 38.075 43 43 38.075 43 32 C 43 25.925 38.075 21 32 21 C 25.925 21 21 25.925 21 32 L 21 64"
- android:strokeColor="#ff0000"
- android:strokeWidth="8"/>
+ android:fillColor="#FF000000"
+ android:pathData="M12,6a6,6 0,1 1,-6 6,6 6,0 0,1 6,-6m0,-2.5A8.5,8.5 0,1 0,20.5 12,8.51 8.51,0 0,0 12,3.5Z"/>
</vector>
diff --git a/core/res/res/layout/platlogo_layout.xml b/core/res/res/layout/platlogo_layout.xml
new file mode 100644
index 000000000000..4a4ad751e421
--- /dev/null
+++ b/core/res/res/layout/platlogo_layout.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipChildren="false"
+ android:background="@android:color/transparent">
+ <ImageView
+ android:id="@+id/text"
+ android:layout_width="400dp"
+ android:layout_height="wrap_content"
+ android:translationY="-100dp"
+ android:adjustViewBounds="true"
+ android:layout_marginBottom="-80dp"
+ android:layout_centerInParent="true"
+ android:src="@drawable/android_logotype"
+ android:tint="?android:attr/textColorPrimary"
+ />
+ <ImageView
+ android:id="@+id/one"
+ android:layout_width="200dp"
+ android:layout_height="200dp"
+ android:layout_marginLeft="24dp"
+ android:layout_below="@id/text"
+ android:layout_alignLeft="@id/text"
+ android:tint="?android:attr/textColorPrimary"
+ />
+ <ImageView
+ android:id="@+id/zero"
+ android:layout_width="200dp"
+ android:layout_height="200dp"
+ android:layout_marginRight="34dp"
+ android:layout_below="@id/text"
+ android:layout_alignRight="@id/text"
+ android:tint="?android:attr/textColorPrimary"
+ />
+</RelativeLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 74f0e68ca498..7a0d475a7285 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Beweeg foon na links."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Beweeg foon na regs."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Kyk asseblief meer reguit na jou toestel."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Kan nie jou gesig sien nie. Kyk na die foon."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Posisioneer jou gesig direk voor die foon."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Te veel beweging. Hou foon stil."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Skryf jou gesig asseblief weer in."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Kan nie meer gesig herken nie. Probeer weer."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Maak oop met"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Maak oop met %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Maak oop"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Maak <xliff:g id="HOST">%1$s</xliff:g>-skakels oop met"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Maak skakels oop met"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Maak skakels oop met <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Maak <xliff:g id="HOST">%1$s</xliff:g>-skakels oop met <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Verleen toegang"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Redigeer met"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redigeer met %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Begin webblaaier?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Aanvaar oproep?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Altyd"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Stel om altyd oop te maak"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Net een keer"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Instellings"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s steun nie werkprofiel nie"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index af0ed28ca379..11ab44de7fea 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"ስልክን ወደ ግራ ያንቀሳቅሱ።"</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"ስልክን ወደ ቀኝ ያንቀሳቅሱ።"</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"እባክዎ መሣሪያዎን ይበልጥ በቀጥታ ይመልከቱ።"</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"የእርስዎን ፊት መመልከት አይችልም። ስልኩ ላይ ይመልከቱ።"</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"መልክዎን በቀጥታ ከስልኩ ፊት ያድርጉት።"</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"ከልክ በላይ ብዙ እንቅስቃሴ። ስልኩን ቀጥ አድርገው ይያዙት።"</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"እባክዎ ፊትዎን እንደገና ያስመዝግቡ"</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"ከእንግዲህ ፊትን ለይቶ ማወቅ አይችልም። እንደገና ይሞክሩ።"</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"ክፈት በ"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"ክፈት በ%1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"ክፈት"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> አገናኞችን ክፈት ከዚህ ጋር"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"አገናኞችን ክፈት ከዚህ ጋር"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"አገናኞችን ከ <xliff:g id="APPLICATION">%1$s</xliff:g> ጋር ክፈት"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g> አገናኞችን ከ <xliff:g id="APPLICATION">%2$s</xliff:g> ጋር ክፈት"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"መዳረሻ ስጥ"</string>
<string name="whichEditApplication" msgid="144727838241402655">"ያርትዑ በ"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"ያርትዑ በ%1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"ማሰሺያን አስነሳ?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"ጥሪ ተቀበል?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"ዘወትር"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"ሁልጊዜ ክፍት ወደ የሚል ተቀናብሯል"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"አንዴ ብቻ"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"ቅንብሮች"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s የስራ መገለጫ አይደግፍም"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 603239fc0936..6edc9339008c 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -580,7 +580,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"يُرجى نقل الهاتف إلى اليمين."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"يُرجى نقل الهاتف إلى اليسار."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"يُرجى النظر إلى جهازك مباشرة أكثر."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"يتعذّر رؤية وجهك. يُرجى النظر إلى الهاتف."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"ضع وجهك أمام الهاتف مباشرة."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"حركة أكثر من اللازم يُرجى حمل بدون حركة."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"يُرجى إعادة تسجيل وجهك."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"لم يعُد يمكن التعرّف على الوجه. حاول مرة أخرى."</string>
@@ -1211,14 +1211,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"فتح باستخدام"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"‏فتح باستخدام %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"فتح"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"فتح روابط <xliff:g id="HOST">%1$s</xliff:g> باستخدام"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"فتح الروابط باستخدام"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"فتح الروابط باستخدام <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"فتح روابط <xliff:g id="HOST">%1$s</xliff:g> باستخدام <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"منح إذن الوصول"</string>
<string name="whichEditApplication" msgid="144727838241402655">"تعديل باستخدام"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"‏تعديل باستخدام %1$s"</string>
@@ -1682,8 +1678,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"تشغيل المتصفح؟"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"هل تريد قبول المكالمة؟"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"دومًا"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"ضبط على الفتح دائمًا"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"مرة واحدة فقط"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"الإعدادات"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"‏لا يدعم %1$s الملفات الشخصية للعمل"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index b126468c3869..36604039d884 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"ফ’নটো বাওঁফালে নিয়ক।"</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"ফ’নটো সোঁফালে নিয়ক।"</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"আপোনাৰ ডিভাইচটোলৈ অধিক পোনে পোনে চাওক।"</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"আপোনাৰ মুখমণ্ডল দেখা নাই। ফ’নটোলৈ চাওক।"</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"আপোনাৰ মুখখন পোনপটীয়াকৈ ফ’নটোৰ সন্মুখত ৰাখক।"</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"বেছি লৰচৰ কৰি আছে। ফ’নটো স্থিৰকৈ ধৰক।"</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"আপোনাৰ মুখমণ্ডল পুনৰ পঞ্জীয়ন কৰক।"</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"মুখমণ্ডল আৰু চিনাক্ত কৰিব নোৱাৰি। আকৌ চেষ্টা কৰক।"</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"ইয়াৰ জৰিয়তে খোলক"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$sৰ জৰিয়তে খোলক"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"খোলক"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> লিংকসমূহ ইয়াৰ জৰিয়তে খোলক"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"লিংকসমূহ ইয়াৰ জৰিয়তে খোলক"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"লিংকসমূহ <xliff:g id="APPLICATION">%1$s</xliff:g>ৰ জৰিয়তে খোলক"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g> লিংকসমূহ <xliff:g id="APPLICATION">%2$s</xliff:g>ৰ জৰিয়তে খোলক"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"এক্সেছ দিয়ক"</string>
<string name="whichEditApplication" msgid="144727838241402655">"ইয়াৰ দ্বাৰা সম্পাদনা কৰক"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sৰদ্বাৰা সম্পাদনা কৰক"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"ব্ৰাউজাৰ লঞ্চ কৰিবনে?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"কল স্বীকাৰ কৰিবনে?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"সদায়"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"সদায় খোলক-লৈ ছেট কৰক"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"মাত্ৰ এবাৰ"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"ছেটিংসমূহ"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$sএ কৰ্মস্থানৰ প্ৰ\'ফাইল সমৰ্থন নকৰে।"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index f372fec14a44..e2b399850af7 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Telefonu sola hərəkət etdirin."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Telefonu sağa hərəkət etdirin."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Birbaşa cihaza baxın."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Üzünüz görünmür. Telefona baxın."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Üzünüzü telefonun qarşısında sabit saxlayın."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Cihaz stabil deyil. Telefonu tərpətməyin."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Üzünüzü yenidən qeydiyyatdan keçirin."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Üzü artıq tanımaq olmur. Yenidən cəhd edin."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Bununla açın"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ilə açın"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Açın"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> linklərini belə açın:"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Linkləri belə açın:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Linkləri <xliff:g id="APPLICATION">%1$s</xliff:g> ilə açın"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g> linklərini <xliff:g id="APPLICATION">%2$s</xliff:g> ilə açın"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"İcazə verin"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Bununla düzəliş edin:"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ilə düzəliş edin"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Brauzer işə salınsın?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Zəngi qəbul edək?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Həmişə"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"\"Həmişə açıq\" olaraq ayarlayın"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Sadəcə bir dəfə"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ayarlar"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s iş profilini dəstəkləmir"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index b4faae72fa2b..821b73039c89 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -571,7 +571,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Pomerite telefon ulevo."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Pomerite telefon udesno."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Gledajte pravo u uređaj."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Ne vidi se lice. Gledajte u telefon."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Postavite lice direktno ispred telefona"</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Mnogo se pomerate. Držite telefon mirno."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Ponovo registrujte lice."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Više ne može da se prepozna lice. Probajte ponovo."</string>
@@ -1151,14 +1151,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Otvorite pomoću"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otvorite pomoću aplikacije %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otvori"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Otvarajte <xliff:g id="HOST">%1$s</xliff:g> linkove pomoću"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Otvaratej linkove pomoću"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Otvarajte linkove pomoću aplikacije <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Otvarajte <xliff:g id="HOST">%1$s</xliff:g> linkove pomoću aplikacije <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Dozvoli pristup"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Izmenite pomoću"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Izmenite pomoću aplikacije %1$s"</string>
@@ -1613,8 +1609,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Želite li da pokrenete pregledač?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Želite li da prihvatite poziv?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Uvek"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Podesi na „uvek otvaraj“"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Samo jednom"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Podešavanja"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne podržava poslovni profil"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 996a02b13350..d5732028981e 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -574,7 +574,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Перамясціце тэлефон улева."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Перамясціце тэлефон управа."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Глядзіце прама на экран прылады."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Не відаць твару. Глядзіце на тэлефон."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Трымайце тэлефон прама перад тварам."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Трымайце прыладу нерухома. Трымайце тэлефон роўна."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Паўтарыце рэгістрацыю твару."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Не ўдаецца распазнаць твар. Паўтарыце спробу."</string>
@@ -1171,14 +1171,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Адкрыць з дапамогай"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Адкрыць з дапамогай %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Адкрыць"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Адкрываць спасылкі <xliff:g id="HOST">%1$s</xliff:g> з дапамогай"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Адкрываць спасылкі з дапамогай"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Адкрываць спасылкі з дапамогай праграмы \"<xliff:g id="APPLICATION">%1$s</xliff:g>\""</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Адкрываць спасылкі <xliff:g id="HOST">%1$s</xliff:g>з дапамогай праграмы \"<xliff:g id="APPLICATION">%2$s</xliff:g>\""</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Даць доступ"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Рэдагаваць з дапамогай"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Рэдагаваць з дапамогай %1$s"</string>
@@ -1636,8 +1632,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Запусцiць браўзер?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Прыняць выклік?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Заўсёды"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Прызначыць стандартна для адкрыцця"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Толькі адзін раз"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Налады"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не падтрымлівае працоўны профіль"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index e4e1e808ae48..e073b7d9948b 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Преместете телефона наляво."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Преместете телефона надясно."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Моля, гледайте точно към устройството си."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Лицето ви не се вижда. Погледнете към телефона."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Позиционирайте лицето си директно пред телефона."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Твърде много движение. Дръжте телефона неподвижно."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Моля, регистрирайте лицето си отново."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Лицето не бе разпознато. Опитайте отново."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Отваряне чрез"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Отваряне чрез %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Отваряне"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Отваряне на връзките от <xliff:g id="HOST">%1$s</xliff:g> посредством"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Отваряне на връзките посредством"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Отваряне на връзките посредством <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Отваряне на връзките от <xliff:g id="HOST">%1$s</xliff:g> посредством <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Даване на достъп"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Редактиране чрез"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Редактиране чрез %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Да се стартира ли браузърът?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Да се приеме ли обаждането?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Винаги"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Задаване винаги да се отваря"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Само веднъж"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Настройки"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не поддържа служебен потребителски профил"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index ca4d12237544..368ff90b5368 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"ফোনটি বাঁদিকে সরান।"</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"ফোনটি ডানদিকে সরান।"</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"সরাসরি ডিভাইসের দিকে তাকান।"</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"আপনার মুখ দেখা যাচ্ছে না। ফোনের দিকে তাকান।"</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"আপনার মুখ সরাসরি ফোনের সামনে রাখুন।"</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"খুব বেশি নড়ছে। ফোনটি যাতে না কাঁপে সেইভাবে ধরুন।"</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"আপনার মুখের ছবি আবার নথিভুক্ত করুন।"</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"আর মুখ চিনতে পারবেন না। আবার চেষ্টা করুন।"</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"এর মাধ্যমে খুলুন"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s দিয়ে খুলুন"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"খুলুন"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"এই ব্রাউজারে <xliff:g id="HOST">%1$s</xliff:g> লিঙ্কটি খুলুন"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"এই ব্রাউজারে লিঙ্কটি খুলুন"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"<xliff:g id="APPLICATION">%1$s</xliff:g>-এ লিঙ্ক খুলুন"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="APPLICATION">%2$s</xliff:g>-এ <xliff:g id="HOST">%1$s</xliff:g> লিঙ্কটি খুলুন"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"অ্যাক্সেস দিন"</string>
<string name="whichEditApplication" msgid="144727838241402655">"এর মাধ্যমে সম্পাদনা করুন"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s দিয়ে সম্পাদনা করুন"</string>
@@ -1591,8 +1587,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"ব্রাউজার লঞ্চ করতে চান?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"কল গ্রহণ করবেন?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"সবসময়"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"\'সবসময় খোলা থাকবে\' হিসেবে সেট করুন"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"শুধু একবার"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"সেটিংস"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s কর্মস্থলের প্রোফাইল সমর্থন করে না।"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index fd441287bb39..ce852b6a01dd 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -127,7 +127,7 @@
<item msgid="3910386316304772394">"Da biste pozivali i slali poruke koristeći WiFi mrežu, prvo zatražite od operatera da postavi tu uslugu. Zatim ponovo uključite pozivanje putem WiFi-ja u Postavkama. (Kôd greške: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
</string-array>
<string-array name="wfcOperatorErrorNotificationMessages">
- <item msgid="7372514042696663278">"Došlo je do problema prilikom registracije pozivanja putem WiFi mreže kod vašeg operatera: <xliff:g id="CODE">%1$s</xliff:g>"</item>
+ <item msgid="7372514042696663278">"Došlo je do problema prilikom registracije pozivanja putem WiFi mreže kod vašeg mobilnog operatera: <xliff:g id="CODE">%1$s</xliff:g>"</item>
</string-array>
<!-- no translation found for wfcSpnFormat_spn (4998685024207291232) -->
<skip />
@@ -571,7 +571,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Pomjerite telefon ulijevo."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Pomjerite telefon udesno."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Gledajte direktno u uređaj."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Ne vidi se lice. Gledajte u telefon."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Postavite lice direktno ispred telefona"</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Previše pokreta. Držite telefon mirno."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Ponovo registrirajte lice."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Nije više moguće prepoznati lice. Pokušajte opet."</string>
@@ -802,7 +802,7 @@
<string name="quick_contacts_not_available" msgid="746098007828579688">"Nije pronađena aplikacija za pregled ovog kontakta."</string>
<string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"Unesite PIN"</string>
<string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Unesite PUK i novi PIN"</string>
- <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK"</string>
+ <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK kôd"</string>
<string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Novi PIN"</string>
<string name="keyguard_password_entry_touch_hint" msgid="2644215452200037944"><font size="17">"Dodirnite za unos lozinke"</font></string>
<string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Unesite lozinku za otključavanje tipkovnice"</string>
@@ -894,7 +894,7 @@
<string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"Otključavanje licem."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"Otključavanje pinom."</string>
<string name="keyguard_accessibility_sim_pin_unlock" msgid="9149698847116962307">"Otključavanje Pin-om za Sim."</string>
- <string name="keyguard_accessibility_sim_puk_unlock" msgid="9106899279724723341">"Otključavanje Puk-om za Sim."</string>
+ <string name="keyguard_accessibility_sim_puk_unlock" msgid="9106899279724723341">"Otključavanje SIM-a PUK-om"</string>
<string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"Otključavanje lozinkom."</string>
<string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"Uzorak oblasti."</string>
<string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"Oblast za pomjeranje klizača."</string>
@@ -1151,14 +1151,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Otvori koristeći"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otvori koristeći %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otvori"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Otvaranje <xliff:g id="HOST">%1$s</xliff:g> linkova pomoću"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Otvaranje linkova pomoću"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Otvaranje linkova pomoću aplikacije <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Otvaranje <xliff:g id="HOST">%1$s</xliff:g> linkova pomoću aplikacije <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Dozvoli pristup"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Uredi koristeći"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Uredi koristeći %1$s"</string>
@@ -1547,7 +1543,7 @@
<string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Povećaj sate"</string>
<string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Smanji sate"</string>
<string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Postavi za poslijepodne (PM)"</string>
- <string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Postavi za prijepodne (AM)"</string>
+ <string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Postavi za prijepodne"</string>
<string name="date_picker_increment_month_button" msgid="5369998479067934110">"Povećaj mjesece"</string>
<string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Smanji mjesece"</string>
<string name="date_picker_increment_day_button" msgid="7130465412308173903">"Povećaj dane"</string>
@@ -1615,8 +1611,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Pokretanje preglednika?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Prihvatiti poziv?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Uvijek"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Postavi da se uvijek otvara"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Samo ovaj put"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Postavke"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne podržava poslovni profil"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 1638fd82c243..7cfcaf4c8809 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Mou el telèfon cap a l\'esquerra."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Mou el telèfon cap a la dreta."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Mira més directament cap al dispositiu."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"No se\'t veu la cara. Mira el telèfon."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Posa la cara directament davant del telèfon."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Massa moviment. Subjecta bé el telèfon."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Torna a registrar la teva cara."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Ja no es reconeix la teva cara. Torna-ho a provar."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Obre amb"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Obre amb %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Obre"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Obre els enllaços de <xliff:g id="HOST">%1$s</xliff:g> amb"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Obre els enllaços amb"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Obre els enllaços amb <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Obre els enllaços de <xliff:g id="HOST">%1$s</xliff:g> amb <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Dona accés"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Edita amb"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edita amb %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Vols iniciar el navegador?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Vols acceptar la trucada?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Obre sempre"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Només una vegada"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configuració"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s no admet perfils professionals."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 5208e5bc1c3a..4171a8bce984 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -574,7 +574,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Přesuňte telefon vlevo."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Přesuňte telefon vpravo."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Dívejte se přímo na zařízení."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Obličej není vidět. Podívejte se na telefon."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Umístěte obličej přímo před telefon."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Příliš mnoho pohybu. Držte telefon nehybně."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Zaznamenejte obličej znovu."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Obličej už nelze rozpoznat. Zkuste to znovu."</string>
@@ -1171,14 +1171,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Otevřít v aplikaci"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otevřít v aplikaci %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otevřít"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Odkazy <xliff:g id="HOST">%1$s</xliff:g> otevírat pomocí aplikace"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Odkazy otevírat pomocí aplikace"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Odkazy otevírat pomocí aplikace <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Odkazy <xliff:g id="HOST">%1$s</xliff:g> otevírat pomocí aplikace <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Udělit přístup"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Upravit v aplikaci"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Upravit v aplikaci %1$s"</string>
@@ -1636,8 +1632,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Spustit prohlížeč?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Přijmout hovor?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Vždy"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Nastavit na Otevírat vždy"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Pouze jednou"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Nastavení"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s pracovní profily nepodporuje."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 401fa4f75334..b6cb874eb647 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Flyt telefonen til venstre."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Flyt telefonen til højre."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Kig mere direkte på din enhed."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Dit ansigt kan ikke registreres. Kig på telefonen."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Sørg for, at dit ansigt er direkte foran telefonen."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Der er for meget bevægelse. Hold telefonen stille."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Registrer dit ansigt igen."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Ansigtet kan ikke længere genkendes. Prøv igen."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Åbn med"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Åbn med %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Åbn"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Åbn <xliff:g id="HOST">%1$s</xliff:g>-links med"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Åbn links med"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Åbn links med <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Åbn <xliff:g id="HOST">%1$s</xliff:g>-links med <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Giv adgang"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Rediger med"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Rediger med %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Vil du starte browseren?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Vil du besvare opkaldet?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Altid"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Angiv som altid åben"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Kun én gang"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Indstillinger"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s understøtter ikke arbejdsprofil"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 67c179dc5e95..5316d13a9fcf 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -316,15 +316,15 @@
<string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Fensterinhalte abrufen"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Die Inhalte eines Fensters, mit dem du interagierst, werden abgerufen."</string>
<string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"\"Tippen &amp; Entdecken\" aktivieren"</string>
- <string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"Berührte Elemente werden laut vorgelesen und der Bildschirm kann über Gesten erkundet werden."</string>
+ <string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"Berührte Elemente werden laut vorgelesen und der Bildschirm kann über Touch-Gesten erkundet werden."</string>
<string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Text bei der Eingabe beobachten"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Einschließlich personenbezogener Daten wie Kreditkartennummern und Passwörter."</string>
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Displayvergrößerung festlegen"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Legt die Zoom-Stufe und -Position auf dem Display fest."</string>
- <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Gesten möglich"</string>
- <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Tippen, Wischen, Zusammenziehen und andere Gesten möglich."</string>
- <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Bewegungen auf dem Fingerabdrucksensor"</string>
- <string name="capability_desc_canCaptureFingerprintGestures" msgid="4386487962402228670">"Erfasst Bewegungen auf dem Fingerabdrucksensor des Geräts."</string>
+ <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Touch-Gesten möglich"</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Tippen, Wischen, Zusammenziehen und andere Touch-Gesten möglich."</string>
+ <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Fingerabdrucksensor-Gesten"</string>
+ <string name="capability_desc_canCaptureFingerprintGestures" msgid="4386487962402228670">"Erfasst Touch-Gesten auf dem Fingerabdrucksensor des Geräts."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"Statusleiste deaktivieren oder ändern"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Ermöglicht der App, die Statusleiste zu deaktivieren oder Systemsymbole hinzuzufügen oder zu entfernen"</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"Statusleiste darstellen"</string>
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Beweg das Smartphone nach links."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Beweg das Smartphone nach rechts."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Bitte sieh direkt auf dein Gerät."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Gesicht wurde nicht gefunden. Blicke aufs Telefon."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Halte dein Gesicht direkt vor dein Smartphone."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Zu viel Unruhe. Halte das Smartphone ruhig."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Bitte registriere dein Gesicht noch einmal."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Gesicht wird nicht mehr erkannt. Erneut versuchen."</string>
@@ -971,8 +971,8 @@
<string name="searchview_description_submit" msgid="2688450133297983542">"Anfrage senden"</string>
<string name="searchview_description_voice" msgid="2453203695674994440">"Sprachsuche"</string>
<string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"\"Tippen &amp; Entdecken\" aktivieren?"</string>
- <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> fordert die Aktivierung von \"Tippen &amp; Entdecken\" an. Wenn \"Tippen &amp; Entdecken\" aktiviert ist, kannst du Beschreibungen dessen hören oder sehen, was sich unter deinen Fingern befindet, oder Gesten ausführen, um mit dem Tablet zu kommunizieren."</string>
- <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> fordert die Aktivierung von \"Tippen &amp; Entdecken\" an. Wenn \"Tippen &amp; Entdecken\" aktiviert ist, kannst du Beschreibungen dessen hören oder sehen, was sich unter deinen Fingern befindet, oder Gesten ausführen, um mit dem Telefon zu kommunizieren."</string>
+ <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> fordert die Aktivierung von \"Tippen &amp; Entdecken\" an. Wenn \"Tippen &amp; Entdecken\" aktiviert ist, kannst du Beschreibungen dessen hören oder sehen, was sich unter deinen Fingern befindet, oder über Touch-Gesten mit dem Tablet kommunizieren."</string>
+ <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> fordert die Aktivierung von \"Tippen &amp; Entdecken\" an. Wenn \"Tippen &amp; Entdecken\" aktiviert ist, kannst du Beschreibungen dessen hören oder sehen, was sich unter deinen Fingern befindet, oder über Touch-Gesten mit dem Telefon kommunizieren."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Vor 1 Monat"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Vor mehr als 1 Monat"</string>
<plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Öffnen mit"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Mit %1$s öffnen"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Öffnen"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Links von <xliff:g id="HOST">%1$s</xliff:g> öffnen mit"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Links öffnen mit"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Links mit <xliff:g id="APPLICATION">%1$s</xliff:g> öffnen"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Links von <xliff:g id="HOST">%1$s</xliff:g> mit <xliff:g id="APPLICATION">%2$s</xliff:g> öffnen"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Zugriff erlauben"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Bearbeiten mit"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Mit %1$s bearbeiten"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Browser starten?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Anruf annehmen?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Immer"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Auf \"Immer geöffnet\" festlegen"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Nur diesmal"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Einstellungen"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Das Arbeitsprofil wird von %1$s nicht unterstützt."</string>
@@ -1675,8 +1670,8 @@
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g> wurde durch die Bedienungshilfenverknüpfung deaktiviert"</string>
<string name="accessibility_shortcut_spoken_feedback" msgid="8376923232350078434">"Halten Sie beide Lautstärketasten drei Sekunden lang gedrückt, um <xliff:g id="SERVICE_NAME">%1$s</xliff:g> zu verwenden"</string>
<string name="accessibility_button_prompt_text" msgid="1176658502969738564">"Wähle den Dienst aus, der verwendet werden soll, wenn du auf die Schaltfläche für die Bedienungshilfen tippst:"</string>
- <string name="accessibility_gesture_prompt_text" msgid="8259145549733019401">"Wähle den Dienst aus, der mit der Bewegung für die Bedienungshilfen verwendet werden soll (mit zwei Fingern vom unteren Bildschirmrand nach oben wischen):"</string>
- <string name="accessibility_gesture_3finger_prompt_text" msgid="1041435574275047665">"Wähle den Dienst aus, der mit der Geste für die Bedienungshilfen verwendet werden soll (mit drei Fingern vom unteren Bildschirmrand nach oben wischen):"</string>
+ <string name="accessibility_gesture_prompt_text" msgid="8259145549733019401">"Wähle den Dienst aus, der mit der Touch-Geste für die Bedienungshilfen verwendet werden soll (mit zwei Fingern vom unteren Bildschirmrand nach oben wischen):"</string>
+ <string name="accessibility_gesture_3finger_prompt_text" msgid="1041435574275047665">"Wähle den Dienst aus, der mit der Touch-Geste für die Bedienungshilfen verwendet werden soll (mit drei Fingern vom unteren Bildschirmrand nach oben wischen):"</string>
<string name="accessibility_button_instructional_text" msgid="7003212763213614833">"Wenn du zwischen den Diensten wechseln möchtest, halte die Schaltfläche für die Bedienungshilfen gedrückt."</string>
<string name="accessibility_gesture_instructional_text" msgid="5261788874937410950">"Wenn du zwischen den Diensten wechseln möchtest, wische mit zwei Fingern nach oben und halte sie gedrückt."</string>
<string name="accessibility_gesture_3finger_instructional_text" msgid="4969448938984394550">"Wenn du zwischen den Diensten wechseln möchtest, wische mit drei Fingern nach oben und halte sie gedrückt."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 87d08444db0a..44357ff161b5 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Μετακινήστε το τηλέφωνο στα αριστερά."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Μετακινήστε το τηλέφωνο στα δεξιά."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Κοιτάξτε απευθείας τη συσκευή σας."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Δεν εντοπίστηκε το πρόσωπό σας. Δείτε το τηλέφωνο."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Στρέψτε το πρόσωπό σάς απευθείας στο τηλέφωνο."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Πάρα πολλή κίνηση. Κρατήστε σταθερό το τηλέφωνο."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Καταχωρίστε ξανά το πρόσωπό σας."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Αδύνατη η αναγνώριση του προσώπου. Επανάληψη."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Άνοιγμα με"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Άνοιγμα με %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Άνοιγμα"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Άνοιγμα συνδέσμων <xliff:g id="HOST">%1$s</xliff:g> με"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Άνοιγμα συνδέσμων με"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Άνοιγμα συνδέσμων με την εφαρμογή <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Άνοιγμα συνδέσμων <xliff:g id="HOST">%1$s</xliff:g> με την εφαρμογή <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Παροχή πρόσβασης"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Επεξεργασία με"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Επεξεργασία με %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Εκκίνηση προγράμματος περιήγησης;"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Αποδοχή κλήσης;"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Πάντα"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Ορισμός ως πάντα ανοικτής"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Μόνο μία φορά"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ρυθμίσεις"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Το προφίλ εργασίας δεν υποστηρίζεται από %1$s"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 51b031bc535c..cc389f3189f1 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Move phone to the left."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Move phone to the right."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Please look more directly at your device."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Can’t see your face. Look at the phone."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Position your face directly in front of the phone."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Too much motion. Hold phone steady."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Please re-enroll your face."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"No longer able to recognise face. Try again."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Open with"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Open with %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Open"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Open links with"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Open links with <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Give access"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Edit with"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Launch Browser?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Set to always open"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Settings"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s doesn\'t support work profile"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index fd14d4dc7e31..0e6d49cef10f 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Move phone to the left."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Move phone to the right."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Please look more directly at your device."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Can’t see your face. Look at the phone."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Position your face directly in front of the phone."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Too much motion. Hold phone steady."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Please re-enroll your face."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"No longer able to recognise face. Try again."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Open with"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Open with %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Open"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Open links with"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Open links with <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Give access"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Edit with"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Launch Browser?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Set to always open"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Settings"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s doesn\'t support work profile"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 51b031bc535c..cc389f3189f1 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Move phone to the left."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Move phone to the right."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Please look more directly at your device."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Can’t see your face. Look at the phone."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Position your face directly in front of the phone."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Too much motion. Hold phone steady."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Please re-enroll your face."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"No longer able to recognise face. Try again."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Open with"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Open with %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Open"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Open links with"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Open links with <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Give access"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Edit with"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Launch Browser?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Set to always open"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Settings"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s doesn\'t support work profile"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 51b031bc535c..cc389f3189f1 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Move phone to the left."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Move phone to the right."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Please look more directly at your device."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Can’t see your face. Look at the phone."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Position your face directly in front of the phone."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Too much motion. Hold phone steady."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Please re-enroll your face."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"No longer able to recognise face. Try again."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Open with"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Open with %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Open"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Open <xliff:g id="HOST">%1$s</xliff:g> links with"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Open links with"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Open links with <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Open <xliff:g id="HOST">%1$s</xliff:g> links with <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Give access"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Edit with"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit with %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Launch Browser?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Accept call?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Always"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Set to always open"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Just once"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Settings"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s doesn\'t support work profile"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 638d29d2aa8f..dade85ebf851 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‎‎‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‎‎‎‏‎‏‏‎‏‏‎‏‏‎‏‎‏‎‏‎‏‏‏‏‏‏‏‎‎‏‏‎‎‏‎‎Move phone to the left.‎‏‎‎‏‎"</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‏‎‎‎‎‏‏‎‎‏‏‏‎‎‏‎‎‏‎‏‏‏‎‏‎‏‎‎‏‏‎‎‏‎‎‎‏‎‎‎‏‎‏‎‏‎‏‎‎‎‎‎‎‎Move phone to the right.‎‏‎‎‏‎"</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‏‏‎‎‎‏‏‎‏‏‏‎‏‎‎‏‎‎‎‏‎‎‎‏‎‎‏‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‎‏‎Please look more directly at your device.‎‏‎‎‏‎"</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‏‏‎‎‏‏‎‎‏‏‎‎‏‎‎‏‏‎‏‎‏‏‏‏‎‎‎‎‏‏‎‎‎‏‏‎‏‎‏‏‎‎‎‏‎‏‏‎‏‎‎‏‎Can’t see your face. Look at the phone.‎‏‎‎‏‎"</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‎‎‏‎‏‏‎‎‎‎‏‎‏‏‎‎‎‎‏‏‏‎‎‎‎‏‏‏‏‎‎‏‎‏‎‏‏‎‏‏‏‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎Position your face directly in front of the phone.‎‏‎‎‏‎"</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‏‎‏‎‎‏‎‏‎‏‏‎‎‏‏‏‎‏‏‎‎‎‏‏‏‏‎‏‎‎‏‎‎‎‎‎‎‎‎‏‏‏‏‎‎‏‎‏‏‎‎‏‏‎Too much motion. Hold phone steady.‎‏‎‎‏‎"</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‏‏‎‏‎‏‎‏‎‎‏‎‎‎‏‎‎‎‏‏‎‎‎‏‎‏‎‎‏‏‎‎‎‎‏‎‏‏‏‎‏‎‎‎‏‎‎‎‏‎‎‏‏‎Please re-enroll your face.‎‏‎‎‏‎"</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‏‏‎‏‏‏‏‏‏‎‎‎‎‏‎‏‎‎‎‏‎‎‎‏‎‎‏‏‎‏‎‎‏‎‏‏‎‎‏‏‎‎‏‎‏‎‏‏‏‏‏‏‎‎No longer able to recognize face. Try again.‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 43e0823a7c18..3a2ea3e101e7 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -292,7 +292,7 @@
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
<string name="permgroupdesc_sms" msgid="4656988620100940350">"enviar y ver mensajes SMS"</string>
<string name="permgrouprequest_sms" msgid="7168124215838204719">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envíe y vea SMS?"</string>
- <string name="permgrouplab_storage" msgid="1971118770546336966">"Espacio de almacenamiento"</string>
+ <string name="permgrouplab_storage" msgid="1971118770546336966">"Almacenamiento"</string>
<string name="permgroupdesc_storage" msgid="637758554581589203">"acceder a las fotos, el contenido multimedia y los archivos"</string>
<string name="permgrouprequest_storage" msgid="7885942926944299560">"¿Permitir que &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; acceda a las fotos, el contenido multimedia y los archivos de tu dispositivo?"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"Micrófono"</string>
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Mueve el teléfono hacia la izquierda."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Mueve el teléfono hacia la derecha."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Mira directamente al dispositivo."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"No se ve tu cara. Mira el teléfono."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Ubica el rostro directamente frente al teléfono."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Te estás moviendo demasiado. No muevas el teléfono"</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Vuelve a registrar tu cara."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Ya no se reconoce la cara. Vuelve a intentarlo."</string>
@@ -602,7 +602,7 @@
<string name="permdesc_readSyncStats" msgid="1510143761757606156">"Permite que la aplicación consulte las estadísticas de sincronización de una cuenta, por ejemplo, el historial de eventos sincronizados y la cantidad de datos sincronizados."</string>
<string name="permlab_sdcardRead" msgid="1438933556581438863">"ver almacenamiento compartido"</string>
<string name="permdesc_sdcardRead" msgid="1804941689051236391">"Ver almacenamiento compartido"</string>
- <string name="permlab_sdcardWrite" msgid="9220937740184960897">"Cambia/borra almac. compartido"</string>
+ <string name="permlab_sdcardWrite" msgid="9220937740184960897">"cambiar o borrar contenido de almacenamiento compartido"</string>
<string name="permdesc_sdcardWrite" msgid="2834431057338203959">"Editar almacen. compartido"</string>
<string name="permlab_use_sip" msgid="2052499390128979920">"realizar/recibir llamadas SIP"</string>
<string name="permdesc_use_sip" msgid="2297804849860225257">"Permite que la aplicación realice y reciba llamadas SIP."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Abrir con"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir con %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Abrir vínculos de <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Abrir vínculos con"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Abrir vínculos con <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Abrir vínculos de <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Otorgar acceso"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Editar con"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar con %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"¿Deseas iniciar el navegador?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"¿Aceptar la llamada?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Siempre"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Establecer en \"abrir siempre\""</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Solo una vez"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configuración"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s no admite perfiles de trabajo."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 90bf8b6dc51b..633759b68cb5 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Mueve el teléfono hacia la izquierda."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Mueve el teléfono hacia la derecha."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Mira de forma más directa al dispositivo."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"No se detecta tu cara. Mira al teléfono."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Coloca la cara directamente frente al teléfono."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"El teléfono se mueve demasiado. Mantenlo quieto."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Vuelve a registrar tu cara."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"No puede reconocer tu cara. Vuelve a intentarlo."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Abrir con"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir con %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Abrir enlaces de <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Abrir enlaces con"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Abrir enlaces con <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Abrir enlaces de <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Permitir acceso"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Editar con"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar con %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"¿Iniciar el navegador?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"¿Aceptar la llamada?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Siempre"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Configurar para que se abra siempre"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Solo una vez"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ajustes"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s no admite perfiles de trabajo"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index cf84482078de..86843c7a3dfd 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Liigutage telefoni vasakule."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Liigutage telefoni paremale."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Vaadake otse oma seadmesse."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Teie nägu ei ole näha. Vaadake telefoni poole."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Hoidke oma nägu otse telefoni ees."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Liiga palju liikumist. Hoidke telefoni paigal."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Registreerige oma nägu uuesti."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Nägu ei õnnestu enam tuvastada. Proovige uuesti."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Avamine:"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Avamine rakendusega %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ava"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Ava teenuse <xliff:g id="HOST">%1$s</xliff:g> lingid rakendusega"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Ava lingid rakendusega"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Linkide avamine rakendusega <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Ava teenuse <xliff:g id="HOST">%1$s</xliff:g> lingid rakendusega <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Juudep. andmine"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Muutmine:"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Muutmine rakendusega %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Kas käivitada brauser?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Kas vastata kõnele?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Alati"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Määra alati avama"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Ainult üks kord"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Seaded"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ei toeta tööprofiili"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index ba1e0b2b8fdd..d25fe8c24401 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -375,7 +375,7 @@
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Beren zati batzuk memoria modu iraunkorrean ezartzeko baimena ematen die aplikazioei. Horrela, beste aplikazioek erabilgarri duten memoria murritz daiteke eta tableta motel daiteke."</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Beren zati batzuk memorian modu iraunkorrean aktibo uztea baimentzen die aplikazioei. Horrela, beste aplikazioek memoria gutxiago izan lezakete erabilgarri eta telebistak motelago funtziona lezake."</string>
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Beren zati batzuk memoria modu iraunkorrean ezartzeko baimena ematen die aplikazioei. Horrela, beste aplikazioek erabilgarri duten memoria murritz daiteke eta telefonoa motel daiteke."</string>
- <string name="permlab_foregroundService" msgid="3310786367649133115">"Exekutatu zerbitzuak aurreko planoan"</string>
+ <string name="permlab_foregroundService" msgid="3310786367649133115">"Abiarazi zerbitzuak aurreko planoan"</string>
<string name="permdesc_foregroundService" msgid="6471634326171344622">"Aurreko planoko zerbitzuak erabiltzea baimentzen dio aplikazioari."</string>
<string name="permlab_getPackageSize" msgid="7472921768357981986">"neurtu aplikazioen biltegiratzeko tokia"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"Bere kodea, datuak eta cache-tamainak eskuratzeko baimena ematen die aplikazioei."</string>
@@ -422,7 +422,7 @@
<string name="permdesc_accessCoarseLocation" product="tv" msgid="3027871910200890806">"Aplikazioa aurreko planoan dagoenean, zure kokapenaren berri izan dezake sareen iturburuak erabilita; adibidez, telefonia mugikorreko dorreak eta Wi-Fi sareak. Kokapen-zerbitzu horiek aktibatuta eta erabilgarri izan behar dituzu telebistan, aplikazioak erabil ditzan."</string>
<string name="permdesc_accessCoarseLocation" product="default" msgid="854896049371048754">"Aplikazioa aurreko planoan dagoenean, zure kokapenaren berri izan dezake sareen iturburuak erabilita; adibidez, telefonia mugikorreko dorreak eta Wi-Fi sareak. Kokapen-zerbitzu horiek aktibatuta eta erabilgarri izan behar dituzu telefonoan, aplikazioak erabil ditzan."</string>
<string name="permlab_accessBackgroundLocation" msgid="3965397804300661062">"Atzitu kokapena atzeko planoan"</string>
- <string name="permdesc_accessBackgroundLocation" msgid="1096394429579210251">"Baimen hau ematen bada kokapen zehatz edo gutxi gorabeherakorako sarbideaz gain, atzeko planoan exekutatu bitartean atzitu ahalko du aplikazioak kokapena."</string>
+ <string name="permdesc_accessBackgroundLocation" msgid="1096394429579210251">"Baimen hau ematen bada kokapen zehatz edo gutxi gorabeherakorako sarbideaz gain, atzeko planoan abian den bitartean atzitu ahalko du aplikazioak kokapena."</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"aldatu audio-ezarpenak"</string>
<string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Audio-ezarpen orokorrak aldatzeko baimena ematen dio; besteak beste, bolumena eta irteerarako zer bozgorailu erabiltzen den."</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"grabatu audioa"</string>
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Mugitu telefonoa ezkerretara."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Mugitu telefonoa eskuinetara."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Begiratu zuzenago gailuari."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Ez da hautematen aurpegia. Begiratu telefonoari."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Ipini aurrez aurre aurpegia eta telefonoa."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Mugimendu gehiegi dago. Eutsi tinko telefonoari."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Erregistratu berriro aurpegia."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Ez dugu ezagutzen aurpegi hori. Saiatu berriro."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Ireki honekin:"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Irekin %1$s aplikazioarekin"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ireki"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Ireki <xliff:g id="HOST">%1$s</xliff:g> ostalariko estekak honekin:"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Ireki estekak honekin:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Ireki estekak <xliff:g id="APPLICATION">%1$s</xliff:g> aplikazioarekin"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Ireki <xliff:g id="HOST">%1$s</xliff:g> ostalariko estekak <xliff:g id="APPLICATION">%2$s</xliff:g> aplikazioarekin"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Eman sarbidea"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Editatu honekin:"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editatu %1$s aplikazioarekin"</string>
@@ -1181,7 +1177,7 @@
<string name="wait" msgid="7147118217226317732">"Itxaron"</string>
<string name="webpage_unresponsive" msgid="3272758351138122503">"Orriak ez du erantzuten.\n\nItxi egin nahi duzu?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Aplikazioa birbideratu da"</string>
- <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioa exekutatzen ari da."</string>
+ <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioa abian da."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioa lehenago abiarazi da."</string>
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"Eskala"</string>
<string name="screen_compat_mode_show" msgid="4013878876486655892">"Erakutsi beti"</string>
@@ -1207,7 +1203,7 @@
<string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> prestatzen."</string>
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"Aplikazioak abiarazten."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"Bertsio-berritzea amaitzen."</string>
- <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> exekutatzen"</string>
+ <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> abian da"</string>
<string name="heavy_weight_notification_detail" msgid="2304833848484424985">"Sakatu jokora itzultzeko"</string>
<string name="heavy_weight_switcher_title" msgid="387882830435195342">"Aukeratu joko bat"</string>
<string name="heavy_weight_switcher_text" msgid="4176781660362912010">"Funtzionamendu hobea izateko, joko hauetako bat baino ezin da egon irekita aldi berean."</string>
@@ -1445,7 +1441,7 @@
<string name="ime_action_next" msgid="3138843904009813834">"Hurrengoa"</string>
<string name="ime_action_done" msgid="8971516117910934605">"Eginda"</string>
<string name="ime_action_previous" msgid="1443550039250105948">"Atzera"</string>
- <string name="ime_action_default" msgid="2840921885558045721">"Exekutatu"</string>
+ <string name="ime_action_default" msgid="2840921885558045721">"Abiarazi"</string>
<string name="dial_number_using" msgid="5789176425167573586">"Markatu zenbakia \n<xliff:g id="NUMBER">%s</xliff:g> erabilita"</string>
<string name="create_contact_using" msgid="4947405226788104538">"Sortu kontaktua\n<xliff:g id="NUMBER">%s</xliff:g> erabilita"</string>
<string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"Aplikazio hauetako bat edo gehiago kontua orain eta etorkizunean atzitzeko baimena eskatzen ari dira."</string>
@@ -1555,7 +1551,7 @@
<string name="storage_sd_card_label" msgid="6347111320774379257">"<xliff:g id="MANUFACTURER">%s</xliff:g> SD txartela"</string>
<string name="storage_usb_drive" msgid="6261899683292244209">"USB bidezko unitatea"</string>
<string name="storage_usb_drive_label" msgid="4501418548927759953">"<xliff:g id="MANUFACTURER">%s</xliff:g> enpresaren USB bidezko unitatea"</string>
- <string name="storage_usb" msgid="3017954059538517278">"USB memoria"</string>
+ <string name="storage_usb" msgid="3017954059538517278">"USB bidezko memoria"</string>
<string name="extract_edit_menu_button" msgid="8940478730496610137">"Editatu"</string>
<string name="data_usage_warning_title" msgid="6499834033204801605">"Datuen erabileraren abisua"</string>
<string name="data_usage_warning_body" msgid="7340198905103751676">"<xliff:g id="APP">%s</xliff:g> erabili dituzu"</string>
@@ -1591,8 +1587,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Arakatzailea abiarazi nahi duzu?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Deia onartu nahi duzu?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Beti"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Ezarri beti irekitzeko"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Behin soilik"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ezarpenak"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s abiarazleak ez du laneko profil hau onartzen"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 280a56ec5f14..48cdafcfed47 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"تلفن را به‌سمت چپ حرکت دهید."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"تلفن را به سمت راست حرکت دهید."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"لطفاً مستقیم به دستگاه نگه کنید."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"چهره‌تان دیده نمی‌شود. به تلفن نگاه کنید."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"صورتتان را مستقیماً روبروی تلفن قرار دهید."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"حرکت خیلی زیاد است. تلفن را ثابت نگه‌دارید."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"لطفاً چهره‌تان را مجدداً ثبت کنید."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"دیگر چهره را تشخیص نمی‌دهد. دوباره امتحان کنید."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"باز کردن با"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"‏باز کردن با %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"باز کردن"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"باز کردن پیوندهای <xliff:g id="HOST">%1$s</xliff:g> با"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"باز کردن پیوندها با"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"باز کردن پیوندها با <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"باز کردن پیوندهای <xliff:g id="HOST">%1$s</xliff:g> با <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ارائه دسترسی"</string>
<string name="whichEditApplication" msgid="144727838241402655">"ویرایش با"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"‏ویرایش با %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"مرورگر راه‌اندازی شود؟"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"تماس را می‌پذیرید؟"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"همیشه"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"تنظیم روی همیشه باز شدن"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"فقط این بار"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"تنظیمات"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"‏%1$s از نمایه کاری پشتیبانی نمی‌کند"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 7a5003bacce3..cd9a71174649 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Siirrä puhelinta vasemmalle."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Siirrä puhelinta oikealle."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Katso suoremmin laitteeseen."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Kasvojasi ei näy. Katso puhelinta."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Aseta kasvosi suoraan puhelimen eteen."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Laite liikkui liikaa. Pidä puhelin vakaana."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Rekisteröi kasvot uudelleen."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Ei enää tunnista kasvoja. Yritä uudelleen."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Avaa sovelluksessa"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Avaa sovelluksessa %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Avaa"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g>-linkit avataan:"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Linkit avataan:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"<xliff:g id="APPLICATION">%1$s</xliff:g> avaa linkit"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="APPLICATION">%2$s</xliff:g> avaa linkit (<xliff:g id="HOST">%1$s</xliff:g>)"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Salli"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Muokkaa sovelluksessa"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Muokkaa sovelluksessa %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Käynnistetäänkö selain?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Vastataanko puheluun?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Aina"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Avaa aina"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Vain kerran"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Asetukset"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ei tue työprofiilia"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 0ddb19abbdd6..2bfef39cf924 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Déplacez le téléphone vers la gauche."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Déplacez le téléphone vers la droite."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Veuillez regarder plus directement votre appareil."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Visage non détecté. Regardez le téléphone."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Placez votre visage directement devant le téléphone."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Trop de mouvement. Tenez le téléphone immobile."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Veuillez inscrire votre visage à nouveau."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Ce visage ne sera plus reconnu. Réessayez."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Ouvrir avec"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Ouvrir avec %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ouvrir"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Ouvrir les liens <xliff:g id="HOST">%1$s</xliff:g> avec"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Ouvrir les liens avec"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Ouvrir les liens avec <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Ouvrir les liens <xliff:g id="HOST">%1$s</xliff:g> avec <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Accorder l\'accès"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Modifier avec"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Modifier avec %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Lancer le navigateur?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Prendre l\'appel?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Toujours"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Définir cette activité comme toujours ouverte"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Une seule fois"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Paramètres"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne prend pas en charge le profil professionnel"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 5f98a8acd945..041668fdba58 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Déplacez le téléphone vers la gauche."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Déplacez le téléphone vers la droite."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Veuillez regarder plus directement l\'appareil."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Visage non détecté. Regardez le téléphone."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Placez votre visage en face du téléphone."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Trop de mouvement. Ne bougez pas le téléphone."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Veuillez enregistrer à nouveau votre visage."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Impossible de reconnaître le visage. Réessayez."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Ouvrir avec"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Ouvrir avec %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ouvrir"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Ouvrir les liens <xliff:g id="HOST">%1$s</xliff:g> avec"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Ouvrir les liens avec"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Ouvrir les liens avec <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Ouvrir les liens <xliff:g id="HOST">%1$s</xliff:g> avec <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Accorder l\'accès"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Modifier avec"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Modifier avec %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Lancer le navigateur ?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Prendre l\'appel ?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Toujours"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Définir cette activité comme toujours ouverte"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Une seule fois"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Paramètres"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s n\'est pas compatible avec le profil professionnel."</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 740f699ec9c4..18bba90202ca 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Move o teléfono cara á esquerda."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Move o teléfono cara á dereita."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Mira o dispositivo de forma máis directa."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Non se ve a túa cara. Mira para o teléfono"</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Coloca a cara directamente diante do teléfono."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Demasiado movemento. Non movas o teléfono."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Volve rexistrar a túa cara."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Xa non se pode recoñecer a cara. Téntao de novo."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Abrir con"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir con %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Abrir ligazóns de <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Abrir ligazóns con"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Abrir ligazóns con <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Abrir ligazóns de <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Conceder acceso"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Editar con"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar con %1$s"</string>
@@ -1591,8 +1587,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Iniciar o navegador?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Aceptar chamada?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Definir como abrir sempre"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Só unha vez"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configuración"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s non admite o perfil de traballo"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index ddc4aaeec355..1b961727da84 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"ફોનને ડાબી બાજુ ખસેડો."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"ફોનને જમણી બાજુ ખસેડો."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"કૃપા કરીને તમારા ડિવાઇસ તરફ સીધું જુઓ."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"તમારો ચહેરો દેખાતો નથી. ફોનની સામે જુઓ."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"તમારો ચહેરો તમારા ફોનની બિલકુલ સામે રાખો."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"ડિવાઇસ અસ્થિર છે. ફોનને સ્થિર રાખો."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"કૃપા કરીને તમારા ચહેરાની ફરી નોંધણી કરાવો."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"ચહેરો ઓળખી શકાતો નથી. ફરી પ્રયાસ કરો."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"આની સાથે ખોલો"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s સાથે ખોલો"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"ખોલો"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"આના વડે <xliff:g id="HOST">%1$s</xliff:g> લિંક ખોલો"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"આના વડે લિંક ખોલો"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"<xliff:g id="APPLICATION">%1$s</xliff:g> વડે લિંક ખોલો"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="APPLICATION">%2$s</xliff:g> વડે <xliff:g id="HOST">%1$s</xliff:g> લિંક ખોલો"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ઍક્સેસ આપો"</string>
<string name="whichEditApplication" msgid="144727838241402655">"આનાથી સંપાદિત કરો"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s સાથે સંપાદિત કરો"</string>
@@ -1591,8 +1587,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"બ્રાઉઝર લોન્ચ કરીએ?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"કૉલ સ્વીકારીએ?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"હંમેશા"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"હંમેશાં ખુલ્લી તરીકે સેટ કરો"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"ફક્ત એક વાર"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"સેટિંગ"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s કાર્ય પ્રોફાઇલનું સમર્થન કરતું નથી"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 0a1051bb6fc9..9f0df13d8ef0 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"फ़ोन को बाईं ओर घुमाएं."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"फ़ोन को दाईं ओर घुमाएं."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"कृपया अपने डिवाइस की तरफ़ सीधे देखें."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"आपका चेहरा नहीं दिखाई दे रहा. फ़ोन की तरफ़ देखें."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"अपने चेहरे को फोन के ठीक सामने लाएं."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"डिवाइस बहुत ज़्यादा हिल रहा है. फ़ोन को बिना हिलाएं पकड़ें."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"कृपया फिर से अपने चेहरे की पहचान कराएं."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"अब चेहरे की पहचान नहीं कर पा रहा. फिर से कोशिश करें."</string>
@@ -784,7 +784,7 @@
<string name="relationTypeDomesticPartner" msgid="6904807112121122133">"हमसफ़र"</string>
<string name="relationTypeFather" msgid="5228034687082050725">"पिता"</string>
<string name="relationTypeFriend" msgid="7313106762483391262">"दोस्त"</string>
- <string name="relationTypeManager" msgid="6365677861610137895">"प्रबंधक"</string>
+ <string name="relationTypeManager" msgid="6365677861610137895">"मैनेजर"</string>
<string name="relationTypeMother" msgid="4578571352962758304">"मां"</string>
<string name="relationTypeParent" msgid="4755635567562925226">"अभिभावक"</string>
<string name="relationTypePartner" msgid="7266490285120262781">"सहयोगी"</string>
@@ -904,7 +904,7 @@
<string name="granularity_label_line" msgid="5764267235026120888">"पंक्ति"</string>
<string name="factorytest_failed" msgid="5410270329114212041">"फ़ैक्‍ट्री परीक्षण विफल"</string>
<string name="factorytest_not_system" msgid="4435201656767276723">"FACTORY_TEST का काम केवल /system/app में इंस्‍टॉल किए गए पैकेज के लिए ही हो सकता है."</string>
- <string name="factorytest_no_action" msgid="872991874799998561">"ऐसा कोई पैकेज नहीं मिला था जो FACTORY_TEST कार्रवाई प्रदान करता हो."</string>
+ <string name="factorytest_no_action" msgid="872991874799998561">"ऐसा कोई पैकेज नहीं मिला था जो FACTORY_TEST कार्रवाई मुहैया करवाता हो."</string>
<string name="factorytest_reboot" msgid="6320168203050791643">"रीबूट करें"</string>
<string name="js_dialog_title" msgid="1987483977834603872">"\'<xliff:g id="TITLE">%s</xliff:g>\' पर यह पेज दर्शाता है:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
@@ -1085,7 +1085,7 @@
<string name="undo" msgid="7905788502491742328">"वापस लाएं"</string>
<string name="redo" msgid="7759464876566803888">"फिर से करें"</string>
<string name="autofill" msgid="3035779615680565188">"ऑटोमैटिक भरना"</string>
- <string name="textSelectionCABTitle" msgid="5236850394370820357">"लेख चयन"</string>
+ <string name="textSelectionCABTitle" msgid="5236850394370820357">"टेक्स्ट चुनें"</string>
<string name="addToDictionary" msgid="4352161534510057874">"शब्दकोश में जोड़ें"</string>
<string name="deleteText" msgid="6979668428458199034">"मिटाएं"</string>
<string name="inputMethod" msgid="1653630062304567879">"इनपुट विधि"</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"इसमें खोलें"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s में खोलें"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"खोलें"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"इसे इस्तेमाल करके <xliff:g id="HOST">%1$s</xliff:g> लिंक खोलें"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"इसे इस्तेमाल करके लिंक खोलें"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"<xliff:g id="APPLICATION">%1$s</xliff:g> इस्तेमाल करके लिंक खोलें"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="APPLICATION">%2$s</xliff:g> इस्तेमाल करके <xliff:g id="HOST">%1$s</xliff:g> लिंक खोलें"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"एक्सेस दें"</string>
<string name="whichEditApplication" msgid="144727838241402655">"इसके ज़रिये बदलाव करें"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s की मदद से बदलाव करें"</string>
@@ -1288,7 +1284,7 @@
<item msgid="75483255295529161">"वाई-फ़ाई"</item>
<item msgid="6862614801537202646">"ब्लूटूथ"</item>
<item msgid="5447331121797802871">"ईथरनेट"</item>
- <item msgid="8257233890381651999">"VPN"</item>
+ <item msgid="8257233890381651999">"वीपीएन"</item>
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"अज्ञात नेटवर्क प्रकार"</string>
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाई-फ़ाई से कनेक्‍ट नहीं हो सका"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"ब्राउज़र लॉन्च करें?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"कॉल स्वीकार करें?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"हमेशा"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"\'हमेशा खुला रखें\' पर सेट करें"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"केवल एक बार"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"सेटिंग"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s वर्क प्रोफ़ाइल का समर्थन नहीं करता"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index cc8eb49e0dee..21fdc2ff1072 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -571,7 +571,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Pomaknite telefon ulijevo."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Pomaknite telefon udesno."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Gledajte izravnije prema uređaju."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Vaše se lice ne vidi. Pogledajte telefon."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Postavite lice izravno ispred telefona."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Previše kretanja. Držite telefon mirno."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Ponovo registrirajte svoje lice."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Lice nije prepoznato. Pokušajte ponovo."</string>
@@ -1151,14 +1151,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Otvaranje pomoću aplikacije"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otvaranje pomoću aplikacije %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otvori"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Otvaranje veza s <xliff:g id="HOST">%1$s</xliff:g> u aplikaciji"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Otvaranje veza u aplikaciji"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Otvaranje veza u aplikaciji <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Otvaranje veza s <xliff:g id="HOST">%1$s</xliff:g> u aplikaciji <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Omogući pristup"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Uređivanje pomoću aplikacije"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Uređivanje pomoću aplikacije %1$s"</string>
@@ -1613,8 +1609,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Pokrenuti preglednik?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Prihvatiti poziv?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Uvijek"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Postavi to otvaranje kao zadano"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Samo jednom"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Postavke"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne podržava radni profil"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 4ce7d4282893..1198610fe605 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Mozgassa a telefont balra."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Mozgassa a telefont jobbra."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Szemből nézzen az eszközre."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Nem látszik az arca. Nézzen a telefonra."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"A telefont közvetlenül az arca elé tegye."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Túl sok a mozgás. Tartsa stabilan a telefont."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Rögzítsen újra képet az arcáról."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Már nem lehet felismerni az arcát. Próbálja újra."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Megnyitás a következővel:"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Megnyitás a következővel: %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Megnyitás"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g>-linkek megnyitása a következővel:"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Linkek megnyitása a következővel:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Linkek megnyitása a következővel: <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g>-linkek megnyitása a következővel: <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Engedély adása"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Szerkesztés a következővel:"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Szerkesztés a következővel: %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Böngésző indítása?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Fogadja a hívást?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Mindig"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Megnyitás mindig ezzel"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Csak egyszer"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Beállítások"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"A(z) %1$s nem támogatja a munkaprofilokat."</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 2be6d6f32370..cb4886a6a408 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -104,7 +104,7 @@
<string name="serviceClassFAX" msgid="5566624998840486475">"Ֆաքս"</string>
<string name="serviceClassSMS" msgid="2015460373701527489">"SMS"</string>
<string name="serviceClassDataAsync" msgid="4523454783498551468">"Չհամաժամեցված"</string>
- <string name="serviceClassDataSync" msgid="7530000519646054776">"Համաժամել"</string>
+ <string name="serviceClassDataSync" msgid="7530000519646054776">"Համաժամացնել"</string>
<string name="serviceClassPacket" msgid="6991006557993423453">"Փաթեթ"</string>
<string name="serviceClassPAD" msgid="3235259085648271037">"Հարթակ"</string>
<string name="roamingText0" msgid="7170335472198694945">"Ռոումինգի ցուցիչը միացված է"</string>
@@ -169,8 +169,8 @@
<string name="httpErrorFileNotFound" msgid="6203856612042655084">"Չհաջողվեց գտնել հարցվող ֆայլը:"</string>
<string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Չափից շատ հարցումներ են մշակվում: Փորձեք կրկին ավելի ուշ:"</string>
<string name="notification_title" msgid="8967710025036163822">"Մուտք գործելու սխալ` <xliff:g id="ACCOUNT">%1$s</xliff:g>-ի համար"</string>
- <string name="contentServiceSync" msgid="8353523060269335667">"Համաժամեցնել"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="7036196943673524858">"Չի հաջողվում համաժամեցնել"</string>
+ <string name="contentServiceSync" msgid="8353523060269335667">"Համաժամացնել"</string>
+ <string name="contentServiceSyncNotificationTitle" msgid="7036196943673524858">"Չի հաջողվում համաժամացնել"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="4884451152168188763">"Հետևյալ ծառայությունից չափազանց շատ տարրեր եք ջնջել՝ <xliff:g id="CONTENT_TYPE">%s</xliff:g>:"</string>
<string name="low_memory" product="tablet" msgid="6494019234102154896">"Պլանշետի պահոցը լիքն է: Ջնջեք մի քանի ֆայլ` տարածք ազատելու համար:"</string>
<string name="low_memory" product="watch" msgid="4415914910770005166">"Ժամացույցի ֆայլերի պահեստը լիքն է: Ջնջեք որոշ ֆայլեր՝ տարածք ազատելու համար:"</string>
@@ -346,7 +346,7 @@
<string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"կարդալ բջջային զեկուցվող հաղորդագրությունները"</string>
<string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Թույլ է տալիս հավելվածին կարդալ ձեր սարքի կողմից ստացված բջջային հեռարձակվող հաղորդագրությունները: Բջջային հեռարձակվող զգուշացումները ուղարկվում են որոշ վայրերում` արտակարգ իրավիճակների մասին ձեզ զգուշացնելու համար: Վնասարար հավելվածները կարող են խանգարել ձեր սարքի արդյունավետությանը կամ շահագործմանը, երբ ստացվում է արտակարգ իրավիճակի մասին բջջային հաղորդում:"</string>
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"կարդալ բաժանորդագրված հոսքերը"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Թույլ է տալիս հավելվածին մանրամասներ ստանալ ընթացիկ համաժամեցված հոսքերի մասին:"</string>
+ <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Թույլ է տալիս հավելվածին մանրամասներ ստանալ ընթացիկ համաժամացված հոսքերի մասին:"</string>
<string name="permlab_sendSms" msgid="7544599214260982981">"SMS հաղորդագրությունների ուղարկում և ընթերցում"</string>
<string name="permdesc_sendSms" msgid="7094729298204937667">"Թույլ է տալիս հավելվածին ուղարկել SMS հաղորդագրություններ: Այն կարող է անսպասելի ծախսերի պատճառ դառնալ: Վնասարար հավելվածները կարող են ձեր հաշվից գումար ծախսել` ուղարկելով հաղորդագրություններ` առանց ձեր հաստատման:"</string>
<string name="permlab_readSms" msgid="8745086572213270480">"կարդալ ձեր տեքստային հաղորդագրությունները (SMS կամ MMS)"</string>
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Տեղափոխեք հեռախոսը ձախ:"</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Տեղափոխեք հեռախոսը աջ:"</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Նայեք ուղիղ էկրանին։"</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Ձեր դեմքը չի երևում։ Նայեք հեռախոսին։"</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Պահեք ձեր դեմքն անմիջապես հեռախոսի էկրանի դիմաց:"</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Շատ եք շարժում։ Հեռախոսն անշարժ պահեք։"</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Նորից փորձեք։"</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Չհաջողվեց ճանաչել դեմքը։ Նորից փորձեք:"</string>
@@ -594,12 +594,12 @@
<string-array name="face_error_vendor">
</string-array>
<string name="face_icon_content_description" msgid="4024817159806482191">"Դեմքի պատկերակ"</string>
- <string name="permlab_readSyncSettings" msgid="6201810008230503052">"կարդալ համաժամեցման կարգավորումները"</string>
- <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Թույլ է տալիս հավելվածին կարդալ համաժամեցման կարգավորումները հաշվի համար: Օրինակ` այն կարող է որոշել, արդյոք Մարդիկ հավելվածը համաժամեցված է հաշվի հետ:"</string>
- <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"համաժամեցումը փոխարկել միացվածի և անջատվածի"</string>
- <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Թույլ է տալիս հավելվածին փոփոխել համաժամեցման կարգավորումները հաշվի համար: Օրինակ, այն կարող է օգտագործվել` միացնելու Մարդիկ հավելվածի համաժամեցումը հաշվի հետ:"</string>
- <string name="permlab_readSyncStats" msgid="7396577451360202448">"կարդալ համաժամեցման վիճակագրությունը"</string>
- <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Թույլ է տալիս հավելվածին կարդալ հաշվի համաժամեցման վիճակագրությունը, այդ թվում` համաժամեցման իրադարձությունների պատմությունը և թե որքան տվյալ է համաժամեցված:"</string>
+ <string name="permlab_readSyncSettings" msgid="6201810008230503052">"կարդալ համաժամացման կարգավորումները"</string>
+ <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Թույլ է տալիս հավելվածին կարդալ համաժամացման կարգավորումները հաշվի համար: Օրինակ` այն կարող է որոշել, արդյոք Մարդիկ հավելվածը համաժամացված է հաշվի հետ:"</string>
+ <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"համաժամացումը փոխարկել միացվածի և անջատվածի"</string>
+ <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Թույլ է տալիս հավելվածին փոփոխել համաժամացման կարգավորումները հաշվի համար: Օրինակ, այն կարող է օգտագործվել` միացնելու Մարդիկ հավելվածի համաժամացումը հաշվի հետ:"</string>
+ <string name="permlab_readSyncStats" msgid="7396577451360202448">"կարդալ համաժամացման վիճակագրությունը"</string>
+ <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Թույլ է տալիս հավելվածին կարդալ հաշվի համաժամացման վիճակագրությունը, այդ թվում` համաժամացման իրադարձությունների պատմությունը և թե որքան տվյալ է համաժամացված:"</string>
<string name="permlab_sdcardRead" msgid="1438933556581438863">"կարդալ ձեր ընդհանուր հիշողության պարունակությունը"</string>
<string name="permdesc_sdcardRead" msgid="1804941689051236391">"Հավելվածին թույլ է տալիս կարդալ ձեր ընդհանուր հիշողության պարունակությունը:"</string>
<string name="permlab_sdcardWrite" msgid="9220937740184960897">"փոփոխել կամ ջնջել ձեր ընդհանուր հիշողության բովանդակությունը"</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Բացել հետևյալ ծրագրով՝"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Բացել հավելվածով՝ %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Բացել"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> տեսակի հղումները բացել…"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Հղումները բացել…"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Հղումները բացել <xliff:g id="APPLICATION">%1$s</xliff:g> դիտարկիչում"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g> տեսակի հղումները բացել <xliff:g id="APPLICATION">%2$s</xliff:g> դիտարկիչում"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Թույլատրել"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Խմբագրել հետևյալ ծրագրով՝"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Խմբագրել հետևյալով՝ %1$s"</string>
@@ -1156,7 +1152,7 @@
<string name="whichImageCaptureApplicationNamed" msgid="8619384150737825003">"Լուսանկարել %1$s հավելվածի օգնությամբ"</string>
<string name="whichImageCaptureApplicationLabel" msgid="6390303445371527066">"Լուսանկարել"</string>
<string name="alwaysUse" msgid="4583018368000610438">"Օգտագործել ըստ կանխադրման այս գործողության համար:"</string>
- <string name="use_a_different_app" msgid="8134926230585710243">"Օգտագործել այլ հավելված"</string>
+ <string name="use_a_different_app" msgid="8134926230585710243">"Ուրիշ հավելված"</string>
<string name="clearDefaultHintMsg" msgid="3252584689512077257">"Մաքրել լռելյայնը Համակարգի կարգավորումներ &gt; Ծրագրեր &gt;Ներբեռնված էջից:"</string>
<string name="chooseActivity" msgid="7486876147751803333">"Ընտրել գործողություն"</string>
<string name="chooseUsbActivity" msgid="6894748416073583509">"Ընտրեք հավելված USB սարքի համար"</string>
@@ -1457,7 +1453,7 @@
<string name="forward_intent_to_owner" msgid="1207197447013960896">"Դուք օգտագործում եք այս հավելվածը ձեր աշխատանքային պրոֆիլից դուրս"</string>
<string name="forward_intent_to_work" msgid="621480743856004612">"Դուք օգտագործում եք այս հավելվածը ձեր աշխատանքային պրոֆիլում"</string>
<string name="input_method_binding_label" msgid="1283557179944992649">"Ներածման եղանակը"</string>
- <string name="sync_binding_label" msgid="3687969138375092423">"Համաժամել"</string>
+ <string name="sync_binding_label" msgid="3687969138375092423">"Համաժամացնել"</string>
<string name="accessibility_binding_label" msgid="4148120742096474641">"Մատչելիությունը"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Պաստառ"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Փոխել պաստառը"</string>
@@ -1590,9 +1586,8 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Գործարկե՞լ զննարկիչը:"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Ընդունե՞լ զանգը:"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Միշտ"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
- <string name="activity_resolver_use_once" msgid="2404644797149173758">"Միայն մեկ անգամ"</string>
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Միշտ բացել"</string>
+ <string name="activity_resolver_use_once" msgid="2404644797149173758">"Միայն այս անգամ"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Կարգավորումներ"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s-ը չի աջակցում աշխատանքային պրոֆիլներ"</string>
<string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Գրասալիկ"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index e71ab41f378d..ca369ebf8b40 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Gerakkan ponsel ke kiri."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Gerakkan ponsel ke kanan."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Lihat langsung ke perangkat."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Tidak dapat melihat wajah Anda. Lihat ke ponsel."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Posisikan wajah Anda langsung di depan ponsel."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Terlalu banyak gerakan. Stabilkan ponsel."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Daftarkan ulang wajah Anda."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Tidak lagi dapat mengenali wajah. Coba lagi."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Buka dengan"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Buka dengan %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Buka"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Buka link <xliff:g id="HOST">%1$s</xliff:g> dengan"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Buka link dengan"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Buka link dengan <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Buka link <xliff:g id="HOST">%1$s</xliff:g> dengan <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Berikan akses"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Edit dengan"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit dengan %1$s"</string>
@@ -1383,7 +1379,7 @@
<string name="alert_windows_notification_channel_group_name" msgid="1463953341148606396">"Tampilkan di atas apl lain"</string>
<string name="alert_windows_notification_channel_name" msgid="3116610965549449803">"<xliff:g id="NAME">%s</xliff:g> ditampilkan di atas aplikasi lain"</string>
<string name="alert_windows_notification_title" msgid="3697657294867638947">"<xliff:g id="NAME">%s</xliff:g> ditampilkan di atas aplikasi lain"</string>
- <string name="alert_windows_notification_message" msgid="8917232109522912560">"Jika Anda tidak ingin <xliff:g id="NAME">%s</xliff:g> menggunakan fitur ini, tap untuk membuka setelan dan menonaktifkannya."</string>
+ <string name="alert_windows_notification_message" msgid="8917232109522912560">"Jika Anda tidak ingin <xliff:g id="NAME">%s</xliff:g> menggunakan fitur ini, ketuk untuk membuka setelan dan menonaktifkannya."</string>
<string name="alert_windows_notification_turn_off_action" msgid="2902891971380544651">"Nonaktifkan"</string>
<string name="ext_media_checking_notification_title" msgid="4411133692439308924">"Memeriksa <xliff:g id="NAME">%s</xliff:g>…"</string>
<string name="ext_media_checking_notification_message" msgid="410185170877285434">"Meninjau konten saat ini"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Luncurkan Browser?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Terima panggilan?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Selalu"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Setel untuk selalu membuka"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Hanya sekali"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Setelan"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s tidak mendukung profil kerja"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 3d2acd9c7d24..572313aa0ed6 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Færðu símann til vinstri."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Færðu símann til hægri."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Horfðu beint á tækið."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Sé ekki andlit þitt. Horfðu á símann."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Hafðu andlitið beint fyrir framan símann."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Of mikil hreyfing. Haltu símanum stöðugum."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Skráðu nafnið þitt aftur."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Andlit þekkist ekki lengur. Reyndu aftur."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Opna með"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Opna með %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Opna"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Opna <xliff:g id="HOST">%1$s</xliff:g> tengla með"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Opna tengla með"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Opna tengla með <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Opna <xliff:g id="HOST">%1$s</xliff:g> tengla með <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Veita aðgang"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Breyta með"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Breyta með %1$s"</string>
@@ -1591,8 +1587,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Opna vafra?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Samþykkja símtal?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Alltaf"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Stilla á „Alltaf opið“"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Bara einu sinni"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Stillingar"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s styður ekki vinnusnið"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 6d1d132f2ea6..6c579b85600f 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -325,7 +325,7 @@
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Consente di toccare, far scorrere, pizzicare ed eseguire altri gesti."</string>
<string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gesti con sensore di impronte digitali"</string>
<string name="capability_desc_canCaptureFingerprintGestures" msgid="4386487962402228670">"È in grado di rilevare i gesti compiuti con il sensore di impronte digitali dei dispositivi."</string>
- <string name="permlab_statusBar" msgid="7417192629601890791">"disattivare o modificare la barra di stato"</string>
+ <string name="permlab_statusBar" msgid="7417192629601890791">"disattivazione o modifica della barra di stato"</string>
<string name="permdesc_statusBar" msgid="8434669549504290975">"Consente all\'applicazione di disattivare la barra di stato o di aggiungere e rimuovere icone di sistema."</string>
<string name="permlab_statusBarService" msgid="4826835508226139688">"ruolo di barra di stato"</string>
<string name="permdesc_statusBarService" msgid="716113660795976060">"Consente di visualizzare l\'applicazione nella barra di stato."</string>
@@ -337,7 +337,7 @@
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"Consente all\'applicazione di rimuovere le scorciatoie della schermata Home automaticamente."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"reindirizzamento chiamate in uscita"</string>
<string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Consente all\'app di rilevare il numero digitato durante una chiamata in uscita, con la possibilità di reindirizzare la telefonata a un numero diverso o interromperla del tutto."</string>
- <string name="permlab_answerPhoneCalls" msgid="4077162841226223337">"rispondi a telefonate in arrivo"</string>
+ <string name="permlab_answerPhoneCalls" msgid="4077162841226223337">"risposta a telefonate in arrivo"</string>
<string name="permdesc_answerPhoneCalls" msgid="2901889867993572266">"Consente all\'app di rispondere a una telefonata in arrivo."</string>
<string name="permlab_receiveSms" msgid="8673471768947895082">"ricezione messaggi di testo (SMS)"</string>
<string name="permdesc_receiveSms" msgid="6424387754228766939">"Consente all\'applicazione di ricevere ed elaborare messaggi SMS. Significa che l\'applicazione potrebbe monitorare o eliminare i messaggi inviati al tuo dispositivo senza mostrarteli."</string>
@@ -347,7 +347,7 @@
<string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Consente all\'applicazione di leggere i messaggi cell broadcast ricevuti dal dispositivo. Gli avvisi cell broadcast vengono trasmessi in alcune località per avvertire di eventuali situazioni di emergenza. Le applicazioni dannose potrebbero interferire con il rendimento o con il funzionamento del dispositivo quando si riceve un messaggio cell broadcast di emergenza."</string>
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"lettura feed sottoscritti"</string>
<string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Consente all\'applicazione di ottenere dettagli sui feed attualmente sincronizzati."</string>
- <string name="permlab_sendSms" msgid="7544599214260982981">"inviare e visualizzare SMS"</string>
+ <string name="permlab_sendSms" msgid="7544599214260982981">"invio e visualizzazione di SMS"</string>
<string name="permdesc_sendSms" msgid="7094729298204937667">"Consente all\'applicazione di inviare messaggi SMS. Ciò potrebbe comportare costi imprevisti. Applicazioni dannose potrebbero generare dei costi inviando messaggi senza la tua conferma."</string>
<string name="permlab_readSms" msgid="8745086572213270480">"lettura messaggi di testo personali (SMS o MMS)"</string>
<string name="permdesc_readSms" product="tablet" msgid="4741697454888074891">"Questa app può leggere tutti i messaggi di testo (SMS) memorizzati sul tablet."</string>
@@ -375,7 +375,7 @@
<string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Consente all\'applicazione di rendere persistenti in memoria alcune sue parti. Ciò può limitare la memoria disponibile per altre applicazioni, rallentando il tablet."</string>
<string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Consente all\'app di rendere alcune sue parti persistenti nella memoria. Potrebbe così essere limitata la memoria a disposizione di altre app ed essere rallentata la TV."</string>
<string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Consente all\'applicazione di rendere persistenti in memoria alcune sue parti. Ciò può limitare la memoria disponibile per altre applicazioni, rallentando il telefono."</string>
- <string name="permlab_foregroundService" msgid="3310786367649133115">"esegui servizio in primo piano"</string>
+ <string name="permlab_foregroundService" msgid="3310786367649133115">"esecuzione servizio in primo piano"</string>
<string name="permdesc_foregroundService" msgid="6471634326171344622">"Consente all\'app di utilizzare i servizi in primo piano."</string>
<string name="permlab_getPackageSize" msgid="7472921768357981986">"calcolo spazio di archiviazione applicazioni"</string>
<string name="permdesc_getPackageSize" msgid="3921068154420738296">"Consente all\'applicazione di recuperare il suo codice, i suoi dati e le dimensioni della cache"</string>
@@ -405,7 +405,7 @@
<string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Consente all\'applicazione di modificare il registro chiamate del telefono, inclusi i dati sulle chiamate in arrivo e in uscita. Le applicazioni dannose potrebbero farne uso per cancellare o modificare il registro chiamate."</string>
<string name="permlab_bodySensors" msgid="4683341291818520277">"accesso ai sensori (come il cardiofrequenzimetro)"</string>
<string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"Consente all\'app di accedere ai dati relativi ai sensori che monitorano le tue condizioni fisiche, ad esempio la frequenza cardiaca."</string>
- <string name="permlab_readCalendar" msgid="6716116972752441641">"Leggi eventi di calendario e dettagli"</string>
+ <string name="permlab_readCalendar" msgid="6716116972752441641">"lettura di eventi di calendario e dettagli"</string>
<string name="permdesc_readCalendar" product="tablet" msgid="4993979255403945892">"Questa app può leggere tutti gli eventi di calendario memorizzati sul tablet e condividere o salvare i dati di calendario."</string>
<string name="permdesc_readCalendar" product="tv" msgid="8837931557573064315">"Questa app può leggere tutti gli eventi di calendario memorizzati sulla TV e condividere o salvare i dati di calendario."</string>
<string name="permdesc_readCalendar" product="default" msgid="4373978642145196715">"Questa app può leggere tutti gli eventi di calendario memorizzati sul telefono e condividere o salvare i dati di calendario."</string>
@@ -415,9 +415,9 @@
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Questa app può aggiungere, rimuovere o modificare eventi di calendario sul telefono. Può inviare messaggi che possono sembrare inviati dai proprietari del calendario o modificare eventi senza notificare i proprietari."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accesso a comandi aggiuntivi provider di geolocalizz."</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Consente all\'app di accedere a ulteriori comandi del fornitore di posizione. Ciò potrebbe consentire all\'app di interferire con il funzionamento del GPS o di altre fonti di geolocalizzazione."</string>
- <string name="permlab_accessFineLocation" msgid="6265109654698562427">"Accesso alla posizione esatta solo in primo piano"</string>
+ <string name="permlab_accessFineLocation" msgid="6265109654698562427">"accesso alla posizione esatta solo in primo piano"</string>
<string name="permdesc_accessFineLocation" msgid="3520508381065331098">"Questa app può recuperare la tua posizione esatta solo quando è in primo piano. Questi servizi di geolocalizzazione devono essere attivi e disponibili sul telefono affinché l\'app possa usarli. Potrebbe aumentare il consumo della batteria."</string>
- <string name="permlab_accessCoarseLocation" msgid="3707180371693213469">"Accesso alla posizione approssimativa (in base alla rete) solo in primo piano"</string>
+ <string name="permlab_accessCoarseLocation" msgid="3707180371693213469">"accesso alla posizione approssimativa (in base alla rete) solo in primo piano"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="8594719010575779120">"Questa app può recuperare la tua posizione tramite fonti di rete quali ripetitori di telefonia mobile e reti Wi-Fi, ma soltanto quando l\'app è in primo piano. Questi servizi di geolocalizzazione devono essere attivi e disponibili sul tablet affinché l\'app possa usarli."</string>
<string name="permdesc_accessCoarseLocation" product="tv" msgid="3027871910200890806">"Questa app può recuperare la tua posizione tramite fonti di rete quali ripetitori di telefonia mobile e reti Wi-Fi, ma soltanto quando l\'app è in primo piano. Questi servizi di geolocalizzazione devono essere attivi e disponibili sulla TV affinché l\'app possa usarli."</string>
<string name="permdesc_accessCoarseLocation" product="default" msgid="854896049371048754">"Questa app può recuperare la tua posizione tramite fonti di rete quali ripetitori di telefonia mobile e reti Wi-Fi, ma soltanto quando l\'app è in primo piano. Questi servizi di geolocalizzazione devono essere attivi e disponibili sul telefono affinché l\'app possa usarli."</string>
@@ -425,7 +425,7 @@
<string name="permdesc_accessBackgroundLocation" msgid="1096394429579210251">"Se concedi l\'autorizzazione insieme all\'accesso alla posizione precisa o approssimativa, l\'app potrà accedere alla posizione mentre viene eseguita in background."</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"modifica impostazioni audio"</string>
<string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"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="3876049771427466323">"registrare audio"</string>
+ <string name="permlab_recordAudio" msgid="3876049771427466323">"registrazione audio"</string>
<string name="permdesc_recordAudio" msgid="4245930455135321433">"Questa app può registrare audio tramite il microfono in qualsiasi momento."</string>
<string name="permlab_sim_communication" msgid="2935852302216852065">"invio di comandi alla SIM"</string>
<string name="permdesc_sim_communication" msgid="5725159654279639498">"Consente all\'app di inviare comandi alla SIM. Questo è molto pericoloso."</string>
@@ -437,7 +437,7 @@
<string name="permdesc_vibrate" msgid="6284989245902300945">"Consente all\'applicazione di controllare la vibrazione."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"chiamata diretta n. telefono"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"Consente all\'applicazione di chiamare numeri di telefono senza il tuo intervento. Ciò può comportare chiamate o addebiti imprevisti. Tieni presente che ciò non consente all\'applicazione di chiamare numeri di emergenza. Applicazioni dannose potrebbero generare dei costi effettuando chiamate senza la tua conferma."</string>
- <string name="permlab_accessImsCallService" msgid="3574943847181793918">"Accesso al servizio di chiamata IMS"</string>
+ <string name="permlab_accessImsCallService" msgid="3574943847181793918">"accesso al servizio di chiamata IMS"</string>
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Consente all\'app di utilizzare il servizio IMS per fare chiamate senza il tuo intervento."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"lettura stato e identità telefono"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"Consente all\'applicazione di accedere alle funzioni telefoniche del dispositivo. Questa autorizzazione consente all\'applicazione di determinare il numero di telefono e gli ID dei dispositivi, se una chiamata è attiva e il numero remoto connesso da una chiamata."</string>
@@ -445,12 +445,12 @@
<string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"Consente all\'app di indirizzare le proprie chiamate tramite il sistema al fine di migliorare l\'esperienza di chiamata."</string>
<string name="permlab_callCompanionApp" msgid="3599252979411970473">"visualizzazione e controllo delle chiamate tramite il sistema."</string>
<string name="permdesc_callCompanionApp" msgid="4567344683275099090">"Consente all\'app di visualizzare e controllare le chiamate in corso sul dispositivo. Sono incluse informazioni quali i numeri e lo stato relativi alle chiamate."</string>
- <string name="permlab_acceptHandover" msgid="2661534649736022409">"Continuazione di una chiamata da un\'altra app"</string>
+ <string name="permlab_acceptHandover" msgid="2661534649736022409">"continuazione di una chiamata da un\'altra app"</string>
<string name="permdesc_acceptHandovers" msgid="4570660484220539698">"Consente all\'app di continuare una chiamata che è stata iniziata in un\'altra app."</string>
<string name="permlab_readPhoneNumbers" msgid="6108163940932852440">"lettura dei numeri di telefono"</string>
<string name="permdesc_readPhoneNumbers" msgid="8559488833662272354">"Consente all\'app di accedere ai numeri di telefono del dispositivo."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"disattivazione stand-by del tablet"</string>
- <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"divieto di attivazione della modalità di sospensione della TV"</string>
+ <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"disattivazione della modalità di sospensione della TV"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"disattivazione stand-by del telefono"</string>
<string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"Consente all\'applicazione di impedire lo stand-by del tablet."</string>
<string name="permdesc_wakeLock" product="tv" msgid="3208534859208996974">"Consente all\'app di impedire l\'attivazione della modalità di sospensione della TV."</string>
@@ -483,7 +483,7 @@
<string name="permdesc_accessWifiState" msgid="5002798077387803726">"Consente all\'applicazione di visualizzare informazioni sulle reti Wi-Fi, ad esempio di rilevare se il Wi-Fi è abilitato e il nome dei dispositivi Wi-Fi connessi."</string>
<string name="permlab_changeWifiState" msgid="6550641188749128035">"connessione e disconnessione dal Wi-Fi"</string>
<string name="permdesc_changeWifiState" msgid="7137950297386127533">"Consente all\'applicazione di connettersi/disconnettersi da punti di accesso Wi-Fi e di apportare modifiche alla configurazione del dispositivo per le reti Wi-Fi."</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"consenti ricezione multicast Wi-Fi"</string>
+ <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"ricezione multicast Wi-Fi"</string>
<string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"Consente all\'applicazione di ricevere pacchetti inviati a tutti i dispositivi su una rete Wi-Fi utilizzando indirizzi multicast, non solo il tuo tablet. Viene consumata più batteria rispetto alla modalità non multicast."</string>
<string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"Consente all\'app di ricevere pacchetti inviati a tutti i dispositivi tramite una rete Wi-Fi utilizzando indirizzi multicast, non soltanto la TV. Questa modalità consuma più energia della modalità non multicast."</string>
<string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"Consente all\'applicazione di ricevere pacchetti inviati a tutti i dispositivi su una rete Wi-Fi utilizzando indirizzi multicast, non solo il tuo telefono. Viene consumata più batteria rispetto alla modalità non multicast."</string>
@@ -505,21 +505,21 @@
<string name="permdesc_nfc" msgid="7120611819401789907">"Consente all\'applicazione di comunicare con tag, schede e lettori NFC (Near Field Communication)."</string>
<string name="permlab_disableKeyguard" msgid="3598496301486439258">"disattivazione blocco schermo"</string>
<string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Consente all\'applicazione di disattivare il blocco tastiera ed eventuali protezioni tramite password associate. Ad esempio, il telefono disattiva il blocco tastiera quando riceve una telefonata in arrivo e lo riattiva al termine della chiamata."</string>
- <string name="permlab_requestPasswordComplexity" msgid="202650535669249674">"richiedi complessità del blocco schermo"</string>
+ <string name="permlab_requestPasswordComplexity" msgid="202650535669249674">"richiesta di complessità del blocco schermo"</string>
<string name="permdesc_requestPasswordComplexity" msgid="4730994229754212347">"Consente all\'app di conoscere il livello di complessità del blocco schermo (alto, medio, basso o nessuno), che indica l\'intervallo di caratteri possibile e il tipo di blocco schermo. L\'app può inoltre suggerire agli utenti di aggiornare il blocco schermo a un livello specifico di complessità, ma gli utenti possono ignorare liberamente il suggerimento e uscire. Tieni presente che il blocco schermo non viene memorizzato come testo non crittografato, quindi l\'app non conosce la password esatta."</string>
- <string name="permlab_useBiometric" msgid="8837753668509919318">"Utilizzo di hardware biometrico"</string>
+ <string name="permlab_useBiometric" msgid="8837753668509919318">"utilizzo di hardware biometrico"</string>
<string name="permdesc_useBiometric" msgid="8389855232721612926">"Consente all\'app di utilizzare hardware biometrico per eseguire l\'autenticazione"</string>
- <string name="permlab_manageFingerprint" msgid="5640858826254575638">"gestisci hardware per il riconoscimento delle impronte digitali"</string>
+ <string name="permlab_manageFingerprint" msgid="5640858826254575638">"gestione di hardware per il riconoscimento delle impronte digitali"</string>
<string name="permdesc_manageFingerprint" msgid="178208705828055464">"Consente all\'app di richiamare metodi per aggiungere e rimuovere modelli di impronte digitali da utilizzare."</string>
<string name="permlab_useFingerprint" msgid="3150478619915124905">"utilizzo di hardware per il riconoscimento delle impronte digitali"</string>
<string name="permdesc_useFingerprint" msgid="9165097460730684114">"Consente all\'app di utilizzare l\'hardware per il riconoscimento delle impronte digitali per eseguire l\'autenticazione"</string>
- <string name="permlab_audioWrite" msgid="2661772059799779292">"Modifica della tua raccolta musicale"</string>
+ <string name="permlab_audioWrite" msgid="2661772059799779292">"modifica della tua raccolta musicale"</string>
<string name="permdesc_audioWrite" msgid="8888544708166230494">"Consente all\'app di modificare la tua raccolta musicale."</string>
- <string name="permlab_videoWrite" msgid="128769316366746446">"Modifica della tua raccolta di video"</string>
+ <string name="permlab_videoWrite" msgid="128769316366746446">"modifica della tua raccolta di video"</string>
<string name="permdesc_videoWrite" msgid="5448565757490640841">"Consente all\'app di modificare la tua raccolta di video."</string>
- <string name="permlab_imagesWrite" msgid="3391306186247235510">"Modifica della tua raccolta di foto"</string>
+ <string name="permlab_imagesWrite" msgid="3391306186247235510">"modifica della tua raccolta di foto"</string>
<string name="permdesc_imagesWrite" msgid="7073662756617474375">"Consente all\'app di modificare la tua raccolta di foto."</string>
- <string name="permlab_mediaLocation" msgid="8675148183726247864">"Lettura delle posizioni dalla tua raccolta multimediale"</string>
+ <string name="permlab_mediaLocation" msgid="8675148183726247864">"lettura delle posizioni dalla tua raccolta multimediale"</string>
<string name="permdesc_mediaLocation" msgid="2237023389178865130">"Consente all\'app di leggere le posizioni dalla tua raccolta multimediale."</string>
<string name="biometric_dialog_default_title" msgid="881952973720613213">"Verifica la tua identità"</string>
<string name="biometric_error_hw_unavailable" msgid="645781226537551036">"Hardware biometrico non disponibile"</string>
@@ -551,9 +551,9 @@
<string-array name="fingerprint_error_vendor">
</string-array>
<string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Icona dell\'impronta digitale"</string>
- <string name="permlab_manageFace" msgid="7262837876352591553">"gestisci l\'hardware per Sblocco col sorriso"</string>
+ <string name="permlab_manageFace" msgid="7262837876352591553">"gestione dell\'hardware per Sblocco col sorriso"</string>
<string name="permdesc_manageFace" msgid="8919637120670185330">"Consente all\'app di richiamare i metodi per aggiungere e rimuovere i modelli di volti."</string>
- <string name="permlab_useFaceAuthentication" msgid="2565716575739037572">"utilizza l\'hardware per Sblocco col sorriso"</string>
+ <string name="permlab_useFaceAuthentication" msgid="2565716575739037572">"utilizzo dell\'hardware per Sblocco col sorriso"</string>
<string name="permdesc_useFaceAuthentication" msgid="4712947955047607722">"Consente all\'app di utilizzare hardware per l\'autenticazione con Sblocco col sorriso"</string>
<string name="face_recalibrate_notification_name" msgid="1913676850645544352">"Sblocco col sorriso"</string>
<string name="face_recalibrate_notification_title" msgid="4087620069451499365">"Registra di nuovo il volto"</string>
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Sposta il telefono verso sinistra."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Sposta il telefono verso destra."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Guarda più direttamente verso il dispositivo."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Impossibile vedere il volto. Guarda il telefono."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Posiziona il viso davanti al telefono."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Troppo movimento. Tieni fermo il telefono."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Ripeti l\'acquisizione del volto."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Non è più possibile riconoscere il volto. Riprova."</string>
@@ -600,21 +600,21 @@
<string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Consente a un\'applicazione di modificare le impostazioni di sincronizzazione per un account. Ad esempio, può servire per attivare la sincronizzazione dell\'applicazione Persone con un account."</string>
<string name="permlab_readSyncStats" msgid="7396577451360202448">"lettura statistiche di sincronizz."</string>
<string name="permdesc_readSyncStats" msgid="1510143761757606156">"Consente a un\'applicazione di leggere le statistiche di sincronizzazione per un account, incluse la cronologia degli eventi di sincronizzazione e la quantità di dati sincronizzati."</string>
- <string name="permlab_sdcardRead" msgid="1438933556581438863">"leggere i contenuti dell\'archivio condiviso"</string>
+ <string name="permlab_sdcardRead" msgid="1438933556581438863">"lettura dei contenuti dell\'archivio condiviso"</string>
<string name="permdesc_sdcardRead" msgid="1804941689051236391">"Consente all\'app di leggere i contenuti del tuo archivio condiviso."</string>
- <string name="permlab_sdcardWrite" msgid="9220937740184960897">"modificare/eliminare i contenuti dell\'archivio condiviso"</string>
+ <string name="permlab_sdcardWrite" msgid="9220937740184960897">"modifica/eliminazione dei contenuti dell\'archivio condiviso"</string>
<string name="permdesc_sdcardWrite" msgid="2834431057338203959">"Consente all\'app di modificare i contenuti del tuo archivio condiviso."</string>
- <string name="permlab_use_sip" msgid="2052499390128979920">"fare/ricevere chiamate SIP"</string>
+ <string name="permlab_use_sip" msgid="2052499390128979920">"invio/ricezione di chiamate SIP"</string>
<string name="permdesc_use_sip" msgid="2297804849860225257">"Consente all\'app di effettuare e ricevere chiamate SIP."</string>
<string name="permlab_register_sim_subscription" msgid="3166535485877549177">"registrazione di nuove connessioni SIM di telecomunicazione"</string>
<string name="permdesc_register_sim_subscription" msgid="2138909035926222911">"Consente all\'app di registrare nuove connessioni SIM di telecomunicazione."</string>
<string name="permlab_register_call_provider" msgid="108102120289029841">"registrazione di nuove connessioni di telecomunicazione"</string>
<string name="permdesc_register_call_provider" msgid="7034310263521081388">"Consente all\'app di registrare nuove connessioni di telecomunicazione."</string>
- <string name="permlab_connection_manager" msgid="1116193254522105375">"gestisci connessioni di telecomunicazione"</string>
+ <string name="permlab_connection_manager" msgid="1116193254522105375">"gestione di connessioni di telecomunicazione"</string>
<string name="permdesc_connection_manager" msgid="5925480810356483565">"Consente all\'app di gestire connessioni di telecomunicazione."</string>
<string name="permlab_bind_incall_service" msgid="6773648341975287125">"interazione con lo schermo durante una chiamata"</string>
<string name="permdesc_bind_incall_service" msgid="8343471381323215005">"Consente all\'app di stabilire quando e come l\'utente vede lo schermo durante una chiamata."</string>
- <string name="permlab_bind_connection_service" msgid="3557341439297014940">"interagire con i servizi di telefonia"</string>
+ <string name="permlab_bind_connection_service" msgid="3557341439297014940">"interazione con i servizi di telefonia"</string>
<string name="permdesc_bind_connection_service" msgid="4008754499822478114">"Consente all\'app di interagire con i servizi di telefonia per effettuare/ricevere chiamate."</string>
<string name="permlab_control_incall_experience" msgid="9061024437607777619">"offerta di un\'esperienza utente durante le chiamate"</string>
<string name="permdesc_control_incall_experience" msgid="915159066039828124">"Consente all\'app di offrire un\'esperienza utente durante le chiamate."</string>
@@ -630,7 +630,7 @@
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"Consente al titolare di vincolarsi all\'interfaccia di primo livello di un servizio listener di notifica. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
<string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"collegamento a un servizio provider di condizioni"</string>
<string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"Consente al titolare di collegarsi all\'interfaccia di primo livello di un servizio provider di condizioni. Non dovrebbe essere mai necessaria per le normali app."</string>
- <string name="permlab_bindDreamService" msgid="4153646965978563462">"associa a servizio dream"</string>
+ <string name="permlab_bindDreamService" msgid="4153646965978563462">"associazione a servizio dream"</string>
<string name="permdesc_bindDreamService" msgid="7325825272223347863">"Consente all\'utente di associare l\'interfaccia di primo livello di un servizio dream. Questa impostazione non è mai necessaria per le app normali."</string>
<string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"richiamo dell\'app di configurazione operatore-provider"</string>
<string name="permdesc_invokeCarrierSetup" msgid="4159549152529111920">"Consente al titolare di richiamare l\'app di configurazione dell\'operatore-provider. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
@@ -646,7 +646,7 @@
<string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Consente a un\'applicazione di rimuovere certificati DRM. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
<string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"associazione a un servizio di messaggi dell\'operatore"</string>
<string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Consente l\'associazione di un servizio di messaggi dell\'operatore all\'interfaccia principale. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
- <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"Collegamento a servizi dell\'operatore"</string>
+ <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"associazione a servizi dell\'operatore"</string>
<string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"Consente al titolare di collegarsi a servizi dell\'operatore. Non dovrebbe mai essere necessaria per le normali app."</string>
<string name="permlab_access_notification_policy" msgid="4247510821662059671">"accesso alla funzione Non disturbare"</string>
<string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Consente all\'app di leggere e modificare la configurazione della funzione Non disturbare."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Apri con"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Apri con %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Apri"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Apri i link <xliff:g id="HOST">%1$s</xliff:g> con"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Apri i link con"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Apri i link con <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Apri i link <xliff:g id="HOST">%1$s</xliff:g> con <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Fornisci accesso"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Modifica con"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Modifica con %1$s"</string>
@@ -1434,7 +1430,7 @@
<string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Consente a un\'applicazione di richiedere l\'installazione di pacchetti."</string>
<string name="permlab_requestDeletePackages" msgid="1703686454657781242">"richiesta di eliminazione dei pacchetti"</string>
<string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"Consente a un\'applicazione di richiedere l\'eliminazione di pacchetti."</string>
- <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"chiedi di ignorare le ottimizzazioni della batteria"</string>
+ <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"richiesta di ignorare le ottimizzazioni della batteria"</string>
<string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"Consente a un\'app di chiedere l\'autorizzazione a ignorare le ottimizzazioni della batteria per quell\'app."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Tocca due volte per il comando dello zoom"</string>
<string name="gadget_host_error_inflating" msgid="4882004314906466162">"Aggiunta del widget non riuscita."</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Avviare l\'applicazione Browser?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Accettare la chiamata?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Imposta per aprire sempre"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Solo una volta"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Impostazioni"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s non supporta il profilo di lavoro"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 8add3d75c638..437b31b652bb 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -574,7 +574,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"צריך להזיז את הטלפון שמאלה."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"צריך להזיז את הטלפון ימינה."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"יש להביט ישירות אל המכשיר."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"אי אפשר לראות את הפנים שלך. צריך להביט אל הטלפון."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"עליך למקם את הפנים ישירות מול הטלפון."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"יותר מדי תנועה. יש להחזיק את הטלפון בצורה יציבה."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"יש לרשום מחדש את הפנים."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"כבר לא ניתן לזהות פנים. יש לנסות שוב."</string>
@@ -1171,14 +1171,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"פתח באמצעות"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"‏פתח באמצעות %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"פתח"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"פתיחת קישורים של <xliff:g id="HOST">%1$s</xliff:g> באמצעות"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"פתיחת קישורים באמצעות"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"פתיחת קישורים באמצעות <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"פתיחת קישורים של <xliff:g id="HOST">%1$s</xliff:g> באמצעות <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"הענקת גישה"</string>
<string name="whichEditApplication" msgid="144727838241402655">"ערוך באמצעות"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"‏ערוך באמצעות %1$s"</string>
@@ -1636,8 +1632,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"להפעיל את הדפדפן?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"האם לקבל את השיחה?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"תמיד"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"הגדרה כברירת מחדל לפתיחה"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"רק פעם אחת"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"הגדרות"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"‏%1$s אינו תומך בפרופיל עבודה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 2d09d67df392..b558a318aa1e 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"スマートフォンを左に動かしてください。"</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"スマートフォンを右に動かしてください。"</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"もっとまっすぐデバイスに顔を向けてください。"</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"顔を確認できません。スマートフォンを見てください。"</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"顔をスマートフォンの真正面に向けてください。"</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"あまり動かさないでください。安定させてください。"</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"顔を登録し直してください。"</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"顔を認識できなくなりました。もう一度お試しください。"</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"アプリで開く"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$sで開く"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"開く"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> のリンクを開くブラウザ / アプリの選択"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"リンクを開くブラウザの選択"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"<xliff:g id="APPLICATION">%1$s</xliff:g> でリンクを開く"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="APPLICATION">%2$s</xliff:g> で <xliff:g id="HOST">%1$s</xliff:g> のリンクを開く"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"アクセス権を付与"</string>
<string name="whichEditApplication" msgid="144727838241402655">"編集に使用"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sで編集"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"ブラウザを起動しますか?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"通話を受けますか?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"常時"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"[常に開く] に設定"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"1回のみ"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"設定"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$sは仕事用プロファイルをサポートしていません"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index f81067837733..3570d4ccecfd 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"გადაანაცვლეთ ტელეფონი მარცხნივ."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"გადაანაცვლეთ ტელეფონი მარჯვნივ."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"გთხოვთ, უფრო პირდაპირ შეხედოთ თქვენს მოწყობილობას."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"თქვენი სახე არ ჩანს. შეხედეთ ტელეფონს."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"დაიჭირეთ სახე უშუალოდ ტელეფონის წინ."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"მეტისმეტად მოძრაობთ. მყარად დაიჭირეთ ტელეფონი."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"გთხოვთ, ხელახლა დაარეგისტრიროთ თქვენი სახე."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"სახის ამოცნობა ვეღარ ხერხდება. ცადეთ ხელახლა."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"გახსნა აპით"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s-ით გახსნა"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"გახსნა"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> ბმულების გახსნა შემდეგით:"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"ბმულების გახსნა შემდეგით:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"ბმულების გახსნა <xliff:g id="APPLICATION">%1$s</xliff:g>-ით"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g> ბმულების <xliff:g id="APPLICATION">%2$s</xliff:g>-ით გახსნა"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"წვდომის მინიჭება"</string>
<string name="whichEditApplication" msgid="144727838241402655">"რედაქტირება აპით:"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"რედაქტირება %1$s-ით"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"გსურთ ბრაუზერის გაშვება?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"უპასუხებთ ზარს?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"ყოველთვის"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"ყოველთვის გახსნის დაყენება"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"მხოლოდ ერთხელ"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"პარამეტრები"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s მხარს არ უჭერს სამუშაო პროფილს"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 3c429865e063..2ed1e5bf5541 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Телефонды солға жылжытыңыз."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Телефонды оңға жылжытыңыз."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Құрылғының камерасына тура қараңыз."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Бетіңіз көрінбейді. Телефонға қараңыз."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Бетіңізді телефонға тура қаратыңыз."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Қозғалыс тым көп. Телефонды қозғалтпаңыз."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Қайта тіркеліңіз."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Енді бет анықтау мүмкін емес. Әрекетті қайталаңыз."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Басқаша ашу"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s қолданбасымен ашу"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ашу"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> сілтемелерін келесімен ашу:"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Сілтемелерді келесімен ашу:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Сілтемелерді <xliff:g id="APPLICATION">%1$s</xliff:g> браузерімен ашу"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g> сілтемелерін <xliff:g id="APPLICATION">%2$s</xliff:g> браузерімен ашу"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Рұқсат беру"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Келесімен өңдеу"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s көмегімен өңдеу"</string>
@@ -1591,8 +1587,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Браузер қосылсын ба?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Қоңырауды қабылдау?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Үнемі"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Әрдайым ашық күйге орнату"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Бір рет қана"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Параметрлер"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s жұмыс профилін қолдамайды"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index b088f4e811d6..02c6ba8cc233 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"ផ្លាស់ទី​ទូរសព្ទទៅខាងឆ្វេង។"</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"ផ្លាស់ទីទូរសព្ទទៅខាងស្ដាំ។"</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"សូមមើល​ឱ្យចំ​ឧបករណ៍​របស់អ្នក​ជាងមុន។"</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"មើលមិនឃើញ​មុខ​របស់អ្នកទេ។ សូមសម្លឹងមើល​ទូរសព្ទ។"</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"បែរមុខ​របស់អ្នក​ឱ្យចំ​ពីមុខ​ទូរសព្ទ​ផ្ទាល់។"</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"មាន​ចលនា​ខ្លាំងពេក។ សូមកាន់​ទូរសព្ទ​ឱ្យនឹង។"</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"សូម​​ស្កេន​បញ្ចូល​មុខរបស់អ្នក​ម្ដងទៀត។"</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"មិន​អាច​សម្គាល់មុខ​បាន​ទៀតទេ។ សូមព្យាយាមម្ដងទៀត។"</string>
@@ -1133,14 +1133,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"បើក​ជា​មួយ"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"បើក​ជាមួយ %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"បើក"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"បើក​តំណ <xliff:g id="HOST">%1$s</xliff:g> ជាមួយ"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"បើកតំណជាមួយ"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"បើក​តំណជាមួយ <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"បើក​តំណ <xliff:g id="HOST">%1$s</xliff:g> ជាមួយ <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ផ្តល់​សិទ្ធិ​ចូល​ប្រើ"</string>
<string name="whichEditApplication" msgid="144727838241402655">"កែសម្រួល​ជាមួយ"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"កែសម្រួល​ជាមួយ​ %1$s"</string>
@@ -1592,8 +1588,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"ចាប់ផ្ដើម​កម្មវិធី​អ៊ីនធឺណិត?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"ទទួល​ការ​ហៅ​?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"ជា​និច្ច"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"កំណត់​ឱ្យ​បើក​ជានិច្ច"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"តែ​ម្ដង"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"ការកំណត់"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s មិន​គាំទ្រ​ប្រវត្តិរូប​ការងារ"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 6da7eec48161..875ecd41eb4a 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"ಫೋನ್ ಅನ್ನು ಎಡಕ್ಕೆ ಸರಿಸಿ."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"ಫೋನ್ ಅನ್ನು ಬಲಕ್ಕೆ ಸರಿಸಿ."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಹೆಚ್ಚಿನದ್ದನ್ನು ನೇರವಾಗಿ ನೋಡಿ."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"ನಿಮ್ಮ ಮುಖ ಕಾಣಿಸುತ್ತಿಲ್ಲ. ಫೋನ್ ಕಡೆಗೆ ನೋಡಿ."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"ನಿಮ್ಮ ಮುಖವನ್ನು ಫೋನ್‌ಗೆ ನೇರವಾಗಿ ಇರಿಸಿ."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"ತುಂಬಾ ಅಲುಗಾಡುತ್ತಿದೆ ಫೋನ್ ಅನ್ನು ಸ್ಥಿರವಾಗಿ ಹಿಡಿಯಿರಿ."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"ನಿಮ್ಮ ಮುಖವನ್ನು ಮರುನೋಂದಣಿ ಮಾಡಿ."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"ಮುಖ ಗುರುತಿಸಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ. ಪುನಃ ಪ್ರಯತ್ನಿಸಿ."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"ಇದರ ಮೂಲಕ ತೆರೆಯಿರಿ"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ಜೊತೆಗೆ ತೆರೆಯಿರಿ"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"ತೆರೆ"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"ಇವುಗಳ ಮೂಲಕ <xliff:g id="HOST">%1$s</xliff:g> ಲಿಂಕ್‌ಗಳನ್ನು ತೆರೆಯಿರಿ"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"ಇವುಗಳ ಮೂಲಕ ಲಿಂಕ್‌ಗಳನ್ನು ತೆರೆಯಿರಿ"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"<xliff:g id="APPLICATION">%1$s</xliff:g> ಮೂಲಕ ಲಿಂಕ್‌ಗಳನ್ನು ತೆರೆಯಿರಿ"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="APPLICATION">%2$s</xliff:g> ಮೂಲಕ <xliff:g id="HOST">%1$s</xliff:g> ಲಿಂಕ್‌ಗಳನ್ನು ತೆರೆಯಿರಿ"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ಪ್ರವೇಶ ಅನುಮತಿಸಿ"</string>
<string name="whichEditApplication" msgid="144727838241402655">"ಇವರ ಜೊತೆಗೆ ಎಡಿಟ್ ಮಾಡಿ"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ಜೊತೆಗೆ ಎಡಿಟ್ ಮಾಡಿ"</string>
@@ -1591,8 +1587,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"ಬ್ರೌಸರ್ ಪ್ರಾರಂಭಿಸುವುದೇ?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"ಕರೆ ಸ್ವೀಕರಿಸುವುದೇ?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"ಯಾವಾಗಲೂ"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"ಯಾವಾಗಲೂ ತೆರೆಯುವುದಕ್ಕೆ ಹೊಂದಿಸಿ"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"ಒಮ್ಮೆ ಮಾತ್ರ"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ಕೆಲಸದ ಪ್ರೊಫೈಲ್ ಅನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 853ccff84648..90771451866a 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"휴대전화를 왼쪽으로 이동하세요."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"휴대전화를 오른쪽으로 이동하세요."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"기기에서 더 똑바로 바라보세요."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"얼굴이 보이지 않습니다. 휴대전화를 바라보세요."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"휴대전화가 얼굴 정면을 향하도록 두세요."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"너무 많이 움직였습니다. 휴대전화를 흔들리지 않게 잡으세요."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"얼굴을 다시 등록해 주세요."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"더 이상 얼굴을 인식할 수 없습니다. 다시 시도하세요."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"연결 프로그램"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s(으)로 열기"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"열기"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> 링크를 열 때 사용할 앱"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"링크를 열 때 사용할 앱"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"<xliff:g id="APPLICATION">%1$s</xliff:g> 앱으로 링크 열기"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="APPLICATION">%2$s</xliff:g> 앱으로 <xliff:g id="HOST">%1$s</xliff:g> 링크 열기"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"권한 부여"</string>
<string name="whichEditApplication" msgid="144727838241402655">"편집 프로그램:"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s(으)로 수정"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"브라우저를 실행하시겠습니까?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"통화를 수락하시겠습니까?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"항상"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"항상 열도록 설정"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"한 번만"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"설정"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s에서 직장 프로필을 지원하지 않습니다."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index e5b11ba96753..8cac3638ae28 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Телефонду солго жылдырыңыз."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Телефонду оңго жылдырыңыз."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Түзмөгүңүзгө түз караңыз."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Жүзүңүз көрүнбөй жатат. Телефонду караңыз."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Телефонду жүзүңүздүн маңдайында кармаңыз."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Кыймылдап жибердиңиз. Телефонду түз кармаңыз."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Жүзүңүздү кайра таанытыңыз."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Жүз таанылган жок. Кайра аракет кылыңыз."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Төмөнкү менен ачуу"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s менен ачуу"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ачуу"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> шилтемелерин төмөнкү колдонмодо ачуу:"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Шилтемелерди төмөнкү колдонмодо ачуу:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Шилтемелерди <xliff:g id="APPLICATION">%1$s</xliff:g> колдонмосунда ачуу"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g> шилтемелерин <xliff:g id="APPLICATION">%2$s</xliff:g> колдонмосунда ачуу"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Мүмкүнчүлүк берүү"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Төмөнкү менен түзөтүү"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s менен түзөтүү"</string>
@@ -1592,8 +1588,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Серепчи иштетилсинби?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Чалуу кабыл алынсынбы?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Дайыма"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Ар дайым ачылсын деп жөндөө"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Бир жолу гана"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Жөндөөлөр"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s жумуш профилин колдоого албайт"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 74b311a09432..47b0fe49796e 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"ຍ້າຍໂທລະສັບໄປທາງຊ້າຍ."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"ຍ້າຍໂທລະສັບໄປທາງຂວາ."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"ກະລຸນາເບິ່ງອຸປະກອນຂອງທ່ານໃຫ້ຊື່ໆ."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"ບໍ່ສາມາດເບິ່ງເຫັນໜ້າຂອງທ່ານໄດ້. ກະລຸນາເບິ່ງໂທລະສັບ."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"ຫັນໜ້າຂອງທ່ານໄປໃສ່ໜ້າໂທລະສັບໂດຍກົງ."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"ເຄື່ອນໄຫວຫຼາຍເກີນໄປ. ກະລຸນາຖືໂທລະສັບໄວ້ຊື່ໆ."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"ກະລຸນາລົງທະບຽນອຸປະກອນຂອງທ່ານອີກເທື່ອໜຶ່ງ."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"ບໍ່ສາມາດຈຳແນກໃບໜ້າໄດ້ອີກຕໍ່ໄປ. ກະລຸນາລອງໃໝ່."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"ເປີດໂດຍໃຊ້"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"ເປີດ​ໂດຍ​ໃຊ້ %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"ເປີດ"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"ເປີດລິ້ງ <xliff:g id="HOST">%1$s</xliff:g> ໂດຍໃຊ້"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"ເປີດລິ້ງໂດຍໃຊ້"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"ເປີດລິ້ງໂດຍໃຊ້ <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"ເປີດລິ້ງ <xliff:g id="HOST">%1$s</xliff:g> ໂດຍໃຊ້ <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ໃຫ້ສິດອະນຸຍາດ"</string>
<string name="whichEditApplication" msgid="144727838241402655">"​ແກ້​ໄຂ​ໃນ"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"ແກ້​ໄຂ​ໃນ %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"ເປີດໂປຣແກຣມທ່ອງເວັບ?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"ຮັບການໂທບໍ່?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"ທຸກຄັ້ງ"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"ຕັ້ງໃຫ້ເປັນເປີດທຸກເທື່ອ"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"ຄັ້ງດຽວ"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"ການຕັ້ງຄ່າ"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ບໍ່​ຮອງ​ຮັບ​ໂປຣ​ໄຟລ໌​ບ່ອນ​ເຮັດ​ວຽກ​ຂອງ​ທ່ານ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 191108a0b73b..6f8e2df08241 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -574,7 +574,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Pasukite telefoną kairėn."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Pasukite telefoną dešinėn."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Žiūrėkite tiesiai į įrenginį."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Nematau jūsų veido. Žiūrėkite į telefoną."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Veidas turi būti prieš telefoną."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Įrenginys per daug judinamas. Nejudink. telefono."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Užregistruokite veidą iš naujo."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Nebegalima atpažinti veido. Bandykite dar kartą."</string>
@@ -1171,14 +1171,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Atidaryti naudojant"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Atidaryti naudojant %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Atidaryti"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Atidaryti <xliff:g id="HOST">%1$s</xliff:g> nuorodas naudojant"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Atidaryti nuorodas naudojant"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Atidaryti nuorodas naudojant „<xliff:g id="APPLICATION">%1$s</xliff:g>“"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Atidaryti <xliff:g id="HOST">%1$s</xliff:g> nuorodas naudojant „<xliff:g id="APPLICATION">%2$s</xliff:g>“"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Suteikti prieigą"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Redaguoti naudojant"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redaguoti naudojant %1$s"</string>
@@ -1636,8 +1632,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Paleisti naršyklę?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Priimti skambutį?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Visada"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Nustatyti parinktį „Visada atidaryti“"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Tik kartą"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Nustatymai"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s nepalaiko darbo profilio"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 94f14891eec7..253ff722ffda 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -571,7 +571,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Pārvietojiet tālruni pa kreisi."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Pārvietojiet tālruni pa labi."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Lūdzu, tiešāk skatieties uz savu ierīci."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Jūsu seja nav redzama. Paskatieties uz tālruni."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Novietojiet savu seju tieši pretī tālrunim."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Pārāk daudz kustību. Nekustīgi turiet tālruni."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Lūdzu, atkārtoti reģistrējiet savu seju."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Seju vairs nevar atpazīt. Mēģiniet vēlreiz."</string>
@@ -1151,14 +1151,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Atvērt, izmantojot"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Atvērt, izmantojot %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Atvērt"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> saišu atvēršana, izmantojot:"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Saišu atvēršana, izmantojot:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Saišu atvēršana, izmantojot pārlūku <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g> saišu atvēršana, izmantojot pārlūku <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Atļaut piekļuvi"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Rediģēt, izmantojot"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Rediģēt, izmantojot %1$s"</string>
@@ -1613,8 +1609,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Vai palaist pārlūkprogrammu?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Vai atbildēt uz zvanu?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Vienmēr"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Iestatīt uz “Vienmēr atvērt”"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Tikai vienreiz"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Iestatījumi"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Programma %1$s neatbalsta darba profilus"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 71d695ab7f02..19c1c85c28d7 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Поместете го телефонот налево."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Поместете го телефонот надесно."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Погледнете подиректно во уредот."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Не ви се гледа ликот. Гледајте во телефонот."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Наместете го лицето директно пред телефонот."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Премногу движење. Држете го телефонот стабилно."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Повторно регистрирајте го лицето."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Ликот не се препознава. Обидете се повторно."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Отвори со"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Отвори со %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Отвори"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Отворајте врски на <xliff:g id="HOST">%1$s</xliff:g> со"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Отворајте врски со"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Отворајте врски со <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Отворајте врски на <xliff:g id="HOST">%1$s</xliff:g> со <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Дозволи пристап"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Измени со"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Измени со %1$s"</string>
@@ -1593,8 +1589,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Стартувај прелистувач?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Прифати повик?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Секогаш"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Поставете на секогаш отворај"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Само еднаш"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Поставки"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не поддржува работен профил"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index b58f19502c91..b2e9b643366c 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"ഫോൺ ഇടത്തോട്ട് നീക്കുക."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"ഫോൺ വലത്തോട്ട് നീക്കുക."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"നിങ്ങളുടെ ഉപകരണത്തിന് നേരെ കൂടുതൽ നന്നായി നോക്കുക."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"നിങ്ങളുടെ മുഖം കാണാനാവുന്നില്ല. ഫോണിലേക്ക് നോക്കൂ."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"നിങ്ങളുടെ മുഖം ക്യാമറയ്‌ക്ക് നേരെയാക്കുക."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"വളരെയധികം ചലനം. ഫോൺ അനക്കാതെ നേരെ പിടിക്കുക."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"നിങ്ങളുടെ മുഖം വീണ്ടും എൻറോൾ ചെയ്യുക."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"ഇനി മുഖം തിരിച്ചറിയാനാവില്ല. വീണ്ടും ശ്രമിക്കൂ."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"ഇത് ഉപയോഗിച്ച് തുറക്കുക"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ഉപയോഗിച്ച് തുറക്കുക"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"തുറക്കുക"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"ഇനിപ്പറയുന്നത് ഉപയോഗിച്ച് <xliff:g id="HOST">%1$s</xliff:g> ലിങ്കുകൾ തുറക്കുക"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"ഇനിപ്പറയുന്നത് ഉപയോഗിച്ച് ലിങ്കുകൾ തുറക്കുക"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"<xliff:g id="APPLICATION">%1$s</xliff:g> ഉപയോഗിച്ച് ലിങ്കുകൾ തുറക്കുക"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g> ലിങ്കുകൾ <xliff:g id="APPLICATION">%2$s</xliff:g> ഉപയോഗിച്ച് തുറക്കുക"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ആക്‌സസ് നൽകുക"</string>
<string name="whichEditApplication" msgid="144727838241402655">"ഇത് ഉപയോഗിച്ച് എഡിറ്റുചെയ്യുക"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ഉപയോഗിച്ച് എഡിറ്റുചെയ്യുക"</string>
@@ -1591,8 +1587,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"ബ്രൗസർ സമാരംഭിക്കണോ?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"കോൾ സ്വീകരിക്കണോ?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"എല്ലായ്പ്പോഴും"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"\'എല്ലായ്‌പ്പോഴും തുറക്കുക\' എന്നതിലേക്കാക്കുക"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"ഒരിക്കൽ മാത്രം"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"ക്രമീകരണം"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s, ഔദ്യോഗിക പ്രൊഫൈലിനെ പിന്തുണയ്‌ക്കുന്നില്ല"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 9f1de468a100..a229713fd61e 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Утсаа зүүн тийш болгоно уу."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Утсаа баруун тийш болгоно уу."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Төхөөрөмж рүүгээ аль болох эгц харна уу."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Таны царайг харахгүй байна. Утас руу харна уу."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Царайгаа утасны урд эгц байрлуулна уу"</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Хэт их хөдөлгөөнтэй байна. Утсаа хөдөлгөөнгүй барина уу."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Нүүрээ дахин бүртгүүлнэ үү."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Царайг таних боломжгүй боллоо. Дахин оролдоно уу."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Нээх"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ашиглан нээх"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Нээх"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g>-н холбоосуудыг дараахаар нээх"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Холбоосуудыг дараахаар нээх"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Холбоосуудыг <xliff:g id="APPLICATION">%1$s</xliff:g>-р нээх"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g>-н холбоосуудыг <xliff:g id="APPLICATION">%2$s</xliff:g>-р нээх"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Хандалт өгөх"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Засварлах"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ашиглан засварлах"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Хөтөч ажиллуулах уу?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Дуудлагыг зөвшөөрөх үү?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Байнга"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Тогтмол нээлттэй гэж тохируулах"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Нэг удаа"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Тохиргоо"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ажлын профайлыг дэмждэггүй"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index f2111e7ebcda..a86caa5c0fc8 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"फोन डावीकडे हलवा."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"फोन उजवीकडे हलवा."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"कृपया तुमच्या डिव्हाइसकडे थेट पाहा"</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"तुमचा चेहरा दिसत नाही. फोनकडे पहा."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"तुमचा चेहरा थेट फोन समोर आणा."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"खूप हलत आहे. फोन स्थिर धरून ठेवा."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"कृपया तुमच्या चेहऱ्याची पुन्हा नोंदणी करा."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"चेहरा ओळखू शकत नाही. पुन्हा प्रयत्न करा."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"यासह उघडा"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s सह उघडा"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"उघडा"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"वापरून <xliff:g id="HOST">%1$s</xliff:g> लिंक उघडा"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"वापरून लिंक उघडा"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"<xliff:g id="APPLICATION">%1$s</xliff:g> वापरून लिंक उघडा"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="APPLICATION">%2$s</xliff:g> वापरून <xliff:g id="HOST">%1$s</xliff:g> लिंक उघडा"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"अ‍ॅक्सेस द्या"</string>
<string name="whichEditApplication" msgid="144727838241402655">"सह संपादित करा"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s सह संपादित करा"</string>
@@ -1591,8 +1587,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"ब्राउझर लाँच करायचा?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"कॉल स्वीकारायचा?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"नेहमी"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"नेहमी उघडावर सेट करा"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"फक्त एकदाच"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"सेटिंग्ज"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s कार्य प्रोफाईलचे समर्थन करीत नाही"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 49a55782a3dd..c18e07879512 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Alihkan telefon ke kiri."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Alihkan telefon ke kanan."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Sila lihat terus pada peranti anda."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Gagal mengesan wajah anda. Lihat telefon."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Letakkan wajah anda betul-betul di depan telefon."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Terlalu bnyk gerakan. Pegang telefon dgn stabil."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Sila daftarkan semula wajah anda."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Tidak lagi dapat mengecam wajah. Cuba lagi."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Buka dengan"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Buka dengan %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Buka"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Buka pautan <xliff:g id="HOST">%1$s</xliff:g> dengan"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Buka pautan dengan"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Buka pautan dengan <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Buka pautan <xliff:g id="HOST">%1$s</xliff:g> dengan <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Berikan akses"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Edit dengan"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edit dengan %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Lancarkan Penyemak Imbas?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Terima panggilan?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Sentiasa"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Tetapkan agar sentiasa dibuka"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Hanya sekali"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Tetapan"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s tidak menyokong profil kerja"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index bbe115feb5f9..55e7b015fe00 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"ဖုန်းကို ဘယ်ဘက်သို့ရွှေ့ပါ။"</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"ဖုန်းကို ညာဘက်သို့ ရွှေ့ပါ။"</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"သင့်စက်ပစ္စည်းကို တည့်တည့်ကြည့်ပါ။"</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"သင့်မျက်နှာကို မမြင်ရပါ။ ဖုန်းကိုကြည့်ပါ။"</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"မျက်နှာကို ဖုန်းရှေ့တွင် တည့်အောင်ထားပါ။"</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"လှုပ်လွန်းသည်။ ဖုန်းကို ငြိမ်ငြိမ်ကိုင်ပါ။"</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"သင့်မျက်နှာကို ပြန်စာရင်းသွင်းပါ။"</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"မျက်နှာ မမှတ်သားနိုင်တော့ပါ။ ထပ်စမ်းကြည့်ပါ။"</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"...ဖြင့် ဖွင့်မည်"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ဖြင့် ဖွင့်မည်"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"ဖွင့်ပါ"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> လင့်ခ်များကို အောက်ပါဖြင့် ဖွင့်ရန်−"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"လင့်ခ်များကို အောက်ပါဖြင့် ဖွင့်ရန်−"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"လင့်ခ်ကို <xliff:g id="APPLICATION">%1$s</xliff:g> ဖြင့် ဖွင့်ရန်"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g> လင့်ခ်များကို <xliff:g id="APPLICATION">%2$s</xliff:g> ဖြင့် ဖွင့်ရန်"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ဖွင့်ခွင့်ပေးရန်"</string>
<string name="whichEditApplication" msgid="144727838241402655">"...နှင့် တည်းဖြတ်ရန်"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s နှင့် တည်းဖြတ်ရန်"</string>
@@ -1591,8 +1587,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"ဘရောက်ဇာ ဖွင့်မည်လား။"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"ဖုန်းခေါ်ဆိုမှုကို လက်ခံမလား?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"အမြဲတမ်း"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"အမြဲဖွင့်မည်အဖြစ် သတ်မှတ်ရန်"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"တစ်ခါတည်း"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"ဆက်တင်များ"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s က အလုပ်ပရိုဖိုင်ကို မပံ့ပိုးပါ။"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 34275dff32e7..a5893892bc70 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Flytt telefonen til venstre."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Flytt telefonen til høyre."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Se mer direkte på enheten din."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Kan ikke se ansiktet ditt. Se på telefonen."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Hold ansiktet ditt rett foran telefonen."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"For mye bevegelse. Hold telefonen stødig."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Registrer ansiktet ditt på nytt."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Kan ikke gjenkjenne ansiktet lenger. Prøv igjen."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Åpne med"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Åpne med %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Åpne"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Åpne <xliff:g id="HOST">%1$s</xliff:g>-linker med"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Åpne linker med"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Åpne linker med <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Åpne <xliff:g id="HOST">%1$s</xliff:g>-linker med <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Gi tilgang"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Rediger med"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Rediger med %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Vil du starte nettleseren?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Vil du besvare anropet?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Alltid"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Angi som alltid åpen"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Bare én gang"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Innstillinger"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s støtter ikke arbeidsprofiler"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 80bd83a6016b..89e75b4257ac 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"फोन बायाँतिर सार्नुहोस्।"</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"फोन दायाँतिर सार्नुहोस्।"</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"कृपया अझ सीधा गरी आफ्नो स्क्रिनमा हेर्नुहोस्।"</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"तपाईंको अनुहार देखिएन। फोनमा हेर्नुहोस्।"</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"आफ्नो अनुहार फोनको सीधा अगाडि पार्नुहोस्।"</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"अत्यधिक हल्लियो। फोन स्थिर राख्नुहोस्।"</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"कृपया आफ्नो अनुहार पुनः दर्ता गर्नुहोस्।"</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"अब उप्रान्त अनुहार पहिचान गर्न सकिएन। फेरि प्रयास गर्नुहोस्।"</string>
@@ -1135,14 +1135,10 @@
<!-- no translation found for whichViewApplicationNamed (2286418824011249620) -->
<skip />
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"खोल्नुहोस्"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"निम्नमार्फत <xliff:g id="HOST">%1$s</xliff:g> का लिंकहरू खोल्नुहोस्"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"निम्नमार्फत लिंकहरू खोल्नुहोस्"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"<xliff:g id="APPLICATION">%1$s</xliff:g> मार्फत लिंकहरू खोल्नुहोस्"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="APPLICATION">%2$s</xliff:g> मार्फत <xliff:g id="HOST">%1$s</xliff:g> का लिंकहरू खोल्नुहोस्"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"पहुँच दिनुहोस्"</string>
<string name="whichEditApplication" msgid="144727838241402655">"सँग सम्पादन गर्नुहोस्"</string>
<!-- String.format failed for translation -->
@@ -1596,8 +1592,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"ब्राउजर सुरु गर्ने हो?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"कल स्वीकार गर्नुहुन्छ?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"सधैँ"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"सधैँ खुला राख्ने गरी सेट गर्नुहोस्"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"एक पटक मात्र"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"सेटिङहरू"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s कार्य प्रोफाइल समर्थन गर्दैन"</string>
@@ -1975,7 +1970,7 @@
<string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"तटीय क्षेत्र र नदीछेउका ठाउँहरू छाडी उच्च सतहमा अवस्थित कुनै अझ सुरक्षित ठाउँमा जानुहोस्।"</string>
<string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"शान्त रहनुहोस् र नजिकै आश्रयस्थल खोज्नुहोस्।"</string>
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"आपतकालीन सन्देशहरूको परीक्षण"</string>
- <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"जवाफ दिनुहोस्"</string>
+ <string name="notification_reply_button_accessibility" msgid="3621714652387814344">"जवाफ दिनु…"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
<string name="mmcc_authentication_reject" msgid="5767701075994754356">"SIM मार्फत भ्वाइस कल गर्न मिल्दैन"</string>
<string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"SIM मार्फत भ्वाइस कल गर्ने प्रावधान छैन"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 7c23e2c1131b..4194eb15b6af 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Beweeg je telefoon meer naar links."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Beweeg je telefoon meer naar rechts."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Kijk rechter naar je apparaat."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Je gezicht is niet te zien. Kijk naar de telefoon."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Houd je gezicht recht voor de telefoon."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Te veel beweging. Houd je telefoon stil."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Registreer je gezicht opnieuw."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Herkent gezicht niet meer. Probeer het nog eens."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Openen met"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Openen met %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Openen"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Links van <xliff:g id="HOST">%1$s</xliff:g> openen met"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Links openen met"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Links openen met <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Links van <xliff:g id="HOST">%1$s</xliff:g> openen met <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Toegang geven"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Bewerken met"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Bewerken met %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Browser starten?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Gesprek accepteren?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Altijd"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Instellen op altijd openen"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Één keer"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Instellingen"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ondersteunt werkprofielen niet"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 257dd065fe3e..0f3472c10fb5 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"ବାମ ପଟକୁ ଫୋନ୍ ଘୁଞ୍ଚାନ୍ତୁ।"</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"ଡାହାଣ ପଟକୁ ଫୋନ୍ ଘୁଞ୍ଚାନ୍ତୁ।"</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"ଦୟାକରି ଆପଣଙ୍କ ଡିଭାଇସ୍‌କୁ ସିଧାସଳଖ ଦେଖନ୍ତୁ।"</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"ଆପଣଙ୍କର ମୁହଁ ଦେଖି ପାରୁନାହିଁ। ଫୋନ୍‌କୁ ଦେଖନ୍ତୁ।"</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"ଆପଣଙ୍କ ମୁହଁକୁ ଫୋନ୍ ସାମ୍ନାରେ ସିଧାସଳଖ ରଖନ୍ତୁ।"</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"ଅତ୍ୟଧିକ ଅସ୍ଥିର। ଫୋନ୍‍କୁ ସ୍ଥିର ଭାବେ ଧରନ୍ତୁ।"</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"ଦୟାକରି ଆପଣଙ୍କର ମୁହଁ ପୁଣି-ଏନ୍‍ରୋଲ୍ କରନ୍ତୁ।"</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"ଆଉ ମୁହଁ ଚିହ୍ନଟ କରିହେଲା ନାହିଁ। ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"ସହିତ ଖୋଲନ୍ତୁ"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ସହିତ ଖୋଲନ୍ତୁ"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"ଖୋଲନ୍ତୁ"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"ଏଥିରେ <xliff:g id="HOST">%1$s</xliff:g> ଲିଙ୍କ୍‍ଗୁଡ଼ିକ ଖୋଲନ୍ତୁ"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"ଏଥିରେ ଲିଙ୍କ୍‍ଗୁଡ଼ିକ ଖୋଲନ୍ତୁ"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"<xliff:g id="APPLICATION">%1$s</xliff:g> ମାଧ୍ୟମରେ ଲିଙ୍କ୍‍ଗୁଡ଼ିକ ଖୋଲନ୍ତୁ"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="APPLICATION">%2$s</xliff:g> ମାଧ୍ୟମରେ <xliff:g id="HOST">%1$s</xliff:g> ଲିଙ୍କ୍‍ଗୁଡ଼ିକ ଖୋଲନ୍ତୁ"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ଆକ୍ସେସ୍‌ ଦିଅନ୍ତୁ"</string>
<string name="whichEditApplication" msgid="144727838241402655">"ସହିତ ଏଡିଟ୍‌ କରନ୍ତୁ"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sରେ ସଂଶୋଧନ କରନ୍ତୁ"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"ବ୍ରାଉଜର୍‍ ଲଞ୍ଚ କରିବେ?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"କଲ୍‍ ସ୍ୱୀକାର କରିବେ?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"ସର୍ବଦା"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"\'ସର୍ବଦା ଖୋଲା\' ଭାବରେ ସେଟ୍ କରନ୍ତୁ"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"ଥରେ ମାତ୍ର"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"ସେଟିଂସ୍"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ୱର୍କ ପ୍ରୋଫାଇଲ୍‌କୁ ସପୋର୍ଟ କରୁନାହିଁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 104fb40115f3..8245546a4436 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"ਫ਼ੋਨ ਨੂੰ ਖੱਬੇ ਪਾਸੇ ਲਿਜਾਓ।"</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"ਫ਼ੋਨ ਨੂੰ ਸੱਜੇ ਪਾਸੇ ਲਿਜਾਓ।"</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"ਕਿਰਪਾ ਕਰਕੇ ਸਿੱਧਾ ਆਪਣੇ ਡੀਵਾਈਸ ਵੱਲ ਦੇਖੋ।"</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"ਤੁਹਾਡਾ ਚਿਹਰਾ ਨਹੀਂ ਦਿਸ ਰਿਹਾ। ਫ਼ੋਨ ਵੱਲ ਦੇਖੋ।"</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"ਆਪਣਾ ਚਿਹਰਾ ਫ਼ੋਨ ਦੇ ਬਿਲਕੁਲ ਸਾਹਮਣੇ ਰੱਖੋ।"</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"ਬਹੁਤ ਜ਼ਿਆਦਾ ਹਿਲਜੁਲ। ਫ਼ੋਨ ਨੂੰ ਸਥਿਰ ਰੱਖੋ।"</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"ਕਿਰਪਾ ਕਰਕੇ ਆਪਣਾ ਚਿਹਰਾ ਦੁਬਾਰਾ ਦਰਜ ਕਰੋ।"</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"ਹੁਣ ਚਿਹਰਾ ਪਛਾਣਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"ਨਾਲ ਖੋਲ੍ਹੋ"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ਨਾਲ ਖੋਲ੍ਹੋ"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"ਖੋਲ੍ਹੋ"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> ਲਿੰਕਾਂ ਨੂੰ ਇਸ ਨਾਲ ਖੋਲ੍ਹੋ"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"ਲਿੰਕਾਂ ਨੂੰ ਇਸ ਨਾਲ ਖੋਲ੍ਹੋ"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"ਲਿੰਕਾਂ ਨੂੰ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨਾਲ ਖੋਲ੍ਹੋ"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g> ਲਿੰਕਾਂ ਨੂੰ <xliff:g id="APPLICATION">%2$s</xliff:g> ਨਾਲ ਖੋਲ੍ਹੋ"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ਪਹੁੰਚ ਦਿਓ"</string>
<string name="whichEditApplication" msgid="144727838241402655">"ਇਸ ਨਾਲ ਸੰਪਾਦਨ ਕਰੋ"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ਨਾਲ ਸੰਪਾਦਨ ਕਰੋ"</string>
@@ -1591,8 +1587,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"ਕੀ ਬ੍ਰਾਊਜ਼ਰ ਲਾਂਚ ਕਰਨਾ ਹੈ?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"ਕੀ ਕਾਲ ਸਵੀਕਾਰ ਕਰਨੀ ਹੈ?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"ਹਮੇਸ਼ਾਂ"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"ਹਮੇਸ਼ਾਂ ਖੁੱਲ੍ਹਾ \'ਤੇ ਸੈੱਟ ਕਰੋ"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"ਕੇਵਲ ਇੱਕ ਵਾਰ"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"ਸੈਟਿੰਗਾਂ"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index a61555b3f652..a90acface07c 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -574,7 +574,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Przesuń telefon w lewo."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Przesuń telefon w prawo."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Patrz prosto na urządzenie."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Nie widzę Twojej twarzy. Spójrz na telefon."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Ustaw twarz dokładnie na wprost telefonu."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Telefon się porusza. Trzymaj go nieruchomo."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Zarejestruj swoją twarz ponownie."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Nie można już rozpoznać twarzy. Spróbuj ponownie."</string>
@@ -1171,14 +1171,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Otwórz w aplikacji"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otwórz w aplikacji %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otwórz"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Otwieraj linki z: <xliff:g id="HOST">%1$s</xliff:g> w"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Otwieraj linki w"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Otwieraj linki w aplikacji <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Otwieraj linki z: <xliff:g id="HOST">%1$s</xliff:g> w aplikacji <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Udziel uprawnień"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Edytuj w aplikacji"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Edytuj w aplikacji %1$s"</string>
@@ -1636,8 +1632,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Uruchomić przeglądarkę?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Odebrać połączenie?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Zawsze"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Zawsze otwieraj"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Tylko raz"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ustawienia"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s nie obsługuje profilu do pracy"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 11c6a2880d1e..742fa81d0e25 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Mova o smartphone para a esquerda."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Mova o smartphone para a direita."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Olhe mais diretamente para o dispositivo."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Não é possível ver o rosto. Olhe para o telefone."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Deixe o rosto diretamente na frente do smartphone."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Muito movimento. Não mova o smartphone."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Registre seu rosto novamente."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"O rosto não é mais reconhecido. Tente novamente."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Abrir com"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir com %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Abrir links do domínio <xliff:g id="HOST">%1$s</xliff:g> com"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Abrir links com"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Abrir links com <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Abrir links do domínio <xliff:g id="HOST">%1$s</xliff:g> com <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Conceder acesso"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Editar com"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar com %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Abrir Navegador?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Aceitar chamada?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Definir como \"Sempre abrir\""</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Só uma vez"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configurações"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s não aceita perfis de trabalho"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index ed26c2d7c927..85fb7fddc5d8 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Mova o telemóvel para a esquerda."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Mova o telemóvel para a direita."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Olhe mais diretamente para o dispositivo."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Não consigo ver o rosto. Olhe para o telemóvel."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Posicione o rosto em frente ao telemóvel."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Demasiado movimento. Mantenha o telemóvel firme."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Volte a inscrever o rosto."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Impossível reconhecer o rosto. Tente novamente."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Abrir com"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir com %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Abra os links de <xliff:g id="HOST">%1$s</xliff:g> com:"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Abra os links com:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Abra os links com a aplicação <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Abra os links de <xliff:g id="HOST">%1$s</xliff:g> com a aplicação <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Conceder acesso"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Editar com"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar com %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Iniciar Navegador?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Aceitar chamada?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Definir como abrir sempre"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Apenas uma vez"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Definições"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s não suporta o perfil de trabalho"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 11c6a2880d1e..742fa81d0e25 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Mova o smartphone para a esquerda."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Mova o smartphone para a direita."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Olhe mais diretamente para o dispositivo."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Não é possível ver o rosto. Olhe para o telefone."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Deixe o rosto diretamente na frente do smartphone."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Muito movimento. Não mova o smartphone."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Registre seu rosto novamente."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"O rosto não é mais reconhecido. Tente novamente."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Abrir com"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Abrir com %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Abrir"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Abrir links do domínio <xliff:g id="HOST">%1$s</xliff:g> com"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Abrir links com"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Abrir links com <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Abrir links do domínio <xliff:g id="HOST">%1$s</xliff:g> com <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Conceder acesso"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Editar com"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editar com %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Abrir Navegador?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Aceitar chamada?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Sempre"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Definir como \"Sempre abrir\""</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Só uma vez"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Configurações"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s não aceita perfis de trabalho"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index edbc2a4a427a..2f464e93920a 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -571,7 +571,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Mutați telefonul spre stânga."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Mutați telefonul spre dreapta."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Priviți mai direct spre dispozitiv."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Nu vi se vede fața. Uitați-vă la telefon."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Stați cu capul direct în fața telefonului."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Prea multă mișcare. Țineți telefonul nemișcat."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Reînregistrați-vă chipul."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Nu se mai poate recunoaște fața. Încercați din nou."</string>
@@ -1151,14 +1151,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Deschideți cu"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Deschideți cu %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Deschideți"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Deschideți linkurile <xliff:g id="HOST">%1$s</xliff:g> cu"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Deschideți linkurile cu"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Deschideți linkurile cu <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Deschideți linkurile <xliff:g id="HOST">%1$s</xliff:g> cu <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Permiteți accesul"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Editați cu"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Editați cu %1$s"</string>
@@ -1613,8 +1609,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Lansați browserul?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Acceptați apelul?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Întotdeauna"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Schimbați la „Deschideți întotdeauna”"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Numai o dată"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Setări"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s nu acceptă profilul de serviciu"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index a7c5c7a68e62..c4b61b2f9216 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -574,7 +574,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Переместите телефон влево."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Переместите телефон вправо."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Смотрите прямо на устройство."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Вашего лица не видно. Смотрите на телефон."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Держите телефон прямо перед лицом."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Не перемещайте устройство. Держите его неподвижно."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Повторите попытку."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Не удалось распознать лицо. Повторите попытку."</string>
@@ -1171,14 +1171,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Открыть с помощью приложения:"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Открыть с помощью приложения \"%1$s\""</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Открыть"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Открывать ссылки вида <xliff:g id="HOST">%1$s</xliff:g> с помощью:"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Открывать ссылки с помощью:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Открывать ссылки в браузере <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Открывать ссылки вида <xliff:g id="HOST">%1$s</xliff:g> в браузере <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Открыть доступ"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Редактировать с помощью приложения:"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Редактировать с помощью приложения \"%1$s\""</string>
@@ -1636,8 +1632,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Запустить браузер?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Ответить?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Всегда"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Всегда открывать"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Только сейчас"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Настройки"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не поддерживает рабочие профили"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index c23728e66a5c..ddeb94ba9ec0 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"දුරකථනය වමට ගෙන යන්න."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"දුරකථනය දකුණට ගෙන යන්න."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"ඔබේ උපාංගය වෙත තවත් ඍජුව බලන්න."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"ඔබේ මුහුණ දැකිය නොහැක. දුරකථනය වෙත බලන්න."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"ඔබේ මුහුණ දුරකථනයට සෘජුවම ඉදිරියෙන් ස්ථානගත කරන්න."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"චලනය ඉතා වැඩියි. දුරකථනය ස්ථිරව අල්ලා සිටින්න."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"ඔබේ මුහුණ යළි ලියාපදිංචි කරන්න."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"තවදුරටත් මුහුණ හඳුනාගත නොහැක. නැවත උත්සාහ කරන්න."</string>
@@ -1133,14 +1133,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"සමඟ විවෘත කරන්න"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s සමඟ විවෘත කරන්න"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"විවෘත කරන්න"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"සමග <xliff:g id="HOST">%1$s</xliff:g> සබැඳි විවෘත කරන්න"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"සමඟ සබැඳි විවෘත කරන්න"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"<xliff:g id="APPLICATION">%1$s</xliff:g> සමඟ සබැඳි විවෘත කරන්න"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="APPLICATION">%2$s</xliff:g> සමග <xliff:g id="HOST">%1$s</xliff:g> සබැඳි විවෘත කරන්න"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ප්‍රවේශය දෙන්න"</string>
<string name="whichEditApplication" msgid="144727838241402655">"සමඟ සංස්කරණය කරන්න"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s සමඟ සංස්කරණය කරන්න"</string>
@@ -1592,8 +1588,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"බ්‍රවුසරය දියත් කරන්නද?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"ඇමතුම පිළිගන්නවාද?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"සැම විටම"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"සැම විට විවෘත ලෙස සකසන්න"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"එක් වාරයයි"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"සැකසීම්"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s කාර්යාල පැතිකඩ සඳහා සහාය ලබනොදේ."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 76b211aac953..4d19308c15e1 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -574,7 +574,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Posuňte telefón doľava."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Posuňte telefón doprava."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Pozrite sa priamejšie na zariadenie."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Nie je vidieť vašu tvár. Pozrite sa na telefón."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Umiestnite svoju tvár priamo pred telefón."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Priveľa pohybu. Nehýbte telefónom."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Znova zaregistrujte svoju tvár."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Tvár už nie je možné rozpoznať. Skúste to znova."</string>
@@ -1171,14 +1171,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Otvoriť v aplikácii"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Otvoriť v aplikácii %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Otvoriť"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Otvárajte odkazy z webu <xliff:g id="HOST">%1$s</xliff:g> v prehliadači alebo aplikácii"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Otvárajte odkazy v prehliadači"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Otvárajte odkazy v prehliadači <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Otvárajte odkazy z webu <xliff:g id="HOST">%1$s</xliff:g> v prehliadači <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Udeliť prístup"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Upraviť pomocou"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Upraviť v aplikácii %1$s"</string>
@@ -1636,8 +1632,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Spustiť prehliadač?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Prijať hovor?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Vždy"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Nastaviť na Vždy otvárať"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Len raz"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Nastavenia"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Spúšťač %1$s nepodporuje pracovné profily"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 943e9e260a89..b2b3109b2b60 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -574,7 +574,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Telefon premaknite v levo."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Telefon premaknite v desno."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Glejte bolj naravnost v napravo."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Obraz ni viden. Poglejte v telefon."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Obraz nastavite naravnost pred telefon."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Preveč se premikate. Držite telefon pri miru."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Znova prijavite svoj obraz."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Obraza ni več mogoče prepoznati. Poskusite znova."</string>
@@ -1171,14 +1171,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Odpiranje z aplikacijo"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Odpiranje z aplikacijo %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Odpiranje"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Odpiranje povezav <xliff:g id="HOST">%1$s</xliff:g> z"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Odpiranje povezav z"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Odpiranje povezav z aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Odpiranje povezav <xliff:g id="HOST">%1$s</xliff:g> z aplikacijo <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Omogoči dostop"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Urejanje z aplikacijo"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Urejanje z aplikacijo %1$s"</string>
@@ -1636,8 +1632,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Ali želite odpreti brskalnik?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Ali želite sprejeti klic?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Vedno"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Nastavi na »vedno odpri«"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Samo tokrat"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Nastavitve"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ne podpira delovnega profila"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 28f6062b16fb..afed336078a2 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Lëvize telefonin majtas."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Lëvize telefonin djathtas"</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Shiko më drejt në pajisjen tënde."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Fytyra jote nuk shfaqet. Shiko te telefoni."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Pozicionoje fytyrën tënde direkt përpara telefonit."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Ka shumë lëvizje. Mbaje telefonin të palëvizur."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Regjistroje përsëri fytyrën tënde."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Fytyra nuk mund të njihet më. Provo përsëri."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Hap me"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Hap me %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Hap"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Hapi lidhjet e <xliff:g id="HOST">%1$s</xliff:g> me"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Hapi lidhjet me"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Hapi lidhjet me <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Hapi lidhjet e <xliff:g id="HOST">%1$s</xliff:g> me <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Jep qasje"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Redakto me"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redakto me %1$s"</string>
@@ -1591,8 +1587,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Të hapet shfletuesi?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Dëshiron ta pranosh telefonatën?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Gjithmonë"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Caktoje si gjithmonë të hapur"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Vetëm një herë"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Cilësimet"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s nuk e mbështet profilin e punës"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 4fdf30145741..110b31d68b97 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -571,7 +571,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Померите телефон улево."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Померите телефон удесно."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Гледајте право у уређај."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Не види се лице. Гледајте у телефон."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Поставите лице директно испред телефона"</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Много се померате. Држите телефон мирно."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Поново региструјте лице."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Више не може да се препозна лице. Пробајте поново."</string>
@@ -1151,14 +1151,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Отворите помоћу"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Отворите помоћу апликације %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Отвори"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Отварајте <xliff:g id="HOST">%1$s</xliff:g> линкове помоћу"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Отваратеј линкове помоћу"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Отварајте линкове помоћу апликације <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Отварајте <xliff:g id="HOST">%1$s</xliff:g> линкове помоћу апликације <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Дозволи приступ"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Измените помоћу"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Измените помоћу апликације %1$s"</string>
@@ -1613,8 +1609,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Желите ли да покренете прегледач?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Желите ли да прихватите позив?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Увек"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Подеси на „увек отварај“"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Само једном"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Подешавања"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не подржава пословни профил"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index ff82a14db19c..bc1752e7135d 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Flytta mobilen åt vänster."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Flytta mobilen åt höger."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Titta rakt på enheten."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Ansiktet syns inte. Titta på mobilen."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Ha ansiktet direkt framför telefonen."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"För mycket rörelse. Håll mobilen stilla."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Registrera ansiktet på nytt."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Ansiktet kan inte längre kännas igen. Försök igen."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Öppna med"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Öppna med %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Öppna"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Öppna länkar på <xliff:g id="HOST">%1$s</xliff:g> med"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Öppna länkar med"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Öppna länkar med <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Öppna länkar på <xliff:g id="HOST">%1$s</xliff:g> med <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Ge åtkomst"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Redigera med"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Redigera med %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Vill du öppna webbläsaren?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Vill du ta emot samtal?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Alltid"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Ställ in på att alltid öppnas"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Bara en gång"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Inställningar"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s har inte stöd för arbetsprofil"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 528d5d7a159c..92510ea79f7f 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Sogeza simu upande wa kushoto."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Sogeza simu upande wa kulia."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Tafadhali angalia kifaa chako moja kwa moja."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Uso wako hauonekani. Angalia simu."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Weka uso wako moja kwa moja mbele ya simu."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Inatikisika sana. Ishike simu iwe thabiti."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Tafadhali sajili uso wako tena."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Haiwezi tena kutambua uso. Jaribu tena."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Fungua ukitumia"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Fungua ukitumia %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Fungua"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Fungua viungo vya <xliff:g id="HOST">%1$s</xliff:g> ukitumia"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Fungua viungo ukitumia"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Fungua viungo ukitumia <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Fungua viungo vya <xliff:g id="HOST">%1$s</xliff:g> ukitumia <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Idhinisha ufikiaji"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Badilisha kwa"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Badilisha kwa %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Zindua Kivinjari?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Kubali simu?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Kila mara"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Weka ifunguke kila wakati"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Mara moja tu"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Mipangilio"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s haitumii wasifu wa kazini"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 39cd685c4aee..8ddcfe6f5048 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"மொபைலை இடப்புறம் நகர்த்தவும்."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"மொபைலை வலப்புறம் நகர்த்தவும்."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"முழுமுகம் தெரியுமாறு நேராகப் பார்க்கவும்."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"முகம் சரியாகத் தெரியவில்லை. மொபைலைப் பார்க்கவும்."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"முகத்தை மொபைலுக்கு நேராக வைக்கவும்."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"அதிகமாக அசைகிறது. மொபைலை அசைக்காமல் பிடிக்கவும்."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"உங்கள் முகத்தை மீண்டும் பதிவுசெய்யுங்கள்."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"முகத்தைக் கண்டறிய இயலவில்லை. மீண்டும் முயலவும்."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"இதன்மூலம் திற"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s மூலம் திற"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"திற"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> இணைப்புகளை இதன் மூலம் திற:"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"இணைப்புகளை இதன் மூலம் திற:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"இணைப்புகளை <xliff:g id="APPLICATION">%1$s</xliff:g> ஆப்ஸில் திறத்தல்"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g> இணைப்புகளை <xliff:g id="APPLICATION">%2$s</xliff:g> ஆப்ஸில் திறத்தல்"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"அணுகலை வழங்கு"</string>
<string name="whichEditApplication" msgid="144727838241402655">"இதன் மூலம் திருத்து"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s மூலம் திருத்து"</string>
@@ -1591,8 +1587,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"உலாவியைத் துவக்கவா?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"அழைப்பை ஏற்கவா?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"எப்போதும்"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"எப்போதும் திறக்குமாறு அமைத்தல்"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"இப்போது மட்டும்"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"அமைப்புகள்"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s பணிக் கணக்கை ஆதரிக்காது"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 3ba794a60017..649e17c4229d 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"ఫోన్‌ను ఎడమవైపునకు జరపండి."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"ఫోన్‌ను కుడివైపునకు జరపండి."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"దయచేసి మీ పరికరం వైపు మరింత నేరుగా చూడండి."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"మీ ముఖం కనిపించడం లేదు. ఫోన్ వైపు చూడండి."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"మీ ముఖాన్ని ఫోన్‌కు ఎదురుగా ఉంచండి."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"బాగా కదుపుతున్నారు. ఫోన్‌ను స్థిరంగా పట్టుకోండి"</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"దయచేసి మీ ముఖాన్ని మళ్లీ నమోదు చేయండి."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"ఇక ముఖం గుర్తించలేదు. మళ్లీ ప్రయత్నించండి."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"దీనితో తెరువు"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$sతో తెరువు"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"తెరువు"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"దీనితో <xliff:g id="HOST">%1$s</xliff:g> లింక్‌లను తెరవండి"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"దీనితో లింక్‌లను తెరవండి"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"<xliff:g id="APPLICATION">%1$s</xliff:g>తో లింక్‌లను తెరవండి"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g> లింక్‌లను <xliff:g id="APPLICATION">%2$s</xliff:g>తో తెరవండి"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"యాక్సెస్ ఇవ్వండి"</string>
<string name="whichEditApplication" msgid="144727838241402655">"దీనితో సవరించు"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$sతో సవరించు"</string>
@@ -1591,8 +1587,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"బ్రౌజర్‌ను ప్రారంభించాలా?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"కాల్‌ను ఆమోదించాలా?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"ఎల్లప్పుడూ"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"ఎల్లప్పుడూ తెరవడానికి సెట్ చేయి"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"ఒకసారి మాత్రమే"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"సెట్టింగ్‌లు"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s కార్యాలయ ప్రొఫైల్‌కు మద్దతు ఇవ్వదు"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 437d89eaaa05..4e6943011d33 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"เลื่อนโทรศัพท์ไปทางซ้าย"</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"เลื่อนโทรศัพท์ไปทางขวา"</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"โปรดมองตรงมาที่อุปกรณ์"</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"ไม่เห็นหน้าเลย ลองมองที่โทรศัพท์"</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"หันหน้าให้ตรงกับโทรศัพท์"</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"มีการเคลื่อนไหวมากเกินไป ถือโทรศัพท์นิ่งๆ"</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"โปรดลงทะเบียนใบหน้าอีกครั้ง"</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"จำใบหน้าไม่ได้แล้ว ลองอีกครั้ง"</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"เปิดด้วย"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"เปิดด้วย %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"เปิด"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"เปิดลิงก์ <xliff:g id="HOST">%1$s</xliff:g> ด้วย"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"เปิดลิงก์ด้วย"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"เปิดลิงก์ด้วย <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"เปิดลิงก์ <xliff:g id="HOST">%1$s</xliff:g> ด้วย <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"ให้สิทธิ์"</string>
<string name="whichEditApplication" msgid="144727838241402655">"แก้ไขด้วย"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"แก้ไขด้วย %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"เปิดเบราว์เซอร์หรือไม่"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"รับสายหรือไม่"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"ทุกครั้ง"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"ตั้งค่าให้เปิดทุกครั้ง"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"เฉพาะครั้งนี้"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"การตั้งค่า"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ไม่สนับสนุนโปรไฟล์งาน"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 8469e7ba1d6e..68435284b9a5 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Igalaw ang telepono pakaliwa."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Igalaw ang telepono pakanan."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Tumingin nang mas direkta sa iyong device."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Hindi makita ang mukha mo. Tumingin sa telepono."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Itapat ang mukha mo sa mismong harap ng telepono."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Masyadong magalaw. Hawakang mabuti ang telepono."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Paki-enroll muli ang iyong mukha."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Hindi na makilala ang mukha. Subukang muli."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Buksan gamit ang"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Buksan gamit ang %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Buksan"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Buksan ang mga link ng <xliff:g id="HOST">%1$s</xliff:g> gamit ang"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Buksan ang mga link gamit ang"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Buksan ang mga link gamit ang <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Buksan ang mga link ng <xliff:g id="HOST">%1$s</xliff:g> gamit ang <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Bigyan ng access"</string>
<string name="whichEditApplication" msgid="144727838241402655">"I-edit gamit ang"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"I-edit gamit ang %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Ilunsad ang Browser?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Tanggapin ang tawag?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Palagi"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Itakda sa palaging buksan"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Isang beses lang"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Mga Setting"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"Hindi sinusuportahan ng %1$s ang profile sa trabaho"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 8a28a0d2b415..3592df9abe34 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Telefonu sola hareket ettirin."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Telefonu sağa hareket ettirin."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Lütfen cihazınıza daha doğrudan bakın."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Yüzünüz görülmüyor. Telefona bakın."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Yüzünüz telefonun tam karşısına gelmelidir."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Çok fazla hareket ediyorsunuz. Telefonu sabit tutun."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Lütfen yüzünüzü yeniden kaydedin."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Yüz artık tanınamıyor. Tekrar deneyin."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Şununla aç:"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s ile aç"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Aç"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> bağlantılarını şununla aç:"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Bağlantıları şununla aç:"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Bağlantıları <xliff:g id="APPLICATION">%1$s</xliff:g> ile aç"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g> bağlantılarını <xliff:g id="APPLICATION">%2$s</xliff:g> ile aç"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Erişim ver"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Şununla düzenle:"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"%1$s ile düzenle"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Tarayıcı Başlatılsın mı?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Çağrı kabul edilsin mi?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Her zaman"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Her zaman açılmak üzere ayarla"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Yalnızca bir defa"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Ayarlar"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s, iş profilini desteklemiyor"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index b02208fc47e0..347c81f3af42 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -574,7 +574,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Тримайте телефон лівіше."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Тримайте телефон правіше."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Дивіться просто на пристрій."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Обличчя не видно. Дивіться на телефон."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Тримайте телефон просто перед обличчям."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Забагато рухів. Тримайте телефон нерухомо."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Повторно проскануйте обличчя."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Розпізнати обличчя вже не вдається. Повторіть спробу."</string>
@@ -1171,14 +1171,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Відкрити за допомогою"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Відкрити за допомогою %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Відкрити"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Відкривати посилання <xliff:g id="HOST">%1$s</xliff:g> за допомогою"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Відкривати посилання за допомогою"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Відкривати посилання за допомогою додатка <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Відкривати посилання <xliff:g id="HOST">%1$s</xliff:g> за допомогою додатка <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Дозволити"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Редагувати за допомогою"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Редагувати за допомогою %1$s"</string>
@@ -1636,8 +1632,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Запустити веб-переглядач?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Прийняти виклик?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Завжди"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Вибрати додаток для відкривання посилань"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Лише цього разу"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Налаштування"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s не підтримує робочий профіль"</string>
@@ -2076,7 +2071,7 @@
<string name="notification_appops_overlay_active" msgid="633813008357934729">"показ поверх інших додатків на екрані"</string>
<string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"Сповіщення про послідовнсть дій"</string>
<string name="dynamic_mode_notification_title" msgid="508815255807182035">"Акумулятор може розрядитися раніше ніж зазвичай"</string>
- <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Режим економії заряду акумулятора активовано для збільшення часу його роботи"</string>
+ <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"Режим енергозбереження активовано для збільшення часу роботи акумулятора"</string>
<string name="battery_saver_notification_channel_name" msgid="2083316159716201806">"Режим енергозбереження"</string>
<string name="battery_saver_sticky_disabled_notification_title" msgid="6376147579378764641">"Режим енергозбереження не ввімкнеться, доки рівень заряду знову не знизиться"</string>
<string name="battery_saver_sticky_disabled_notification_summary" msgid="8090192609249817945">"Акумулятор заряджено достатньо. Режим енергозбереження буде знову ввімкнено, коли рівень заряду знизиться."</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 5adf84e0f2d9..3fd6fe757bbf 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"فون کو بائیں جانب لے جائيں۔"</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"فون کو دائیں جانب لے جائیں۔"</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"براہ کرم اپنے آلہ کی طرف چہرے کو سیدھا رکھیں۔"</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"آپ کا چہرہ دکھائی نہیں دے رہا۔ فون کی طرف دیکھیں۔"</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"اپنے چہرے کو براہ راست فون کے سامنے رکھیں۔"</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"کافی حرکت ہو رہی ہے۔ فون کو مضبوطی سے پکڑیں۔"</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"براہ کرم اپنے چہرے کو دوبارہ مندرج کریں۔"</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"اب چہرے کی شناخت نہیں کر سکتے۔ پھر آزمائيں۔"</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"اس کے ساتھ کھولیں"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"‏%1$s کے ساتھ کھولیں"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"کھولیں"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> لنکس کے ساتھ کھولیں"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"لنکس کے ساتھ کھولیں"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"<xliff:g id="APPLICATION">%1$s</xliff:g> کے ذریعے لنکس کھولیں"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g> لنکس کو <xliff:g id="APPLICATION">%2$s</xliff:g> کے ذریعے کھولیں"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"رسائی دیں"</string>
<string name="whichEditApplication" msgid="144727838241402655">"اس کے ساتھ ترمیم کریں"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"‏%1$s کے ساتھ ترمیم کریں"</string>
@@ -1591,8 +1587,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"براؤزر شروع کریں؟"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"کال قبول کریں؟"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"ہمیشہ"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"ہمیشہ کھلا ہوا ہونے پر سیٹ کریں"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"بس ایک مرتبہ"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"ترتیبات"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"‏%1$s دفتری پروفائل کا تعاون نہیں کرتا ہے"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 1452573b12e0..85ebe0035a49 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Telefonni chapga suring."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Telefonni oʻngga suring."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Qurilmaga tik qarang."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Yuzingiz koʻrinmayapti. Telefonga qarang."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Telefoningizga yuzingizni tik tuting."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Ortiqcha harakatlanmoqda. Qimirlatmasdan ushlang."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Yuzingizni qaytadan qayd qildiring."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Yuz tanilmadi. Qaytadan urining."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Ochish…"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"%1$s bilan ochish"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Ochish"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> havolalarini quyidagi orqali ochish"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Havolalarni quyidagi orqali ochish"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Havolalarni <xliff:g id="APPLICATION">%1$s</xliff:g> orqali ochish"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"<xliff:g id="HOST">%1$s</xliff:g> havolalarini <xliff:g id="APPLICATION">%2$s</xliff:g> orqali ochish"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Ruxsat berish"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Tahrirlash…"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"“%1$s” yordamida tahrirlash"</string>
@@ -1591,8 +1587,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Brauzer ishga tushirilsinmi?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Qo‘ng‘iroqni qabul qilasizmi?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Har doim"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Doim ochish"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Faqat hozir"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Sozlamalar"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"“%1$s” ishchi profilni qo‘llab-quvvatlamaydi"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index b27e38963589..f2eb9d4ecb51 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Đưa điện thoại sang bên trái."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Đưa điện thoại sang bên phải."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Vui lòng nhìn thẳng vào thiết bị."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Hệ thống không phát hiện được khuôn mặt bạn. Hãy nhìn vào điện thoại."</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Hướng thẳng khuôn mặt về phía trước điện thoại."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Thiết bị di chuyển quá nhiều. Giữ yên thiết bị."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Vui lòng đăng ký lại khuôn mặt của bạn."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Không nhận ra khuôn mặt. Hãy thử lại."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Mở bằng"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Mở bằng %1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Mở"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Mở đường dẫn liên kết <xliff:g id="HOST">%1$s</xliff:g> bằng"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Mở đường dẫn liên kết bằng"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Mở đường dẫn liên kết bằng <xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Mở đường dẫn liên kết <xliff:g id="HOST">%1$s</xliff:g> bằng <xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Cấp quyền truy cập"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Chỉnh sửa bằng"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Chỉnh sửa bằng %1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Chạy trình duyệt?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Chấp nhận cuộc gọi?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Luôn chọn"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Đặt thành luôn mở"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Chỉ một lần"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Cài đặt"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s không hỗ trợ hồ sơ công việc"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 162b8807bc41..1012337bc466 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"请将手机向左移动。"</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"请将手机向右移动。"</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"请直视您的设备。"</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"看不到您的脸部,请直视手机。"</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"请将你的面部正对手机。"</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"摄像头过于晃动。请将手机拿稳。"</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"请重新注册您的面孔。"</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"已无法识别人脸,请重试。"</string>
@@ -661,8 +661,8 @@
<string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"监控在解锁屏幕时输错密码的次数,并在输错次数过多时锁定平板电脑或清空此用户的所有数据。"</string>
<string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"监控在解锁屏幕时输错密码的次数,并在输错次数过多时锁定电视或清空此用户的所有数据。"</string>
<string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"监控在解锁屏幕时输错密码的次数,并在输错次数过多时锁定手机或清空此用户的所有数据。"</string>
- <string name="policylab_resetPassword" msgid="4934707632423915395">"更改锁屏密码"</string>
- <string name="policydesc_resetPassword" msgid="1278323891710619128">"更改锁屏密码。"</string>
+ <string name="policylab_resetPassword" msgid="4934707632423915395">"更改锁屏方式"</string>
+ <string name="policydesc_resetPassword" msgid="1278323891710619128">"更改锁屏方式。"</string>
<string name="policylab_forceLock" msgid="2274085384704248431">"锁定屏幕"</string>
<string name="policydesc_forceLock" msgid="1141797588403827138">"控制屏幕锁定的方式和时间。"</string>
<string name="policylab_wipeData" msgid="3910545446758639713">"清除所有数据"</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"打开方式"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"使用%1$s打开"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"打开"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"<xliff:g id="HOST">%1$s</xliff:g> 链接打开方式"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"链接打开方式"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"使用<xliff:g id="APPLICATION">%1$s</xliff:g>打开链接"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"使用<xliff:g id="APPLICATION">%2$s</xliff:g>打开 <xliff:g id="HOST">%1$s</xliff:g> 链接"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"授予访问权限"</string>
<string name="whichEditApplication" msgid="144727838241402655">"编辑方式"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"使用%1$s编辑"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"要启动浏览器吗?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"要接听电话吗?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"始终"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"设置为始终打开"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"仅此一次"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"设置"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s不支持工作资料"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index f4ec4d050f6b..9ac4582fca26 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"請將手機向左移。"</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"請將手機向右移。"</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"請以更直視的角度看著裝置。"</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"看不到您的臉。請看著手機。"</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"將手機對準您的臉孔正面。"</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"裝置不夠穩定。請拿穩手機。"</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"請重新註冊臉孔。"</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"無法再識別臉孔。請再試一次。"</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"選擇開啟方式"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"使用 %1$s 開啟"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"開啟"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"開啟 <xliff:g id="HOST">%1$s</xliff:g> 連結的方式"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"開啟連結的方式"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"使用 <xliff:g id="APPLICATION">%1$s</xliff:g> 開啟連結"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"使用 <xliff:g id="APPLICATION">%2$s</xliff:g> 開啟 <xliff:g id="HOST">%1$s</xliff:g> 連結"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"授予存取權"</string>
<string name="whichEditApplication" msgid="144727838241402655">"使用以下選擇器編輯:"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"使用 %1$s 編輯"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"要啟動「瀏覽器」嗎?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"接聽電話嗎?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"一律採用"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"設為一律開啟"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"只此一次"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"設定"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s 不支援公司檔案"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 547736a0d26c..580a1dc6b2b1 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"請將手機向左移動。"</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"請將手機向右移動。"</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"請儘可能直視裝置正面。"</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"無法偵測你的臉孔,請直視手機。"</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"將你的臉孔正對手機。"</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"鏡頭過度晃動,請拿穩手機。"</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"請重新註冊你的臉孔。"</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"已無法辨識臉孔,請再試一次。"</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"選擇開啟工具"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"透過 %1$s 開啟"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"開啟"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"開啟 <xliff:g id="HOST">%1$s</xliff:g> 連結時使用的瀏覽器/應用程式"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"開啟連結時使用的瀏覽器"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"使用「<xliff:g id="APPLICATION">%1$s</xliff:g>」開啟連結"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"使用「<xliff:g id="APPLICATION">%2$s</xliff:g>」開啟 <xliff:g id="HOST">%1$s</xliff:g> 連結"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"授予存取權"</string>
<string name="whichEditApplication" msgid="144727838241402655">"選擇編輯工具"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"使用 %1$s 編輯"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"啟動「瀏覽器」嗎?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"接聽電話嗎?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"一律採用"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"設為一律開啟"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"僅限一次"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"設定"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s 不支援工作設定檔"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index fa8eff327280..c4f8823b1714 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -568,7 +568,7 @@
<string name="face_acquired_too_right" msgid="3667075962661863218">"Hambisa ifoni ngakwesokunxele."</string>
<string name="face_acquired_too_left" msgid="3148242963894703424">"Hambisa ifoni ngakwesokudla."</string>
<string name="face_acquired_poor_gaze" msgid="5606479370806754905">"Sicela ubheke ngokuqondile kakhulu kudivayisi yakho."</string>
- <string name="face_acquired_not_detected" msgid="4885504661626728809">"Ayikwazi ukubona ubuso bakho. Bheka ifoni"</string>
+ <string name="face_acquired_not_detected" msgid="1879714205006680222">"Beka ubuso bakho ngqo phambi kwefoni."</string>
<string name="face_acquired_too_much_motion" msgid="3149332171102108851">"Ukunyakaza okuningi kakhulu. Bamba ifoni iqine."</string>
<string name="face_acquired_recalibrate" msgid="8077949502893707539">"Sicela uphinde ubhalise ubuso bakho."</string>
<string name="face_acquired_too_different" msgid="7663983770123789694">"Ayisakwazi ukubona ubuso. Zama futhi."</string>
@@ -1131,14 +1131,10 @@
<string name="whichViewApplication" msgid="3272778576700572102">"Vula nge-"</string>
<string name="whichViewApplicationNamed" msgid="2286418824011249620">"Vula nge-%1$s"</string>
<string name="whichViewApplicationLabel" msgid="2666774233008808473">"Kuvuliwe"</string>
- <!-- no translation found for whichOpenHostLinksWith (3788174881117226583) -->
- <skip />
- <!-- no translation found for whichOpenLinksWith (6392123355599572804) -->
- <skip />
- <!-- no translation found for whichOpenLinksWithApp (8225991685366651614) -->
- <skip />
- <!-- no translation found for whichOpenHostLinksWithApp (3464470639011045589) -->
- <skip />
+ <string name="whichOpenHostLinksWith" msgid="3788174881117226583">"Vula izixhumanisi ze-<xliff:g id="HOST">%1$s</xliff:g> nge"</string>
+ <string name="whichOpenLinksWith" msgid="6392123355599572804">"Vula izixhumanisi nge"</string>
+ <string name="whichOpenLinksWithApp" msgid="8225991685366651614">"Vula izixhumanisi nge-<xliff:g id="APPLICATION">%1$s</xliff:g>"</string>
+ <string name="whichOpenHostLinksWithApp" msgid="3464470639011045589">"Vula izixhumanisi ze-<xliff:g id="HOST">%1$s</xliff:g> nge-<xliff:g id="APPLICATION">%2$s</xliff:g>"</string>
<string name="whichGiveAccessToApplicationLabel" msgid="6142688895536868827">"Nikeza ukufinyel"</string>
<string name="whichEditApplication" msgid="144727838241402655">"Hlela nge-"</string>
<string name="whichEditApplicationNamed" msgid="1775815530156447790">"Hlela nge-%1$s"</string>
@@ -1590,8 +1586,7 @@
<string name="launchBrowserDefault" msgid="2057951947297614725">"Qala Isiphequluli?"</string>
<string name="SetupCallDefault" msgid="5834948469253758575">"Amukela ucingo?"</string>
<string name="activity_resolver_use_always" msgid="8017770747801494933">"Njalo"</string>
- <!-- no translation found for activity_resolver_set_always (1422574191056490585) -->
- <skip />
+ <string name="activity_resolver_set_always" msgid="1422574191056490585">"Setha ukuthi kuhlale kuvuliwe"</string>
<string name="activity_resolver_use_once" msgid="2404644797149173758">"Kanye nje"</string>
<string name="activity_resolver_app_settings" msgid="8965806928986509855">"Izilungiselelo"</string>
<string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s ayisekeli iphrofayela yomsebenzi"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f515b2dd45f0..bc7e3b7e9058 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4210,6 +4210,14 @@
one bar higher than they actually are -->
<bool name="config_inflateSignalStrength">false</bool>
+ <!-- Trigger a warning for notifications with RemoteView objects that are larger in bytes than
+ this value (default 1MB)-->
+ <integer name="config_notificationWarnRemoteViewSizeBytes">1000000</integer>
+
+ <!-- Strip notification RemoteView objects that are larger in bytes than this value (also log)
+ (default 2MB) -->
+ <integer name="config_notificationStripRemoteViewSizeBytes">2000000</integer>
+
<!-- Sharesheet: define a max number of targets per application for new shortcuts-based direct share introduced in Q -->
<integer name="config_maxShortcutTargetsPerApp">3</integer>
@@ -4217,4 +4225,8 @@
the default implementation of ACTION_FACTORY_RESET does not work, so it is needed to re-route
this intent to this package. This is being used in MasterClearReceiver.java. -->
<string name="config_factoryResetPackage" translatable="false"></string>
+
+ <!-- The list of packages to automatically opt out of refresh rates higher than 60hz because
+ of known compatibility issues. -->
+ <string-array name="config_highRefreshRateBlacklist"></string-array>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 5363ef920886..039bc4d925a1 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -90,6 +90,24 @@
orientation. If zero, the value of rounded_corner_radius is used. -->
<dimen name="rounded_corner_radius_bottom">0dp</dimen>
+ <!-- Default adjustment for the software rounded corners since corners are not perfectly
+ round. This value is used when retrieving the "radius" of the rounded corner in cases
+ where the exact bezier curve cannot be retrieved. This value will be subtracted from
+ rounded_corner_radius to more accurately provide a "radius" for the rounded corner. -->
+ <dimen name="rounded_corner_radius_adjustment">0px</dimen>
+ <!-- Top adjustment for the software rounded corners since corners are not perfectly
+ round. This value is used when retrieving the "radius" of the top rounded corner in cases
+ where the exact bezier curve cannot be retrieved. This value will be subtracted from
+ rounded_corner_radius_top to more accurately provide a "radius" for the top rounded corners.
+ -->
+ <dimen name="rounded_corner_radius_top_adjustment">0px</dimen>
+ <!-- Bottom adjustment for the software rounded corners since corners are not perfectly
+ round. This value is used when retrieving the "radius" of the bottom rounded corner in
+ cases where the exact bezier curve cannot be retrieved. This value will be subtracted from
+ rounded_corner_radius_bottom to more accurately provide a "radius" for the bottom rounded
+ corners. -->
+ <dimen name="rounded_corner_radius_bottom_adjustment">0px</dimen>
+
<!-- Width of the window of the divider bar used to resize docked stacks. -->
<dimen name="docked_stack_divider_thickness">48dp</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6fd855c8f702..913001c0eb94 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1541,7 +1541,7 @@
<!-- Message shown during face acquisition when the user is not front facing the sensor [CHAR LIMIT=50] -->
<string name="face_acquired_poor_gaze">Please look more directly at your device.</string>
<!-- Message shown during face acquisition when the user is not detected [CHAR LIMIT=50] -->
- <string name="face_acquired_not_detected">Can\u2019t see your face. Look at the phone.</string>
+ <string name="face_acquired_not_detected">Position your face directly in front of the phone.</string>
<!-- Message shown during face acquisition when the device is not steady [CHAR LIMIT=50] -->
<string name="face_acquired_too_much_motion">Too much motion. Hold phone steady.</string>
<!-- Message shown during face acquisition when the sensor needs to be recalibrated [CHAR LIMIT=50] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6c908aac1ee8..b3b1b9fc01f2 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3708,6 +3708,9 @@
<java-symbol type="dimen" name="rounded_corner_radius" />
<java-symbol type="dimen" name="rounded_corner_radius_top" />
<java-symbol type="dimen" name="rounded_corner_radius_bottom" />
+ <java-symbol type="dimen" name="rounded_corner_radius_adjustment" />
+ <java-symbol type="dimen" name="rounded_corner_radius_top_adjustment" />
+ <java-symbol type="dimen" name="rounded_corner_radius_bottom_adjustment" />
<java-symbol type="bool" name="config_supportsRoundedCornersOnWindows" />
<java-symbol type="string" name="config_defaultModuleMetadataProvider" />
@@ -3823,5 +3826,14 @@
<java-symbol type="string" name="config_defaultSupervisionProfileOwnerComponent" />
<java-symbol type="bool" name="config_inflateSignalStrength" />
+
+ <java-symbol type="drawable" name="android_logotype" />
+ <java-symbol type="layout" name="platlogo_layout" />
+
+ <java-symbol type="integer" name="config_notificationWarnRemoteViewSizeBytes" />
+ <java-symbol type="integer" name="config_notificationStripRemoteViewSizeBytes" />
+
<java-symbol type="string" name="config_factoryResetPackage" />
+ <java-symbol type="array" name="config_highRefreshRateBlacklist" />
+
</resources>
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index 711eaa7edc2a..c50cbe3773ab 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -19,6 +19,8 @@ package android.app.activity;
import static android.content.Intent.ACTION_EDIT;
import static android.content.Intent.ACTION_VIEW;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
@@ -31,6 +33,7 @@ import android.app.servertransaction.ActivityConfigurationChangeItem;
import android.app.servertransaction.ActivityRelaunchItem;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.ClientTransactionItem;
+import android.app.servertransaction.NewIntentItem;
import android.app.servertransaction.ResumeActivityItem;
import android.app.servertransaction.StopActivityItem;
import android.content.Intent;
@@ -45,9 +48,13 @@ import androidx.test.filters.MediumTest;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.content.ReferrerIntent;
+
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.CountDownLatch;
/**
@@ -307,6 +314,24 @@ public class ActivityThreadTest {
assertEquals(400, activity.mConfig.smallestScreenWidthDp);
}
+ @Test
+ public void testResumeAfterNewIntent() {
+ final Activity activity = mActivityTestRule.launchActivity(new Intent());
+ final ActivityThread activityThread = activity.getActivityThread();
+ final ArrayList<ReferrerIntent> rIntents = new ArrayList<>();
+ rIntents.add(new ReferrerIntent(new Intent(), "android.app.activity"));
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ activityThread.executeTransaction(newNewIntentTransaction(activity, rIntents, false));
+ });
+ assertThat(activity.isResumed()).isFalse();
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ activityThread.executeTransaction(newNewIntentTransaction(activity, rIntents, true));
+ });
+ assertThat(activity.isResumed()).isTrue();
+ }
+
/**
* Calls {@link ActivityThread#handleActivityConfigurationChanged(IBinder, Configuration, int)}
* to try to push activity configuration to the activity for the given sequence number.
@@ -386,6 +411,16 @@ public class ActivityThreadTest {
return transaction;
}
+ private static ClientTransaction newNewIntentTransaction(Activity activity,
+ List<ReferrerIntent> intents, boolean resume) {
+ final NewIntentItem item = NewIntentItem.obtain(intents, resume);
+
+ final ClientTransaction transaction = newTransaction(activity);
+ transaction.addCallback(item);
+
+ return transaction;
+ }
+
private static ClientTransaction newTransaction(Activity activity) {
final IApplicationThread appThread = activity.getActivityThread().getApplicationThread();
return ClientTransaction.obtain(appThread, activity.getActivityToken());
diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
index 1e49c0a7f55d..37d21f0928be 100644
--- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java
@@ -214,15 +214,15 @@ public class ObjectPoolTests {
@Test
public void testRecycleNewIntentItem() {
- NewIntentItem emptyItem = NewIntentItem.obtain(null);
- NewIntentItem item = NewIntentItem.obtain(referrerIntentList());
+ NewIntentItem emptyItem = NewIntentItem.obtain(null, false);
+ NewIntentItem item = NewIntentItem.obtain(referrerIntentList(), false);
assertNotSame(item, emptyItem);
assertFalse(item.equals(emptyItem));
item.recycle();
assertEquals(item, emptyItem);
- NewIntentItem item2 = NewIntentItem.obtain(referrerIntentList());
+ NewIntentItem item2 = NewIntentItem.obtain(referrerIntentList(), false);
assertSame(item, item2);
assertFalse(item2.equals(emptyItem));
}
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 36ed88fbe8d5..d2b18cb0bcb8 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -128,7 +128,7 @@ public class TransactionParcelTests {
@Test
public void testNewIntent() {
// Write to parcel
- NewIntentItem item = NewIntentItem.obtain(referrerIntentList());
+ NewIntentItem item = NewIntentItem.obtain(referrerIntentList(), false);
writeAndPrepareForReading(item);
// Read from parcel and assert
diff --git a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
index 1ca879cde6c8..49849ee72a18 100644
--- a/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
+++ b/core/tests/coretests/src/android/content/pm/dex/DexMetadataHelperTest.java
@@ -36,12 +36,12 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.frameworks.coretests.R;
-import libcore.testing.io.TestIoUtils;
-
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import java.io.File;
@@ -60,21 +60,14 @@ public class DexMetadataHelperTest {
private static final String APK_FILE_EXTENSION = ".apk";
private static final String DEX_METADATA_FILE_EXTENSION = ".dm";
+ @Rule
+ public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+
private File mTmpDir = null;
@Before
- public void setUp() {
- mTmpDir = TestIoUtils.createTemporaryDirectory("DexMetadataHelperTest");
- }
-
- @After
- public void tearDown() {
- if (mTmpDir != null) {
- File[] files = mTmpDir.listFiles();
- for (File f : files) {
- f.delete();
- }
- }
+ public void setUp() throws IOException {
+ mTmpDir = mTemporaryFolder.newFolder("DexMetadataHelperTest");
}
private File createDexMetadataFile(String apkFileName) throws IOException {
diff --git a/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java b/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java
index d5163e193510..eff4826040f4 100644
--- a/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java
+++ b/core/tests/coretests/src/android/os/RedactingFileDescriptorTest.java
@@ -64,7 +64,7 @@ public class RedactingFileDescriptorTest {
@Test
public void testSingleByte() throws Exception {
final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_ONLY,
- new long[] { 10, 11 }).getFileDescriptor();
+ new long[] { 10, 11 }, new long[] {}).getFileDescriptor();
final byte[] buf = new byte[1_000];
assertEquals(buf.length, Os.read(fd, buf, 0, buf.length));
@@ -80,7 +80,7 @@ public class RedactingFileDescriptorTest {
@Test
public void testRanges() throws Exception {
final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_ONLY,
- new long[] { 100, 200, 300, 400 }).getFileDescriptor();
+ new long[] { 100, 200, 300, 400 }, new long[] {}).getFileDescriptor();
final byte[] buf = new byte[10];
assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 90));
@@ -102,7 +102,7 @@ public class RedactingFileDescriptorTest {
@Test
public void testEntireFile() throws Exception {
final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_ONLY,
- new long[] { 0, 5_000_000 }).getFileDescriptor();
+ new long[] { 0, 5_000_000 }, new long[] {}).getFileDescriptor();
try (FileInputStream in = new FileInputStream(fd)) {
int val;
@@ -115,7 +115,7 @@ public class RedactingFileDescriptorTest {
@Test
public void testReadWrite() throws Exception {
final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE,
- new long[] { 100, 200, 300, 400 }).getFileDescriptor();
+ new long[] { 100, 200, 300, 400 }, new long[] {}).getFileDescriptor();
// Redacted at first
final byte[] buf = new byte[10];
@@ -168,4 +168,76 @@ public class RedactingFileDescriptorTest {
assertArrayEquals(new long[] { 100, 200 },
removeRange(new long[] { 100, 200 }, 150, 150));
}
+
+ @Test
+ public void testFreeAtStart() throws Exception {
+ final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE,
+ new long[] { 1, 10 }, new long[] {1}).getFileDescriptor();
+
+ final byte[] buf = new byte[10];
+ assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0));
+ assertArrayEquals(
+ new byte[] { 64, (byte) 'f', (byte) 'r', (byte) 'e', (byte) 'e', 0, 0, 0, 0, 0 },
+ buf);
+ }
+
+ @Test
+ public void testFreeAtOffset() throws Exception {
+ final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE,
+ new long[] { 1, 10 }, new long[] {3}).getFileDescriptor();
+
+ final byte[] buf = new byte[10];
+ assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0));
+ assertArrayEquals(
+ new byte[] { 64, 0, 0, (byte) 'f', (byte) 'r', (byte) 'e', (byte) 'e', 0, 0, 0 },
+ buf);
+ }
+
+ @Test
+ public void testFreeAcrossRedactionStart() throws Exception {
+ final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE,
+ new long[] { 1, 10 }, new long[] {0}).getFileDescriptor();
+
+ final byte[] buf = new byte[10];
+ assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0));
+ assertArrayEquals(
+ new byte[] { 64, (byte) 'r', (byte) 'e', (byte) 'e', 0, 0, 0, 0, 0, 0 },
+ buf);
+ }
+
+ @Test
+ public void testFreeAcrossRedactionEnd() throws Exception {
+ final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE,
+ new long[] { 1, 3 }, new long[] {2}).getFileDescriptor();
+
+ final byte[] buf = new byte[10];
+ assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0));
+ assertArrayEquals(
+ new byte[] { 64, 0, (byte) 'f', 64, 64, 64, 64, 64, 64, 64 },
+ buf);
+ }
+
+ @Test
+ public void testFreeOutsideRedaction() throws Exception {
+ final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE,
+ new long[] { 1, 8 }, new long[] { 8 }).getFileDescriptor();
+
+ final byte[] buf = new byte[10];
+ assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0));
+ assertArrayEquals(
+ new byte[] { 64, 0, 0, 0, 0, 0, 0, 0, 64, 64 },
+ buf);
+ }
+
+ @Test
+ public void testFreeMultipleRedactions() throws Exception {
+ final FileDescriptor fd = RedactingFileDescriptor.open(mContext, mFile, MODE_READ_WRITE,
+ new long[] { 1, 2, 3, 4 }, new long[] { 0 }).getFileDescriptor();
+
+ final byte[] buf = new byte[10];
+ assertEquals(buf.length, Os.pread(fd, buf, 0, 10, 0));
+ assertArrayEquals(
+ new byte[] { 64, (byte) 'r', 64, (byte) 'e', 64, 64, 64, 64, 64, 64 },
+ buf);
+ }
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/logging/SmartSelectionEventTrackerTest.java b/core/tests/coretests/src/android/view/textclassifier/logging/SmartSelectionEventTrackerTest.java
new file mode 100644
index 000000000000..321a7f21c307
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textclassifier/logging/SmartSelectionEventTrackerTest.java
@@ -0,0 +1,43 @@
+/*
+ * 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.view.textclassifier.logging;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.google.common.truth.Truth;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SmartSelectionEventTrackerTest {
+
+ @Test
+ public void getVersionInfo_valid() {
+ String signature = "a|702|b";
+ String versionInfo = SmartSelectionEventTracker.SelectionEvent.getVersionInfo(signature);
+ Truth.assertThat(versionInfo).isEqualTo("702");
+ }
+
+ @Test
+ public void getVersionInfo_invalid() {
+ String signature = "|702";
+ String versionInfo = SmartSelectionEventTracker.SelectionEvent.getVersionInfo(signature);
+ Truth.assertThat(versionInfo).isEmpty();
+ }
+}
diff --git a/data/etc/hiddenapi-package-whitelist.xml b/data/etc/hiddenapi-package-whitelist.xml
index e24f26c16310..054f68ba9e5c 100644
--- a/data/etc/hiddenapi-package-whitelist.xml
+++ b/data/etc/hiddenapi-package-whitelist.xml
@@ -17,8 +17,12 @@
<!--
This XML file declares which system apps should be exempted from the hidden API blacklisting, i.e.
-which apps should be allowed to access the entire private API. Only apps NOT signed with the
-platform cert need to be included, as apps signed with the platform cert are exempted by default.
+which apps should be allowed to access the entire private API.
+
+Only apps NOT signed with the platform cert need to be included, as apps signed with the platform
+cert are exempted by default.
+
+Do NOT include any apps that are updatable via Play Store!
-->
<config>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 54c548a7b174..89e26daed82a 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -269,6 +269,8 @@ applications that come with the platform
<permission name="android.permission.INSTALL_PACKAGES"/>
<!-- Needed for test only -->
<permission name="android.permission.INTERACT_ACROSS_PROFILES"/>
+ <!-- Permission required to test onPermissionsChangedListener -->
+ <permission name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"/>
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.LOCAL_MAC_ADDRESS"/>
<permission name="android.permission.MANAGE_ACCESSIBILITY"/>
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 646aa13664c4..ee8cc40622f8 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -584,7 +584,7 @@ public class KeyStore {
}
KeyCharacteristics characteristics = result.getKeyCharacteristics();
if (characteristics == null) {
- Log.e(TAG, "generateKeyInternal got empty key cheractariestics " + error);
+ Log.e(TAG, "generateKeyInternal got empty key characteristics " + error);
return SYSTEM_ERROR;
}
outCharacteristics.shallowCopyFrom(characteristics);
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index bfead1a70fab..0d837f2c7fed 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -165,6 +165,9 @@ cc_defaults {
"pipeline/skia/SkiaRecordingCanvas.cpp",
"pipeline/skia/RenderNodeDrawable.cpp",
"pipeline/skia/ReorderBarrierDrawables.cpp",
+ "renderthread/Frame.cpp",
+ "renderthread/RenderTask.cpp",
+ "renderthread/TimeLord.cpp",
"hwui/AnimatedImageDrawable.cpp",
"hwui/AnimatedImageThread.cpp",
"hwui/Bitmap.cpp",
@@ -192,6 +195,7 @@ cc_defaults {
"RecordingCanvas.cpp",
"RenderNode.cpp",
"RenderProperties.cpp",
+ "RootRenderNode.cpp",
"SkiaCanvas.cpp",
"VectorDrawable.cpp",
],
@@ -226,10 +230,7 @@ cc_defaults {
"renderthread/VulkanManager.cpp",
"renderthread/VulkanSurface.cpp",
"renderthread/RenderProxy.cpp",
- "renderthread/RenderTask.cpp",
"renderthread/RenderThread.cpp",
- "renderthread/TimeLord.cpp",
- "renderthread/Frame.cpp",
"service/GraphicsStatsService.cpp",
"surfacetexture/EGLConsumer.cpp",
"surfacetexture/ImageConsumer.cpp",
@@ -250,7 +251,6 @@ cc_defaults {
"ProfileData.cpp",
"ProfileDataContainer.cpp",
"Readback.cpp",
- "RootRenderNode.cpp",
"TreeInfo.cpp",
"WebViewFunctorManager.cpp",
"protos/graphicsstats.proto",
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index 93b9decd9cbc..74cf1fda1b75 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -155,11 +155,9 @@ void BaseRenderNodeAnimator::pushStaging(AnimationContext& context) {
RenderNode* oldTarget = mTarget;
mTarget = mStagingTarget;
mStagingTarget = nullptr;
-#ifdef __ANDROID__ // Layoutlib does not support RenderNode
if (oldTarget && oldTarget != mTarget) {
oldTarget->onAnimatorTargetChanged(this);
}
-#endif
}
if (!mHasStartValue) {
diff --git a/libs/hwui/RootRenderNode.cpp b/libs/hwui/RootRenderNode.cpp
index d8c1b57e2ef4..ddbbf58b3071 100644
--- a/libs/hwui/RootRenderNode.cpp
+++ b/libs/hwui/RootRenderNode.cpp
@@ -16,8 +16,13 @@
#include "RootRenderNode.h"
+#ifdef __ANDROID__ // Layoutlib does not support Looper (windows)
+#include <utils/Looper.h>
+#endif
+
namespace android::uirenderer {
+#ifdef __ANDROID__ // Layoutlib does not support Looper
class FinishAndInvokeListener : public MessageHandler {
public:
explicit FinishAndInvokeListener(PropertyValuesAnimatorSet* anim) : mAnimator(anim) {
@@ -280,5 +285,22 @@ private:
AnimationContext* ContextFactoryImpl::createAnimationContext(renderthread::TimeLord& clock) {
return new AnimationContextBridge(clock, mRootNode);
}
+#else
+
+void RootRenderNode::prepareTree(TreeInfo& info) {
+ info.errorHandler = mErrorHandler.get();
+ info.updateWindowPositions = true;
+ RenderNode::prepareTree(info);
+ info.updateWindowPositions = false;
+ info.errorHandler = nullptr;
+}
+
+void RootRenderNode::attachAnimatingNode(RenderNode* animatingNode) { }
+
+void RootRenderNode::destroy() { }
+
+void RootRenderNode::addVectorDrawableAnimator(PropertyValuesAnimatorSet* anim) { }
+
+#endif
} // namespace android::uirenderer
diff --git a/libs/hwui/RootRenderNode.h b/libs/hwui/RootRenderNode.h
index ea10921be20b..12de4ecac94b 100644
--- a/libs/hwui/RootRenderNode.h
+++ b/libs/hwui/RootRenderNode.h
@@ -16,13 +16,12 @@
#pragma once
-#include <utils/Looper.h>
-
#include <set>
#include <vector>
#include "AnimationContext.h"
#include "Animator.h"
+#include <IContextFactory.h>
#include "PropertyValuesAnimatorSet.h"
#include "RenderNode.h"
@@ -75,6 +74,7 @@ private:
void detachVectorDrawableAnimator(PropertyValuesAnimatorSet* anim);
};
+#ifdef __ANDROID__ // Layoutlib does not support Animations
class ANDROID_API ContextFactoryImpl : public IContextFactory {
public:
ANDROID_API explicit ContextFactoryImpl(RootRenderNode* rootNode) : mRootNode(rootNode) {}
@@ -85,5 +85,6 @@ public:
private:
RootRenderNode* mRootNode;
};
+#endif
} // namespace android::uirenderer
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index ff29a5b9e352..84c0d1369e83 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -19,14 +19,17 @@
#include <SkImageEncoder.h>
#include <SkImageInfo.h>
#include <SkImagePriv.h>
+#include <SkMultiPictureDocument.h>
#include <SkOverdrawCanvas.h>
#include <SkOverdrawColorFilter.h>
#include <SkPicture.h>
#include <SkPictureRecorder.h>
+#include <SkSerialProcs.h>
#include "LightingInfo.h"
#include "TreeInfo.h"
#include "VectorDrawable.h"
#include "thread/CommonPool.h"
+#include "tools/SkSharingProc.h"
#include "utils/TraceUtils.h"
#include <unistd.h>
@@ -99,7 +102,7 @@ void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque)
SkASSERT(layerNode->getLayerSurface());
SkiaDisplayList* displayList = (SkiaDisplayList*)layerNode->getDisplayList();
if (!displayList || displayList->isEmpty()) {
- SkDEBUGF(("%p drawLayers(%s) : missing drawable", layerNode, layerNode->getName()));
+ ALOGE("%p drawLayers(%s) : missing drawable", layerNode, layerNode->getName());
return;
}
@@ -233,58 +236,138 @@ static void savePictureAsync(const sk_sp<SkData>& data, const std::string& filen
if (stream.isValid()) {
stream.write(data->data(), data->size());
stream.flush();
- SkDebugf("SKP Captured Drawing Output (%d bytes) for frame. %s", stream.bytesWritten(),
+ ALOGD("SKP Captured Drawing Output (%zu bytes) for frame. %s", stream.bytesWritten(),
filename.c_str());
}
});
}
-SkCanvas* SkiaPipeline::tryCapture(SkSurface* surface) {
- if (CC_UNLIKELY(Properties::skpCaptureEnabled)) {
+// Note multiple SkiaPipeline instances may be loaded if more than one app is visible.
+// Each instance may observe the filename changing and try to record to a file of the same name.
+// Only the first one will succeed. There is no scope available here where we could coordinate
+// to cause this function to return true for only one of the instances.
+bool SkiaPipeline::shouldStartNewFileCapture() {
+ // Don't start a new file based capture if one is currently ongoing.
+ if (mCaptureMode != CaptureMode::None) { return false; }
+
+ // A new capture is started when the filename property changes.
+ // Read the filename property.
+ std::string prop = base::GetProperty(PROPERTY_CAPTURE_SKP_FILENAME, "0");
+ // if the filename property changed to a valid value
+ if (prop[0] != '0' && mCapturedFile != prop) {
+ // remember this new filename
+ mCapturedFile = prop;
+ // and get a property indicating how many frames to capture.
+ mCaptureSequence = base::GetIntProperty(PROPERTY_CAPTURE_SKP_FRAMES, 1);
if (mCaptureSequence <= 0) {
- std::string prop = base::GetProperty(PROPERTY_CAPTURE_SKP_FILENAME, "0");
- if (prop[0] != '0' && mCapturedFile != prop) {
- mCapturedFile = prop;
- mCaptureSequence = base::GetIntProperty(PROPERTY_CAPTURE_SKP_FRAMES, 1);
- }
+ return false;
+ } else if (mCaptureSequence == 1) {
+ mCaptureMode = CaptureMode::SingleFrameSKP;
+ } else {
+ mCaptureMode = CaptureMode::MultiFrameSKP;
}
- if (mCaptureSequence > 0 || mPictureCapturedCallback) {
- mRecorder.reset(new SkPictureRecorder());
- SkCanvas* pictureCanvas =
- mRecorder->beginRecording(surface->width(), surface->height(), nullptr,
- SkPictureRecorder::kPlaybackDrawPicture_RecordFlag);
- mNwayCanvas = std::make_unique<SkNWayCanvas>(surface->width(), surface->height());
- mNwayCanvas->addCanvas(surface->getCanvas());
- mNwayCanvas->addCanvas(pictureCanvas);
- return mNwayCanvas.get();
+ return true;
+ }
+ return false;
+}
+
+// performs the first-frame work of a multi frame SKP capture. Returns true if successful.
+bool SkiaPipeline::setupMultiFrameCapture() {
+ ALOGD("Set up multi-frame capture, frames = %d", mCaptureSequence);
+ // We own this stream and need to hold it until close() finishes.
+ auto stream = std::make_unique<SkFILEWStream>(mCapturedFile.c_str());
+ if (stream->isValid()) {
+ mOpenMultiPicStream = std::move(stream);
+ mSerialContext.reset(new SkSharingSerialContext());
+ SkSerialProcs procs;
+ procs.fImageProc = SkSharingSerialContext::serializeImage;
+ procs.fImageCtx = mSerialContext.get();
+ // SkDocuments don't take owership of the streams they write.
+ // we need to keep it until after mMultiPic.close()
+ // procs is passed as a pointer, but just as a method of having an optional default.
+ // procs doesn't need to outlive this Make call.
+ mMultiPic = SkMakeMultiPictureDocument(mOpenMultiPicStream.get(), &procs);
+ return true;
+ } else {
+ ALOGE("Could not open \"%s\" for writing.", mCapturedFile.c_str());
+ mCaptureSequence = 0;
+ mCaptureMode = CaptureMode::None;
+ return false;
+ }
+}
+
+SkCanvas* SkiaPipeline::tryCapture(SkSurface* surface) {
+ if (CC_LIKELY(!Properties::skpCaptureEnabled)) {
+ return surface->getCanvas(); // Bail out early when capture is not turned on.
+ }
+ // Note that shouldStartNewFileCapture tells us if this is the *first* frame of a capture.
+ if (shouldStartNewFileCapture() && mCaptureMode == CaptureMode::MultiFrameSKP) {
+ if (!setupMultiFrameCapture()) {
+ return surface->getCanvas();
}
}
- return surface->getCanvas();
+
+ // Create a canvas pointer, fill it depending on what kind of capture is requested (if any)
+ SkCanvas* pictureCanvas = nullptr;
+ switch (mCaptureMode) {
+ case CaptureMode::CallbackAPI:
+ case CaptureMode::SingleFrameSKP:
+ mRecorder.reset(new SkPictureRecorder());
+ pictureCanvas = mRecorder->beginRecording(surface->width(), surface->height(),
+ nullptr, SkPictureRecorder::kPlaybackDrawPicture_RecordFlag);
+ break;
+ case CaptureMode::MultiFrameSKP:
+ // If a multi frame recording is active, initialize recording for a single frame of a
+ // multi frame file.
+ pictureCanvas = mMultiPic->beginPage(surface->width(), surface->height());
+ break;
+ case CaptureMode::None:
+ // Returning here in the non-capture case means we can count on pictureCanvas being
+ // non-null below.
+ return surface->getCanvas();
+ }
+
+ // Setting up an nway canvas is common to any kind of capture.
+ mNwayCanvas = std::make_unique<SkNWayCanvas>(surface->width(), surface->height());
+ mNwayCanvas->addCanvas(surface->getCanvas());
+ mNwayCanvas->addCanvas(pictureCanvas);
+ return mNwayCanvas.get();
}
void SkiaPipeline::endCapture(SkSurface* surface) {
+ if (CC_LIKELY(mCaptureMode == CaptureMode::None)) { return; }
mNwayCanvas.reset();
- if (CC_UNLIKELY(mRecorder.get())) {
- ATRACE_CALL();
+ ATRACE_CALL();
+ if (mCaptureSequence > 0 && mCaptureMode == CaptureMode::MultiFrameSKP) {
+ mMultiPic->endPage();
+ mCaptureSequence--;
+ if (mCaptureSequence == 0) {
+ mCaptureMode = CaptureMode::None;
+ // Pass mMultiPic and mOpenMultiPicStream to a background thread, which will handle
+ // the heavyweight serialization work and destroy them. mOpenMultiPicStream is released
+ // to a bare pointer because keeping it in a smart pointer makes the lambda
+ // non-copyable. The lambda is only called once, so this is safe.
+ SkFILEWStream* stream = mOpenMultiPicStream.release();
+ CommonPool::post([doc = std::move(mMultiPic), stream]{
+ ALOGD("Finalizing multi frame SKP");
+ doc->close();
+ delete stream;
+ ALOGD("Multi frame SKP complete.");
+ });
+ }
+ } else {
sk_sp<SkPicture> picture = mRecorder->finishRecordingAsPicture();
if (picture->approximateOpCount() > 0) {
- if (mCaptureSequence > 0) {
- ATRACE_BEGIN("picture->serialize");
- auto data = picture->serialize();
- ATRACE_END();
-
- // offload saving to file in a different thread
- if (1 == mCaptureSequence) {
- savePictureAsync(data, mCapturedFile);
- } else {
- savePictureAsync(data, mCapturedFile + "_" + std::to_string(mCaptureSequence));
- }
- mCaptureSequence--;
- }
if (mPictureCapturedCallback) {
std::invoke(mPictureCapturedCallback, std::move(picture));
+ } else {
+ // single frame skp to file
+ auto data = picture->serialize();
+ savePictureAsync(data, mCapturedFile);
+ mCaptureSequence = 0;
}
}
+ mCaptureMode = CaptureMode::None;
mRecorder.reset();
}
}
@@ -305,7 +388,6 @@ void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& cli
// initialize the canvas for the current frame, that might be a recording canvas if SKP
// capture is enabled.
- std::unique_ptr<SkPictureRecorder> recorder;
SkCanvas* canvas = tryCapture(surface.get());
renderFrameImpl(layers, clip, nodes, opaque, contentDrawBounds, canvas, preTransform);
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 5fc1d6169d4a..37b559f92f05 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -17,12 +17,15 @@
#pragma once
#include <SkSurface.h>
+#include <SkDocument.h>
+#include <SkMultiPictureDocument.h>
#include "Lighting.h"
#include "hwui/AnimatedImageDrawable.h"
#include "renderthread/CanvasContext.h"
#include "renderthread/IRenderPipeline.h"
class SkPictureRecorder;
+struct SkSharingSerialContext;
namespace android {
namespace uirenderer {
@@ -60,9 +63,12 @@ public:
void renderLayersImpl(const LayerUpdateQueue& layers, bool opaque);
+ // Sets the recording callback to the provided function and the recording mode
+ // to CallbackAPI
void setPictureCapturedCallback(
const std::function<void(sk_sp<SkPicture>&&)>& callback) override {
mPictureCapturedCallback = callback;
+ mCaptureMode = callback ? CaptureMode::CallbackAPI : CaptureMode::None;
}
protected:
@@ -92,8 +98,18 @@ private:
*/
void renderVectorDrawableCache();
+ // Called every frame. Normally returns early with screen canvas.
+ // But when capture is enabled, returns an nwaycanvas where commands are also recorded.
SkCanvas* tryCapture(SkSurface* surface);
+ // Called at the end of every frame, closes the recording if necessary.
void endCapture(SkSurface* surface);
+ // Determine if a new file-based capture should be started.
+ // If so, sets mCapturedFile and mCaptureSequence and returns true.
+ // Should be called every frame when capture is enabled.
+ // sets mCaptureMode.
+ bool shouldStartNewFileCapture();
+ // Set up a multi frame capture.
+ bool setupMultiFrameCapture();
std::vector<sk_sp<SkImage>> mPinnedImages;
@@ -103,22 +119,46 @@ private:
std::vector<VectorDrawableRoot*> mVectorDrawables;
// Block of properties used only for debugging to record a SkPicture and save it in a file.
+ // There are three possible ways of recording drawing commands.
+ enum class CaptureMode {
+ // return to this mode when capture stops.
+ None,
+ // A mode where every frame is recorded into an SkPicture and sent to a provided callback,
+ // until that callback is cleared
+ CallbackAPI,
+ // A mode where a finite number of frames are recorded to a file with
+ // SkMultiPictureDocument
+ MultiFrameSKP,
+ // A mode which records a single frame to a normal SKP file.
+ SingleFrameSKP,
+ };
+ CaptureMode mCaptureMode = CaptureMode::None;
+
/**
- * mCapturedFile is used to enforce we don't capture more than once for a given name (cause
- * permissions don't allow to reset a property from render thread).
+ * mCapturedFile - the filename to write a recorded SKP to in either MultiFrameSKP or
+ * SingleFrameSKP mode.
*/
std::string mCapturedFile;
/**
- * mCaptureSequence counts how many frames are left to take in the sequence.
+ * mCaptureSequence counts down how many frames are left to take in the sequence. Applicable
+ * only to MultiFrameSKP or SingleFrameSKP mode.
*/
int mCaptureSequence = 0;
+ // Multi frame serialization stream and writer used when serializing more than one frame.
+ std::unique_ptr<SkFILEWStream> mOpenMultiPicStream;
+ sk_sp<SkDocument> mMultiPic;
+ std::unique_ptr<SkSharingSerialContext> mSerialContext;
+
/**
- * mRecorder holds the current picture recorder. We could store it on the stack to support
- * parallel tryCapture calls (not really needed).
+ * mRecorder holds the current picture recorder when serializing in either SingleFrameSKP or
+ * CallbackAPI modes.
*/
std::unique_ptr<SkPictureRecorder> mRecorder;
std::unique_ptr<SkNWayCanvas> mNwayCanvas;
+
+ // Set by setPictureCapturedCallback and when set, CallbackAPI mode recording is ongoing.
+ // Not used in other recording modes.
std::function<void(sk_sp<SkPicture>&&)> mPictureCapturedCallback;
};
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 3dd1d4462d02..e50428b2ee62 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -30,8 +30,6 @@
#include "utils/TimeUtils.h"
#include "utils/TraceUtils.h"
-#include <ui/GraphicBuffer.h>
-
namespace android {
namespace uirenderer {
namespace renderthread {
diff --git a/libs/hwui/tests/scripts/skp-capture.sh b/libs/hwui/tests/scripts/skp-capture.sh
index 54fa22929586..aad31fcc8eb9 100755
--- a/libs/hwui/tests/scripts/skp-capture.sh
+++ b/libs/hwui/tests/scripts/skp-capture.sh
@@ -4,6 +4,12 @@
#
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+#
+# Before this can be used, the device must be rooted and the filesystem must be writable by Skia
+# - These steps are necessary once after flashing to enable capture -
+# adb root
+# adb remount
+# adb reboot
if [ -z "$1" ]; then
printf 'Usage:\n skp-capture.sh PACKAGE_NAME OPTIONAL_FRAME_COUNT\n\n'
@@ -20,8 +26,8 @@ if ! command -v adb > /dev/null 2>&1; then
exit 2
fi
fi
-phase1_timeout_seconds=15
-phase2_timeout_seconds=60
+phase1_timeout_seconds=60
+phase2_timeout_seconds=300
package="$1"
filename="$(date '+%H%M%S').skp"
remote_path="/data/data/${package}/cache/${filename}"
@@ -29,11 +35,14 @@ local_path_prefix="$(date '+%Y-%m-%d_%H%M%S')_${package}"
local_path="${local_path_prefix}.skp"
enable_capture_key='debug.hwui.capture_skp_enabled'
enable_capture_value=$(adb shell "getprop '${enable_capture_key}'")
-#printf 'captureflag=' "$enable_capture_value" '\n'
+
+# TODO(nifong): check if filesystem is writable here with "avbctl get-verity"
+# result will either start with "verity is disabled" or "verity is enabled"
+
if [ -z "$enable_capture_value" ]; then
- printf 'Capture SKP property need to be enabled first. Please use\n'
- printf "\"adb shell setprop debug.hwui.capture_skp_enabled true\" and then restart\n"
- printf "the process.\n\n"
+ printf 'debug.hwui.capture_skp_enabled was found to be disabled, enabling it now.\n'
+ printf " restart the process you want to capture on the device, then retry this script.\n\n"
+ adb shell "setprop '${enable_capture_key}' true"
exit 1
fi
if [ ! -z "$2" ]; then
@@ -57,12 +66,18 @@ banner() {
printf ' %s' "$*"
printf '\n=====================\n'
}
-banner '...WAITING...'
-adb_test_exist() {
- test '0' = "$(adb shell "test -e \"$1\"; echo \$?")";
+banner '...WAITING FOR APP INTERACTION...'
+# Waiting for nonzero file is an indication that the pipeline has both opened the file and written
+# the header. With multiple frames this does not occur until the last frame has been recorded,
+# so we continue to show the "waiting for app interaction" message as long as the app still requires
+# interaction to draw more frames.
+adb_test_file_nonzero() {
+ # grab first byte of `du` output
+ X="$(adb shell "du \"$1\" 2> /dev/null | dd bs=1 count=1 2> /dev/null")"
+ test "$X" && test "$X" -ne 0
}
timeout=$(( $(date +%s) + $phase1_timeout_seconds))
-while ! adb_test_exist "$remote_path"; do
+while ! adb_test_file_nonzero "$remote_path"; do
spin 0.05
if [ $(date +%s) -gt $timeout ] ; then
printf '\bTimed out.\n'
@@ -72,20 +87,27 @@ while ! adb_test_exist "$remote_path"; do
done
printf '\b'
-#read -n1 -r -p "Press any key to continue..." key
+# Disable further capturing
+adb shell "setprop '${filename_key}' ''"
banner '...SAVING...'
-adb_test_file_nonzero() {
- # grab first byte of `du` output
- X="$(adb shell "du \"$1\" 2> /dev/null | dd bs=1 count=1 2> /dev/null")"
- test "$X" && test "$X" -ne 0
+# return the size of a file in bytes
+adb_filesize() {
+ adb shell "wc -c \"$1\"" 2> /dev/null | awk '{print $1}'
}
-#adb_filesize() {
-# adb shell "wc -c \"$1\"" 2> /dev/null | awk '{print $1}'
-#}
timeout=$(( $(date +%s) + $phase2_timeout_seconds))
-while ! adb_test_file_nonzero "$remote_path"; do
+last_size='0' # output of last size check command
+unstable=true # false once the file size stops changing
+counter=0 # used to perform size check only 1/sec though we update spinner 20/sec
+# loop until the file size is unchanged for 1 second.
+while [ $unstable != 0 ] ; do
spin 0.05
+ counter=$(( $counter+1 ))
+ if ! (( $counter % 20)) ; then
+ new_size=$(adb_filesize "$remote_path")
+ unstable=$(($(adb_filesize "$remote_path") != last_size))
+ last_size=$new_size
+ fi
if [ $(date +%s) -gt $timeout ] ; then
printf '\bTimed out.\n'
adb shell "setprop '${filename_key}' ''"
@@ -94,7 +116,7 @@ while ! adb_test_file_nonzero "$remote_path"; do
done
printf '\b'
-adb shell "setprop '${filename_key}' ''"
+printf "SKP file serialized: %s\n" $(echo $last_size | numfmt --to=iec)
i=0; while [ $i -lt 10 ]; do spin 0.10; i=$(($i + 1)); done; echo
@@ -105,12 +127,4 @@ if ! [ -f "$local_path" ] ; then
fi
adb shell rm "$remote_path"
printf '\nSKP saved to file:\n %s\n\n' "$local_path"
-if [ ! -z "$2" ]; then
- bridge="_"
- adb shell "setprop 'debug.hwui.capture_skp_frames' ''"
- for i in $(seq 2 $2); do
- adb pull "${remote_path}_${i}" "${local_path_prefix}_${i}.skp"
- adb shell rm "${remote_path}_${i}"
- done
-fi
diff --git a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
index 78239714ca3b..274e0e4c2b65 100644
--- a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
+++ b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
@@ -40,127 +40,116 @@ import java.util.Arrays;
*/
public class GnssMetrics {
- private static final String TAG = GnssMetrics.class.getSimpleName();
+ private static final String TAG = GnssMetrics.class.getSimpleName();
- /* Constant which indicates GPS signal quality is as yet unknown */
- public static final int GPS_SIGNAL_QUALITY_UNKNOWN =
- ServerLocationProtoEnums.GPS_SIGNAL_QUALITY_UNKNOWN; // -1
+ /* Constant which indicates GPS signal quality is as yet unknown */
+ private static final int GPS_SIGNAL_QUALITY_UNKNOWN =
+ ServerLocationProtoEnums.GPS_SIGNAL_QUALITY_UNKNOWN; // -1
- /* Constant which indicates GPS signal quality is poor */
- public static final int GPS_SIGNAL_QUALITY_POOR =
- ServerLocationProtoEnums.GPS_SIGNAL_QUALITY_POOR; // 0
+ /* Constant which indicates GPS signal quality is poor */
+ private static final int GPS_SIGNAL_QUALITY_POOR =
+ ServerLocationProtoEnums.GPS_SIGNAL_QUALITY_POOR; // 0
- /* Constant which indicates GPS signal quality is good */
- public static final int GPS_SIGNAL_QUALITY_GOOD =
- ServerLocationProtoEnums.GPS_SIGNAL_QUALITY_GOOD; // 1
+ /* Constant which indicates GPS signal quality is good */
+ private static final int GPS_SIGNAL_QUALITY_GOOD =
+ ServerLocationProtoEnums.GPS_SIGNAL_QUALITY_GOOD; // 1
- /* Number of GPS signal quality levels */
- public static final int NUM_GPS_SIGNAL_QUALITY_LEVELS = GPS_SIGNAL_QUALITY_GOOD + 1;
+ /* Number of GPS signal quality levels */
+ public static final int NUM_GPS_SIGNAL_QUALITY_LEVELS = GPS_SIGNAL_QUALITY_GOOD + 1;
- /** Default time between location fixes (in millisecs) */
- private static final int DEFAULT_TIME_BETWEEN_FIXES_MILLISECS = 1000;
+ /** Default time between location fixes (in millisecs) */
+ private static final int DEFAULT_TIME_BETWEEN_FIXES_MILLISECS = 1000;
- /* The time since boot when logging started */
- private String logStartInElapsedRealTime;
+ /* The time since boot when logging started */
+ private String mLogStartInElapsedRealTime;
- /* GNSS power metrics */
- private GnssPowerMetrics mGnssPowerMetrics;
+ /* GNSS power metrics */
+ private GnssPowerMetrics mGnssPowerMetrics;
- /**
- * A boolean array indicating whether the constellation types have been used in fix.
- */
+ /* A boolean array indicating whether the constellation types have been used in fix. */
private boolean[] mConstellationTypes;
-
- /** Constructor */
- public GnssMetrics(IBatteryStats stats) {
- mGnssPowerMetrics = new GnssPowerMetrics(stats);
- locationFailureStatistics = new Statistics();
- timeToFirstFixSecStatistics = new Statistics();
- positionAccuracyMeterStatistics = new Statistics();
- topFourAverageCn0Statistics = new Statistics();
- reset();
- }
-
- /**
- * Logs the status of a location report received from the HAL
- *
- * @param isSuccessful
- */
- public void logReceivedLocationStatus(boolean isSuccessful) {
- if (!isSuccessful) {
- locationFailureStatistics.addItem(1.0);
- return;
+ /** Location failure statistics */
+ private Statistics mLocationFailureStatistics;
+ /** Time to first fix statistics */
+ private Statistics mTimeToFirstFixSecStatistics;
+ /** Position accuracy statistics */
+ private Statistics mPositionAccuracyMeterStatistics;
+ /** Top 4 average CN0 statistics */
+ private Statistics mTopFourAverageCn0Statistics;
+
+ public GnssMetrics(IBatteryStats stats) {
+ mGnssPowerMetrics = new GnssPowerMetrics(stats);
+ mLocationFailureStatistics = new Statistics();
+ mTimeToFirstFixSecStatistics = new Statistics();
+ mPositionAccuracyMeterStatistics = new Statistics();
+ mTopFourAverageCn0Statistics = new Statistics();
+ reset();
}
- locationFailureStatistics.addItem(0.0);
- return;
- }
-
- /**
- * Logs missed reports
- *
- * @param desiredTimeBetweenFixesMilliSeconds
- * @param actualTimeBetweenFixesMilliSeconds
- */
- public void logMissedReports(int desiredTimeBetweenFixesMilliSeconds,
- int actualTimeBetweenFixesMilliSeconds) {
- int numReportMissed = (actualTimeBetweenFixesMilliSeconds /
- Math.max(DEFAULT_TIME_BETWEEN_FIXES_MILLISECS, desiredTimeBetweenFixesMilliSeconds)) - 1;
- if (numReportMissed > 0) {
- for (int i = 0; i < numReportMissed; i++) {
- locationFailureStatistics.addItem(1.0);
- }
+
+ /**
+ * Logs the status of a location report received from the HAL
+ */
+ public void logReceivedLocationStatus(boolean isSuccessful) {
+ if (!isSuccessful) {
+ mLocationFailureStatistics.addItem(1.0);
+ return;
+ }
+ mLocationFailureStatistics.addItem(0.0);
}
- return;
- }
-
- /**
- * Logs time to first fix
- *
- * @param timeToFirstFixMilliSeconds
- */
- public void logTimeToFirstFixMilliSecs(int timeToFirstFixMilliSeconds) {
- timeToFirstFixSecStatistics.addItem((double) (timeToFirstFixMilliSeconds/1000));
- return;
- }
-
- /**
- * Logs position accuracy
- *
- * @param positionAccuracyMeters
- */
- public void logPositionAccuracyMeters(float positionAccuracyMeters) {
- positionAccuracyMeterStatistics.addItem((double) positionAccuracyMeters);
- return;
- }
-
- /*
- * Logs CN0 when at least 4 SVs are available
- *
- */
- public void logCn0(float[] cn0s, int numSv) {
- if (numSv == 0 || cn0s == null || cn0s.length == 0 || cn0s.length < numSv) {
- if (numSv == 0) {
- mGnssPowerMetrics.reportSignalQuality(null, 0);
- }
- return;
+
+ /**
+ * Logs missed reports
+ */
+ public void logMissedReports(int desiredTimeBetweenFixesMilliSeconds,
+ int actualTimeBetweenFixesMilliSeconds) {
+ int numReportMissed = (actualTimeBetweenFixesMilliSeconds / Math.max(
+ DEFAULT_TIME_BETWEEN_FIXES_MILLISECS, desiredTimeBetweenFixesMilliSeconds)) - 1;
+ if (numReportMissed > 0) {
+ for (int i = 0; i < numReportMissed; i++) {
+ mLocationFailureStatistics.addItem(1.0);
+ }
+ }
}
- float[] cn0Array = Arrays.copyOf(cn0s, numSv);
- Arrays.sort(cn0Array);
- mGnssPowerMetrics.reportSignalQuality(cn0Array, numSv);
- if (numSv < 4) {
- return;
+
+ /**
+ * Logs time to first fix
+ */
+ public void logTimeToFirstFixMilliSecs(int timeToFirstFixMilliSeconds) {
+ mTimeToFirstFixSecStatistics.addItem((double) (timeToFirstFixMilliSeconds / 1000));
}
- if (cn0Array[numSv - 4] > 0.0) {
- double top4AvgCn0 = 0.0;
- for (int i = numSv - 4; i < numSv; i++) {
- top4AvgCn0 += (double) cn0Array[i];
- }
- top4AvgCn0 /= 4;
- topFourAverageCn0Statistics.addItem(top4AvgCn0);
+
+ /**
+ * Logs position accuracy
+ */
+ public void logPositionAccuracyMeters(float positionAccuracyMeters) {
+ mPositionAccuracyMeterStatistics.addItem((double) positionAccuracyMeters);
}
- return;
- }
+ /**
+ * Logs CN0 when at least 4 SVs are available
+ */
+ public void logCn0(float[] cn0s, int numSv) {
+ if (numSv == 0 || cn0s == null || cn0s.length == 0 || cn0s.length < numSv) {
+ if (numSv == 0) {
+ mGnssPowerMetrics.reportSignalQuality(null, 0);
+ }
+ return;
+ }
+ float[] cn0Array = Arrays.copyOf(cn0s, numSv);
+ Arrays.sort(cn0Array);
+ mGnssPowerMetrics.reportSignalQuality(cn0Array, numSv);
+ if (numSv < 4) {
+ return;
+ }
+ if (cn0Array[numSv - 4] > 0.0) {
+ double top4AvgCn0 = 0.0;
+ for (int i = numSv - 4; i < numSv; i++) {
+ top4AvgCn0 += (double) cn0Array[i];
+ }
+ top4AvgCn0 /= 4;
+ mTopFourAverageCn0Statistics.addItem(top4AvgCn0);
+ }
+ }
/**
* Logs that a constellation type has been observed.
@@ -173,82 +162,82 @@ public class GnssMetrics {
mConstellationTypes[constellationType] = true;
}
- /**
- * Dumps GNSS metrics as a proto string
- * @return
- */
- public String dumpGnssMetricsAsProtoString() {
- GnssLog msg = new GnssLog();
- if (locationFailureStatistics.getCount() > 0) {
- msg.numLocationReportProcessed = locationFailureStatistics.getCount();
- msg.percentageLocationFailure = (int) (100.0 * locationFailureStatistics.getMean());
- }
- if (timeToFirstFixSecStatistics.getCount() > 0) {
- msg.numTimeToFirstFixProcessed = timeToFirstFixSecStatistics.getCount();
- msg.meanTimeToFirstFixSecs = (int) timeToFirstFixSecStatistics.getMean();
- msg.standardDeviationTimeToFirstFixSecs
- = (int) timeToFirstFixSecStatistics.getStandardDeviation();
- }
- if (positionAccuracyMeterStatistics.getCount() > 0) {
- msg.numPositionAccuracyProcessed = positionAccuracyMeterStatistics.getCount();
- msg.meanPositionAccuracyMeters = (int) positionAccuracyMeterStatistics.getMean();
- msg.standardDeviationPositionAccuracyMeters
- = (int) positionAccuracyMeterStatistics.getStandardDeviation();
- }
- if (topFourAverageCn0Statistics.getCount() > 0) {
- msg.numTopFourAverageCn0Processed = topFourAverageCn0Statistics.getCount();
- msg.meanTopFourAverageCn0DbHz = topFourAverageCn0Statistics.getMean();
- msg.standardDeviationTopFourAverageCn0DbHz
- = topFourAverageCn0Statistics.getStandardDeviation();
- }
- msg.powerMetrics = mGnssPowerMetrics.buildProto();
- msg.hardwareRevision = SystemProperties.get("ro.boot.revision", "");
- String s = Base64.encodeToString(GnssLog.toByteArray(msg), Base64.DEFAULT);
- reset();
- return s;
- }
-
- /**
- * Dumps GNSS Metrics as text
- *
- * @return GNSS Metrics
- */
- public String dumpGnssMetricsAsText() {
- StringBuilder s = new StringBuilder();
- s.append("GNSS_KPI_START").append('\n');
- s.append(" KPI logging start time: ").append(logStartInElapsedRealTime).append("\n");
- s.append(" KPI logging end time: ");
- TimeUtils.formatDuration(SystemClock.elapsedRealtimeNanos() / 1000000L, s);
- s.append("\n");
- s.append(" Number of location reports: ").append(
- locationFailureStatistics.getCount()).append("\n");
- if (locationFailureStatistics.getCount() > 0) {
- s.append(" Percentage location failure: ").append(
- 100.0 * locationFailureStatistics.getMean()).append("\n");
- }
- s.append(" Number of TTFF reports: ").append(
- timeToFirstFixSecStatistics.getCount()).append("\n");
- if (timeToFirstFixSecStatistics.getCount() > 0) {
- s.append(" TTFF mean (sec): ").append(timeToFirstFixSecStatistics.getMean()).append("\n");
- s.append(" TTFF standard deviation (sec): ").append(
- timeToFirstFixSecStatistics.getStandardDeviation()).append("\n");
- }
- s.append(" Number of position accuracy reports: ").append(
- positionAccuracyMeterStatistics.getCount()).append("\n");
- if (positionAccuracyMeterStatistics.getCount() > 0) {
- s.append(" Position accuracy mean (m): ").append(
- positionAccuracyMeterStatistics.getMean()).append("\n");
- s.append(" Position accuracy standard deviation (m): ").append(
- positionAccuracyMeterStatistics.getStandardDeviation()).append("\n");
- }
- s.append(" Number of CN0 reports: ").append(
- topFourAverageCn0Statistics.getCount()).append("\n");
- if (topFourAverageCn0Statistics.getCount() > 0) {
- s.append(" Top 4 Avg CN0 mean (dB-Hz): ").append(
- topFourAverageCn0Statistics.getMean()).append("\n");
- s.append(" Top 4 Avg CN0 standard deviation (dB-Hz): ").append(
- topFourAverageCn0Statistics.getStandardDeviation()).append("\n");
+ /**
+ * Dumps GNSS metrics as a proto string
+ */
+ public String dumpGnssMetricsAsProtoString() {
+ GnssLog msg = new GnssLog();
+ if (mLocationFailureStatistics.getCount() > 0) {
+ msg.numLocationReportProcessed = mLocationFailureStatistics.getCount();
+ msg.percentageLocationFailure = (int) (100.0 * mLocationFailureStatistics.getMean());
+ }
+ if (mTimeToFirstFixSecStatistics.getCount() > 0) {
+ msg.numTimeToFirstFixProcessed = mTimeToFirstFixSecStatistics.getCount();
+ msg.meanTimeToFirstFixSecs = (int) mTimeToFirstFixSecStatistics.getMean();
+ msg.standardDeviationTimeToFirstFixSecs =
+ (int) mTimeToFirstFixSecStatistics.getStandardDeviation();
+ }
+ if (mPositionAccuracyMeterStatistics.getCount() > 0) {
+ msg.numPositionAccuracyProcessed = mPositionAccuracyMeterStatistics.getCount();
+ msg.meanPositionAccuracyMeters = (int) mPositionAccuracyMeterStatistics.getMean();
+ msg.standardDeviationPositionAccuracyMeters =
+ (int) mPositionAccuracyMeterStatistics.getStandardDeviation();
+ }
+ if (mTopFourAverageCn0Statistics.getCount() > 0) {
+ msg.numTopFourAverageCn0Processed = mTopFourAverageCn0Statistics.getCount();
+ msg.meanTopFourAverageCn0DbHz = mTopFourAverageCn0Statistics.getMean();
+ msg.standardDeviationTopFourAverageCn0DbHz =
+ mTopFourAverageCn0Statistics.getStandardDeviation();
+ }
+ msg.powerMetrics = mGnssPowerMetrics.buildProto();
+ msg.hardwareRevision = SystemProperties.get("ro.boot.revision", "");
+ String s = Base64.encodeToString(GnssLog.toByteArray(msg), Base64.DEFAULT);
+ reset();
+ return s;
}
+
+ /**
+ * Dumps GNSS Metrics as text
+ *
+ * @return GNSS Metrics
+ */
+ public String dumpGnssMetricsAsText() {
+ StringBuilder s = new StringBuilder();
+ s.append("GNSS_KPI_START").append('\n');
+ s.append(" KPI logging start time: ").append(mLogStartInElapsedRealTime).append("\n");
+ s.append(" KPI logging end time: ");
+ TimeUtils.formatDuration(SystemClock.elapsedRealtimeNanos() / 1000000L, s);
+ s.append("\n");
+ s.append(" Number of location reports: ").append(
+ mLocationFailureStatistics.getCount()).append("\n");
+ if (mLocationFailureStatistics.getCount() > 0) {
+ s.append(" Percentage location failure: ").append(
+ 100.0 * mLocationFailureStatistics.getMean()).append("\n");
+ }
+ s.append(" Number of TTFF reports: ").append(
+ mTimeToFirstFixSecStatistics.getCount()).append("\n");
+ if (mTimeToFirstFixSecStatistics.getCount() > 0) {
+ s.append(" TTFF mean (sec): ").append(mTimeToFirstFixSecStatistics.getMean()).append(
+ "\n");
+ s.append(" TTFF standard deviation (sec): ").append(
+ mTimeToFirstFixSecStatistics.getStandardDeviation()).append("\n");
+ }
+ s.append(" Number of position accuracy reports: ").append(
+ mPositionAccuracyMeterStatistics.getCount()).append("\n");
+ if (mPositionAccuracyMeterStatistics.getCount() > 0) {
+ s.append(" Position accuracy mean (m): ").append(
+ mPositionAccuracyMeterStatistics.getMean()).append("\n");
+ s.append(" Position accuracy standard deviation (m): ").append(
+ mPositionAccuracyMeterStatistics.getStandardDeviation()).append("\n");
+ }
+ s.append(" Number of CN0 reports: ").append(
+ mTopFourAverageCn0Statistics.getCount()).append("\n");
+ if (mTopFourAverageCn0Statistics.getCount() > 0) {
+ s.append(" Top 4 Avg CN0 mean (dB-Hz): ").append(
+ mTopFourAverageCn0Statistics.getMean()).append("\n");
+ s.append(" Top 4 Avg CN0 standard deviation (dB-Hz): ").append(
+ mTopFourAverageCn0Statistics.getStandardDeviation()).append("\n");
+ }
s.append(" Used-in-fix constellation types: ");
for (int i = 0; i < mConstellationTypes.length; i++) {
if (mConstellationTypes[i]) {
@@ -256,199 +245,193 @@ public class GnssMetrics {
}
}
s.append("\n");
- s.append("GNSS_KPI_END").append("\n");
- GpsBatteryStats stats = mGnssPowerMetrics.getGpsBatteryStats();
- if (stats != null) {
- s.append("Power Metrics").append("\n");
- s.append(" Time on battery (min): "
- + stats.getLoggingDurationMs() / ((double) DateUtils.MINUTE_IN_MILLIS)).append("\n");
- long[] t = stats.getTimeInGpsSignalQualityLevel();
- if (t != null && t.length == NUM_GPS_SIGNAL_QUALITY_LEVELS) {
- s.append(" Amount of time (while on battery) Top 4 Avg CN0 > " +
- Double.toString(GnssPowerMetrics.POOR_TOP_FOUR_AVG_CN0_THRESHOLD_DB_HZ) +
- " dB-Hz (min): ").append(t[1] / ((double) DateUtils.MINUTE_IN_MILLIS)).append("\n");
- s.append(" Amount of time (while on battery) Top 4 Avg CN0 <= " +
- Double.toString(GnssPowerMetrics.POOR_TOP_FOUR_AVG_CN0_THRESHOLD_DB_HZ) +
- " dB-Hz (min): ").append(t[0] / ((double) DateUtils.MINUTE_IN_MILLIS)).append("\n");
- }
- s.append(" Energy consumed while on battery (mAh): ").append(
- stats.getEnergyConsumedMaMs() / ((double) DateUtils.HOUR_IN_MILLIS)).append("\n");
- }
- s.append("Hardware Version: " + SystemProperties.get("ro.boot.revision", "")).append("\n");
- return s.toString();
- }
-
- /** Class for storing statistics */
- private class Statistics {
-
- /** Resets statistics */
- public void reset() {
- count = 0;
- sum = 0.0;
- sumSquare = 0.0;
+ s.append("GNSS_KPI_END").append("\n");
+ GpsBatteryStats stats = mGnssPowerMetrics.getGpsBatteryStats();
+ if (stats != null) {
+ s.append("Power Metrics").append("\n");
+ s.append(" Time on battery (min): ").append(
+ stats.getLoggingDurationMs() / ((double) DateUtils.MINUTE_IN_MILLIS)).append(
+ "\n");
+ long[] t = stats.getTimeInGpsSignalQualityLevel();
+ if (t != null && t.length == NUM_GPS_SIGNAL_QUALITY_LEVELS) {
+ s.append(" Amount of time (while on battery) Top 4 Avg CN0 > "
+ + GnssPowerMetrics.POOR_TOP_FOUR_AVG_CN0_THRESHOLD_DB_HZ
+ + " dB-Hz (min): ").append(
+ t[1] / ((double) DateUtils.MINUTE_IN_MILLIS)).append("\n");
+ s.append(" Amount of time (while on battery) Top 4 Avg CN0 <= "
+ + GnssPowerMetrics.POOR_TOP_FOUR_AVG_CN0_THRESHOLD_DB_HZ
+ + " dB-Hz (min): ").append(
+ t[0] / ((double) DateUtils.MINUTE_IN_MILLIS)).append("\n");
+ }
+ s.append(" Energy consumed while on battery (mAh): ").append(
+ stats.getEnergyConsumedMaMs() / ((double) DateUtils.HOUR_IN_MILLIS)).append(
+ "\n");
+ }
+ s.append("Hardware Version: ").append(SystemProperties.get("ro.boot.revision", "")).append(
+ "\n");
+ return s.toString();
}
- /** Adds an item */
- public void addItem(double item) {
- count++;
- sum += item;
- sumSquare += item * item;
+ private void reset() {
+ StringBuilder s = new StringBuilder();
+ TimeUtils.formatDuration(SystemClock.elapsedRealtimeNanos() / 1000000L, s);
+ mLogStartInElapsedRealTime = s.toString();
+ mLocationFailureStatistics.reset();
+ mTimeToFirstFixSecStatistics.reset();
+ mPositionAccuracyMeterStatistics.reset();
+ mTopFourAverageCn0Statistics.reset();
+ resetConstellationTypes();
}
- /** Returns number of items added */
- public int getCount() {
- return count;
+ /** Resets {@link #mConstellationTypes} as an all-false boolean array. */
+ public void resetConstellationTypes() {
+ mConstellationTypes = new boolean[GnssStatus.CONSTELLATION_COUNT];
}
- /** Returns mean */
- public double getMean() {
- return sum/count;
- }
+ /** Class for storing statistics */
+ private class Statistics {
- /** Returns standard deviation */
- public double getStandardDeviation() {
- double m = sum/count;
- m = m * m;
- double v = sumSquare/count;
- if (v > m) {
- return Math.sqrt(v - m);
- }
- return 0;
- }
+ private int mCount;
+ private double mSum;
+ private double mSumSquare;
- private int count;
- private double sum;
- private double sumSquare;
- }
-
- /** Location failure statistics */
- private Statistics locationFailureStatistics;
-
- /** Time to first fix statistics */
- private Statistics timeToFirstFixSecStatistics;
-
- /** Position accuracy statistics */
- private Statistics positionAccuracyMeterStatistics;
-
- /** Top 4 average CN0 statistics */
- private Statistics topFourAverageCn0Statistics;
-
- /**
- * Resets GNSS metrics
- */
- private void reset() {
- StringBuilder s = new StringBuilder();
- TimeUtils.formatDuration(SystemClock.elapsedRealtimeNanos() / 1000000L, s);
- logStartInElapsedRealTime = s.toString();
- locationFailureStatistics.reset();
- timeToFirstFixSecStatistics.reset();
- positionAccuracyMeterStatistics.reset();
- topFourAverageCn0Statistics.reset();
- resetConstellationTypes();
- return;
- }
+ /** Resets statistics */
+ public void reset() {
+ mCount = 0;
+ mSum = 0.0;
+ mSumSquare = 0.0;
+ }
- /** Resets {@link #mConstellationTypes} as an all-false boolean array. */
- public void resetConstellationTypes() {
- mConstellationTypes = new boolean[GnssStatus.CONSTELLATION_COUNT];
+ /** Adds an item */
+ public void addItem(double item) {
+ mCount++;
+ mSum += item;
+ mSumSquare += item * item;
+ }
+
+ /** Returns number of items added */
+ public int getCount() {
+ return mCount;
+ }
+
+ /** Returns mean */
+ public double getMean() {
+ return mSum / mCount;
+ }
+
+ /** Returns standard deviation */
+ public double getStandardDeviation() {
+ double m = mSum / mCount;
+ m = m * m;
+ double v = mSumSquare / mCount;
+ if (v > m) {
+ return Math.sqrt(v - m);
+ }
+ return 0;
+ }
}
- /* Class for handling GNSS power related metrics */
- private class GnssPowerMetrics {
+ /* Class for handling GNSS power related metrics */
+ private class GnssPowerMetrics {
- /* Threshold for Top Four Average CN0 below which GNSS signal quality is declared poor */
- public static final double POOR_TOP_FOUR_AVG_CN0_THRESHOLD_DB_HZ = 20.0;
+ /* Threshold for Top Four Average CN0 below which GNSS signal quality is declared poor */
+ public static final double POOR_TOP_FOUR_AVG_CN0_THRESHOLD_DB_HZ = 20.0;
- /* Minimum change in Top Four Average CN0 needed to trigger a report */
- private static final double REPORTING_THRESHOLD_DB_HZ = 1.0;
+ /* Minimum change in Top Four Average CN0 needed to trigger a report */
+ private static final double REPORTING_THRESHOLD_DB_HZ = 1.0;
- /* BatteryStats API */
- private final IBatteryStats mBatteryStats;
+ /* BatteryStats API */
+ private final IBatteryStats mBatteryStats;
- /* Last reported Top Four Average CN0 */
- private double mLastAverageCn0;
+ /* Last reported Top Four Average CN0 */
+ private double mLastAverageCn0;
- /* Last reported signal quality bin (based on Top Four Average CN0) */
- private int mLastSignalLevel;
+ /* Last reported signal quality bin (based on Top Four Average CN0) */
+ private int mLastSignalLevel;
- public GnssPowerMetrics(IBatteryStats stats) {
- mBatteryStats = stats;
- // Used to initialize the variable to a very small value (unachievable in practice) so that
- // the first CNO report will trigger an update to BatteryStats
- mLastAverageCn0 = -100.0;
- mLastSignalLevel = GPS_SIGNAL_QUALITY_UNKNOWN;
- }
+ private GnssPowerMetrics(IBatteryStats stats) {
+ mBatteryStats = stats;
+ // Used to initialize the variable to a very small value (unachievable in practice)
+ // so that
+ // the first CNO report will trigger an update to BatteryStats
+ mLastAverageCn0 = -100.0;
+ mLastSignalLevel = GPS_SIGNAL_QUALITY_UNKNOWN;
+ }
- /**
- * Builds power metrics proto buf. This is included in the gnss proto buf.
- * @return PowerMetrics
- */
- public PowerMetrics buildProto() {
- PowerMetrics p = new PowerMetrics();
- GpsBatteryStats stats = mGnssPowerMetrics.getGpsBatteryStats();
- if (stats != null) {
- p.loggingDurationMs = stats.getLoggingDurationMs();
- p.energyConsumedMah = stats.getEnergyConsumedMaMs() / ((double) DateUtils.HOUR_IN_MILLIS);
- long[] t = stats.getTimeInGpsSignalQualityLevel();
- p.timeInSignalQualityLevelMs = new long[t.length];
- for (int i = 0; i < t.length; i++) {
- p.timeInSignalQualityLevelMs[i] = t[i];
+ /**
+ * Builds power metrics proto buf. This is included in the gnss proto buf.
+ *
+ * @return PowerMetrics
+ */
+ public PowerMetrics buildProto() {
+ PowerMetrics p = new PowerMetrics();
+ GpsBatteryStats stats = mGnssPowerMetrics.getGpsBatteryStats();
+ if (stats != null) {
+ p.loggingDurationMs = stats.getLoggingDurationMs();
+ p.energyConsumedMah =
+ stats.getEnergyConsumedMaMs() / ((double) DateUtils.HOUR_IN_MILLIS);
+ long[] t = stats.getTimeInGpsSignalQualityLevel();
+ p.timeInSignalQualityLevelMs = new long[t.length];
+ for (int i = 0; i < t.length; i++) {
+ p.timeInSignalQualityLevelMs[i] = t[i];
+ }
+ }
+ return p;
}
- }
- return p;
- }
- /**
- * Returns the GPS power stats
- * @return GpsBatteryStats
- */
- public GpsBatteryStats getGpsBatteryStats() {
- try {
- return mBatteryStats.getGpsBatteryStats();
- } catch (Exception e) {
- Log.w(TAG, "Exception", e);
- return null;
- }
- }
+ /**
+ * Returns the GPS power stats
+ *
+ * @return GpsBatteryStats
+ */
+ public GpsBatteryStats getGpsBatteryStats() {
+ try {
+ return mBatteryStats.getGpsBatteryStats();
+ } catch (Exception e) {
+ Log.w(TAG, "Exception", e);
+ return null;
+ }
+ }
- /**
- * Reports signal quality to BatteryStats. Signal quality is based on Top four average CN0. If
- * the number of SVs seen is less than 4, then signal quality is the average CN0.
- * Changes are reported only if the average CN0 changes by more than REPORTING_THRESHOLD_DB_HZ.
- */
- public void reportSignalQuality(float[] ascendingCN0Array, int numSv) {
- double avgCn0 = 0.0;
- if (numSv > 0) {
- for (int i = Math.max(0, numSv - 4); i < numSv; i++) {
- avgCn0 += (double) ascendingCN0Array[i];
+ /**
+ * Reports signal quality to BatteryStats. Signal quality is based on Top four average CN0.
+ * If
+ * the number of SVs seen is less than 4, then signal quality is the average CN0.
+ * Changes are reported only if the average CN0 changes by more than
+ * REPORTING_THRESHOLD_DB_HZ.
+ */
+ public void reportSignalQuality(float[] ascendingCN0Array, int numSv) {
+ double avgCn0 = 0.0;
+ if (numSv > 0) {
+ for (int i = Math.max(0, numSv - 4); i < numSv; i++) {
+ avgCn0 += (double) ascendingCN0Array[i];
+ }
+ avgCn0 /= Math.min(numSv, 4);
+ }
+ if (Math.abs(avgCn0 - mLastAverageCn0) < REPORTING_THRESHOLD_DB_HZ) {
+ return;
+ }
+ int signalLevel = getSignalLevel(avgCn0);
+ if (signalLevel != mLastSignalLevel) {
+ StatsLog.write(StatsLog.GPS_SIGNAL_QUALITY_CHANGED, signalLevel);
+ mLastSignalLevel = signalLevel;
+ }
+ try {
+ mBatteryStats.noteGpsSignalQuality(signalLevel);
+ mLastAverageCn0 = avgCn0;
+ } catch (Exception e) {
+ Log.w(TAG, "Exception", e);
+ }
}
- avgCn0 /= Math.min(numSv, 4);
- }
- if (Math.abs(avgCn0 - mLastAverageCn0) < REPORTING_THRESHOLD_DB_HZ) {
- return;
- }
- int signalLevel = getSignalLevel(avgCn0);
- if (signalLevel != mLastSignalLevel) {
- StatsLog.write(StatsLog.GPS_SIGNAL_QUALITY_CHANGED, signalLevel);
- mLastSignalLevel = signalLevel;
- }
- try {
- mBatteryStats.noteGpsSignalQuality(signalLevel);
- mLastAverageCn0 = avgCn0;
- } catch (Exception e) {
- Log.w(TAG, "Exception", e);
- }
- return;
- }
- /**
- * Obtains signal level based on CN0
- */
- private int getSignalLevel(double cn0) {
- if (cn0 > POOR_TOP_FOUR_AVG_CN0_THRESHOLD_DB_HZ) {
- return GnssMetrics.GPS_SIGNAL_QUALITY_GOOD;
- }
- return GnssMetrics.GPS_SIGNAL_QUALITY_POOR;
+ /**
+ * Obtains signal level based on CN0
+ */
+ private int getSignalLevel(double cn0) {
+ if (cn0 > POOR_TOP_FOUR_AVG_CN0_THRESHOLD_DB_HZ) {
+ return GnssMetrics.GPS_SIGNAL_QUALITY_GOOD;
+ }
+ return GnssMetrics.GPS_SIGNAL_QUALITY_POOR;
+ }
}
- }
}
diff --git a/media/apex/java/android/media/MediaController2.java b/media/apex/java/android/media/MediaController2.java
index 63a4510e7fe7..c3dd3fe4451c 100644
--- a/media/apex/java/android/media/MediaController2.java
+++ b/media/apex/java/android/media/MediaController2.java
@@ -46,14 +46,14 @@ import android.util.Log;
import java.util.concurrent.Executor;
/**
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+ * Library</a> for consistent behavior across all devices.
+ *
* Allows an app to interact with an active {@link MediaSession2} or a
* {@link MediaSession2Service} which would provide {@link MediaSession2}. Media buttons and other
* commands can be sent to the session.
- * <p>
- * This API is not generally intended for third party application developers.
- * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
- * for consistent behavior across all devices.
*/
public class MediaController2 implements AutoCloseable {
static final String TAG = "MediaController2";
@@ -405,6 +405,11 @@ public class MediaController2 implements AutoCloseable {
}
/**
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+ * Library</a> for consistent behavior across all devices.
+ * <p>
* Builder for {@link MediaController2}.
* <p>
* Any incoming event from the {@link MediaSession2} will be handled on the callback
@@ -502,9 +507,12 @@ public class MediaController2 implements AutoCloseable {
}
/**
- * Interface for listening to change in activeness of the {@link MediaSession2}.
- * <p>
* This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+ * Library</a> for consistent behavior across all devices.
+ * <p>
+ * Interface for listening to change in activeness of the {@link MediaSession2}.
*/
public abstract static class ControllerCallback {
/**
diff --git a/media/apex/java/android/media/MediaSession2.java b/media/apex/java/android/media/MediaSession2.java
index b3edf3f50866..081e76ab0215 100644
--- a/media/apex/java/android/media/MediaSession2.java
+++ b/media/apex/java/android/media/MediaSession2.java
@@ -52,13 +52,13 @@ import java.util.Objects;
import java.util.concurrent.Executor;
/**
- * Allows a media app to expose its transport controls and playback information in a process to
- * other processes including the Android framework and other apps.
- * <p>
* This API is not generally intended for third party application developers.
* Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
- * for consistent behavior across all devices.
+ * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+ * Library</a> for consistent behavior across all devices.
+ * <p>
+ * Allows a media app to expose its transport controls and playback information in a process to
+ * other processes including the Android framework and other apps.
*/
public class MediaSession2 implements AutoCloseable {
static final String TAG = "MediaSession2";
@@ -481,6 +481,11 @@ public class MediaSession2 implements AutoCloseable {
}
/**
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+ * Library</a> for consistent behavior across all devices.
+ * <p>
* Builder for {@link MediaSession2}.
* <p>
* Any incoming event from the {@link MediaController2} will be handled on the callback
@@ -616,9 +621,12 @@ public class MediaSession2 implements AutoCloseable {
}
/**
- * Information of a controller.
- * <p>
* This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+ * Library</a> for consistent behavior across all devices.
+ * <p>
+ * Information of a controller.
*/
public static final class ControllerInfo {
private final RemoteUserInfo mRemoteUserInfo;
@@ -807,9 +815,12 @@ public class MediaSession2 implements AutoCloseable {
}
/**
- * Callback to be called for all incoming commands from {@link MediaController2}s.
- * <p>
* This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+ * Library</a> for consistent behavior across all devices.
+ * <p>
+ * Callback to be called for all incoming commands from {@link MediaController2}s.
*/
public abstract static class SessionCallback {
/**
diff --git a/media/apex/java/android/media/MediaSession2Service.java b/media/apex/java/android/media/MediaSession2Service.java
index ee584e5eac30..f6fd509fd245 100644
--- a/media/apex/java/android/media/MediaSession2Service.java
+++ b/media/apex/java/android/media/MediaSession2Service.java
@@ -44,12 +44,12 @@ import java.util.List;
import java.util.Map;
/**
- * Service containing {@link MediaSession2}.
- * <p>
* This API is not generally intended for third party application developers.
* Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
- * for consistent behavior across all devices.
+ * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+ * Library</a> for consistent behavior across all devices.
+ * <p>
+ * Service containing {@link MediaSession2}.
*/
public abstract class MediaSession2Service extends Service {
/**
@@ -287,6 +287,11 @@ public abstract class MediaSession2Service extends Service {
}
/**
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+ * Library</a> for consistent behavior across all devices.
+ * <p>
* Returned by {@link #onUpdateNotification(MediaSession2)} for making session service
* foreground service to keep playback running in the background. It's highly recommended to
* show media style notification here.
diff --git a/media/apex/java/android/media/Session2Command.java b/media/apex/java/android/media/Session2Command.java
index 7c752e198f3a..26f4568fa7e5 100644
--- a/media/apex/java/android/media/Session2Command.java
+++ b/media/apex/java/android/media/Session2Command.java
@@ -26,6 +26,11 @@ import android.text.TextUtils;
import java.util.Objects;
/**
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+ * Library</a> for consistent behavior across all devices.
+ * <p>
* Define a command that a {@link MediaController2} can send to a {@link MediaSession2}.
* <p>
* If {@link #getCommandCode()} isn't {@link #COMMAND_CODE_CUSTOM}), it's predefined command.
@@ -35,11 +40,6 @@ import java.util.Objects;
* Refer to the
* <a href="{@docRoot}reference/androidx/media2/SessionCommand2.html">AndroidX SessionCommand</a>
* class for the list of valid commands.
- * <p>
- * This API is not generally intended for third party application developers.
- * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
- * for consistent behavior across all devices.
*/
public final class Session2Command implements Parcelable {
/**
@@ -162,6 +162,11 @@ public final class Session2Command implements Parcelable {
}
/**
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+ * Library</a> for consistent behavior across all devices.
+ * <p>
* Contains the result of {@link Session2Command}.
*/
public static final class Result {
diff --git a/media/apex/java/android/media/Session2CommandGroup.java b/media/apex/java/android/media/Session2CommandGroup.java
index 06ae8737fdc0..0ee5f62be128 100644
--- a/media/apex/java/android/media/Session2CommandGroup.java
+++ b/media/apex/java/android/media/Session2CommandGroup.java
@@ -28,13 +28,12 @@ import java.util.HashSet;
import java.util.Set;
/**
- * A set of {@link Session2Command} which represents a command group.
- * <p>
* This API is not generally intended for third party application developers.
* Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
- * for consistent behavior across all devices.
- * </p>
+ * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+ * Library</a> for consistent behavior across all devices.
+ * <p>
+ * A set of {@link Session2Command} which represents a command group.
*/
public final class Session2CommandGroup implements Parcelable {
private static final String TAG = "Session2CommandGroup";
@@ -131,6 +130,11 @@ public final class Session2CommandGroup implements Parcelable {
}
/**
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+ * Library</a> for consistent behavior across all devices.
+ * <p>
* Builds a {@link Session2CommandGroup} object.
*/
public static final class Builder {
diff --git a/media/apex/java/android/media/Session2Token.java b/media/apex/java/android/media/Session2Token.java
index 6d499fa88815..6eb76b11497e 100644
--- a/media/apex/java/android/media/Session2Token.java
+++ b/media/apex/java/android/media/Session2Token.java
@@ -36,13 +36,13 @@ import java.util.List;
import java.util.Objects;
/**
- * Represents an ongoing {@link MediaSession2} or a {@link MediaSession2Service}.
- * If it's representing a session service, it may not be ongoing.
- * <p>
* This API is not generally intended for third party application developers.
* Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
- * for consistent behavior across all devices.
+ * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+ * Library</a> for consistent behavior across all devices.
+ * <p>
+ * Represents an ongoing {@link MediaSession2} or a {@link MediaSession2Service}.
+ * If it's representing a session service, it may not be ongoing.
* <p>
* This may be passed to apps by the session owner to allow them to create a
* {@link MediaController2} to communicate with the session.
diff --git a/media/java/android/media/IMediaRoute2Provider.aidl b/media/java/android/media/IMediaRoute2Provider.aidl
index 4bd57106febe..f132cefbfdc7 100644
--- a/media/java/android/media/IMediaRoute2Provider.aidl
+++ b/media/java/android/media/IMediaRoute2Provider.aidl
@@ -23,7 +23,8 @@ import android.media.IMediaRoute2ProviderClient;
* {@hide}
*/
oneway interface IMediaRoute2Provider {
- void registerClient(IMediaRoute2ProviderClient client);
- void selectRoute(IMediaRoute2ProviderClient client, int uid, String id);
- void notifyControlRequestSent(IMediaRoute2ProviderClient client, String id, in Intent request);
+ void setClient(IMediaRoute2ProviderClient client);
+ void selectRoute(String packageName, String id);
+ void unselectRoute(String packageName, String id);
+ void notifyControlRequestSent(String id, in Intent request);
}
diff --git a/media/java/android/media/IMediaRoute2ProviderClient.aidl b/media/java/android/media/IMediaRoute2ProviderClient.aidl
index e849e190e8b8..8d08beb4a72c 100644
--- a/media/java/android/media/IMediaRoute2ProviderClient.aidl
+++ b/media/java/android/media/IMediaRoute2ProviderClient.aidl
@@ -22,6 +22,5 @@ import android.media.MediaRoute2ProviderInfo;
* @hide
*/
oneway interface IMediaRoute2ProviderClient {
- void notifyRouteSelected(int uid, String routeId);
void notifyProviderInfoUpdated(in MediaRoute2ProviderInfo info);
}
diff --git a/media/java/android/media/IMediaRouter2Manager.aidl b/media/java/android/media/IMediaRouter2Manager.aidl
index b8c00a335d13..b059bd3cec91 100644
--- a/media/java/android/media/IMediaRouter2Manager.aidl
+++ b/media/java/android/media/IMediaRouter2Manager.aidl
@@ -23,7 +23,7 @@ import android.media.MediaRoute2Info;
* {@hide}
*/
oneway interface IMediaRouter2Manager {
- void notifyRouteSelected(int uid, in MediaRoute2Info route);
- void notifyControlCategoriesChanged(int uid, in List<String> categories);
+ void notifyRouteSelected(String packageName, in MediaRoute2Info route);
+ void notifyControlCategoriesChanged(String packageName, in List<String> categories);
void notifyProviderInfosUpdated(in List<MediaRoute2ProviderInfo> providers);
}
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index fb108b4a85ec..08266a5a2051 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -48,8 +48,8 @@ interface IMediaRouterService {
/**
* Changes the selected route of the client.
*
- * @param client Client to change it's selected route.
- * @param route Route to be selected.
+ * @param client the client that changes it's selected route
+ * @param route the route to be selected
*/
void selectRoute2(IMediaRouter2Client client, in @nullable MediaRoute2Info route);
void setControlCategories(IMediaRouter2Client client, in List<String> categories);
@@ -60,10 +60,10 @@ interface IMediaRouterService {
/**
* Changes the selected route of an application.
*
- * @param manager Manager that calls the method
- * @param uid UID of the client that will change the selected route.
- * @param route Route to be selected.
+ * @param manager the manager that calls the method
+ * @param packageName the package name of the client that will change the selected route
+ * @param route the route to be selected
*/
- void selectClientRoute2(IMediaRouter2Manager manager, int clientUid,
+ void selectClientRoute2(IMediaRouter2Manager manager, String packageName,
in @nullable MediaRoute2Info route);
}
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 813e4744fc77..0346010f4587 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -800,7 +800,7 @@ public class MediaMetadataRetriever implements AutoCloseable {
*/
public static final int METADATA_KEY_YEAR = 8;
/**
- * The metadata key to retrieve the playback duration of the data source.
+ * The metadata key to retrieve the playback duration (in ms) of the data source.
*/
public static final int METADATA_KEY_DURATION = 9;
/**
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index 855cd77f019e..f13a64c1520b 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -52,6 +52,8 @@ public final class MediaRoute2Info implements Parcelable {
@Nullable
final String mDescription;
@Nullable
+ final String mClientPackageName;
+ @Nullable
final Bundle mExtras;
MediaRoute2Info(@NonNull Builder builder) {
@@ -59,6 +61,7 @@ public final class MediaRoute2Info implements Parcelable {
mProviderId = builder.mProviderId;
mName = builder.mName;
mDescription = builder.mDescription;
+ mClientPackageName = builder.mClientPackageName;
mExtras = builder.mExtras;
}
@@ -67,6 +70,7 @@ public final class MediaRoute2Info implements Parcelable {
mProviderId = in.readString();
mName = in.readString();
mDescription = in.readString();
+ mClientPackageName = in.readString();
mExtras = in.readBundle();
}
@@ -98,6 +102,7 @@ public final class MediaRoute2Info implements Parcelable {
&& Objects.equals(mProviderId, other.mProviderId)
&& Objects.equals(mName, other.mName)
&& Objects.equals(mDescription, other.mDescription)
+ && Objects.equals(mClientPackageName, other.mClientPackageName)
//TODO: This will be evaluated as false in most cases. Try not to.
&& Objects.equals(mExtras, other.mExtras);
}
@@ -131,6 +136,16 @@ public final class MediaRoute2Info implements Parcelable {
return mDescription;
}
+ /**
+ * Gets the package name of the client that uses the route.
+ * Returns null if no clients use this.
+ * @hide
+ */
+ @Nullable
+ public String getClientPackageName() {
+ return mClientPackageName;
+ }
+
@Nullable
public Bundle getExtras() {
return mExtras;
@@ -147,6 +162,7 @@ public final class MediaRoute2Info implements Parcelable {
dest.writeString(mProviderId);
dest.writeString(mName);
dest.writeString(mDescription);
+ dest.writeString(mClientPackageName);
dest.writeBundle(mExtras);
}
@@ -170,6 +186,7 @@ public final class MediaRoute2Info implements Parcelable {
String mProviderId;
String mName;
String mDescription;
+ String mClientPackageName;
Bundle mExtras;
public Builder(@NonNull String id, @NonNull String name) {
@@ -194,6 +211,7 @@ public final class MediaRoute2Info implements Parcelable {
}
setName(routeInfo.mName);
mDescription = routeInfo.mDescription;
+ setClientPackageName(routeInfo.mClientPackageName);
if (routeInfo.mExtras != null) {
mExtras = new Bundle(routeInfo.mExtras);
}
@@ -246,6 +264,15 @@ public final class MediaRoute2Info implements Parcelable {
}
/**
+ * Sets the package name of the app using the route.
+ */
+ @NonNull
+ public Builder setClientPackageName(@Nullable String packageName) {
+ mClientPackageName = packageName;
+ return this;
+ }
+
+ /**
* Sets a bundle of extras for the route.
*/
@NonNull
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 30e0ef1fc182..b89b0b1a5f02 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -36,7 +36,6 @@ public abstract class MediaRoute2ProviderService extends Service {
private final Handler mHandler;
private ProviderStub mStub;
- //TODO: Should allow multiple clients
private IMediaRoute2ProviderClient mClient;
private MediaRoute2ProviderInfo mProviderInfo;
@@ -46,6 +45,7 @@ public abstract class MediaRoute2ProviderService extends Service {
@Override
public IBinder onBind(Intent intent) {
+ //TODO: Allow binding from media router service only?
if (SERVICE_INTERFACE.equals(intent.getAction())) {
if (mStub == null) {
mStub = new ProviderStub();
@@ -58,49 +58,37 @@ public abstract class MediaRoute2ProviderService extends Service {
/**
* Called when selectRoute is called on a route of the provider.
*
- * @param uid The target application uid
- * @param routeId The id of the target route
+ * @param packageName the package name of the application that selected the route
+ * @param routeId the id of the route being selected
*/
- public abstract void onSelect(int uid, String routeId);
+ public abstract void onSelectRoute(String packageName, String routeId);
/**
- * Called when sendControlRequest is called on a route of the provider.
+ * Called when unselectRoute is called on a route of the provider.
*
- * @param routeId The id of the target route
- * @param request The media control request intent
+ * @param packageName the package name of the application that has selected the route.
+ * @param routeId the id of the route being unselected
*/
- //TODO: Discuss what to use for request (e.g., Intent? Request class?)
- public abstract void onControlRequest(String routeId, Intent request);
+ public abstract void onUnselectRoute(String packageName, String routeId);
/**
- * Updates provider info from selected route and application.
- *
- * TODO: When provider descriptor is defined, this should update the descriptor correctly.
+ * Called when sendControlRequest is called on a route of the provider
*
- * @param uid
- * @param routeId
+ * @param routeId the id of the target route
+ * @param request the media control request intent
*/
- public void updateProvider(int uid, String routeId) {
- if (mClient != null) {
- try {
- //TODO: After publishState() is fully implemented, delete this.
- mClient.notifyRouteSelected(uid, routeId);
- } catch (RemoteException ex) {
- Log.d(TAG, "Failed to update provider");
- }
- }
- publishState();
- }
+ //TODO: Discuss what to use for request (e.g., Intent? Request class?)
+ public abstract void onControlRequest(String routeId, Intent request);
/**
- * Updates provider info and publish routes
+ * Updates provider info and publishes routes
*/
public final void setProviderInfo(MediaRoute2ProviderInfo info) {
mProviderInfo = info;
publishState();
}
- void registerClient(IMediaRoute2ProviderClient client) {
+ void setClient(IMediaRoute2ProviderClient client) {
mClient = client;
publishState();
}
@@ -120,20 +108,25 @@ public abstract class MediaRoute2ProviderService extends Service {
ProviderStub() { }
@Override
- public void registerClient(IMediaRoute2ProviderClient client) {
- mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::registerClient,
+ public void setClient(IMediaRoute2ProviderClient client) {
+ mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::setClient,
MediaRoute2ProviderService.this, client));
}
@Override
- public void selectRoute(IMediaRoute2ProviderClient client, int uid, String id) {
- mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSelect,
- MediaRoute2ProviderService.this, uid, id));
+ public void selectRoute(String packageName, String id) {
+ mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSelectRoute,
+ MediaRoute2ProviderService.this, packageName, id));
+ }
+
+ @Override
+ public void unselectRoute(String packageName, String id) {
+ mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onUnselectRoute,
+ MediaRoute2ProviderService.this, packageName, id));
}
@Override
- public void notifyControlRequestSent(IMediaRoute2ProviderClient client, String id,
- Intent request) {
+ public void notifyControlRequestSent(String id, Intent request) {
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onControlRequest,
MediaRoute2ProviderService.this, id, request));
}
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 2d7dc56339e1..5fc37a579d92 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -38,6 +38,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
/**
@@ -58,11 +59,13 @@ public class MediaRouter2Manager {
final Handler mHandler;
@GuardedBy("sLock")
- final ArrayList<CallbackRecord> mCallbacks = new ArrayList<>();
+ final List<CallbackRecord> mCallbacks = new CopyOnWriteArrayList<>();
@SuppressWarnings("WeakerAccess") /* synthetic access */
@NonNull
List<MediaRoute2ProviderInfo> mProviders = Collections.emptyList();
+ @NonNull
+ List<MediaRoute2Info> mRoutes = Collections.emptyList();
/**
* Gets an instance of media router manager that controls media route of other applications.
@@ -158,15 +161,26 @@ public class MediaRouter2Manager {
}
/**
- * Selects media route for the specified application uid.
+ * Gets available routes for an application.
+ *
+ * @param packageName the package name of the application
+ */
+ @NonNull
+ public List<MediaRoute2Info> getAvailableRoutes(@NonNull String packageName) {
+ //TODO: filter irrelevant routes.
+ return Collections.unmodifiableList(mRoutes);
+ }
+
+ /**
+ * Selects media route for the specified package name.
*
- * @param uid The uid of the application that should change it's media route.
- * @param route The route to select
+ * @param packageName the package name of the application that should change it's media route
+ * @param route the route to be selected
*/
- public void selectRoute(int uid, MediaRoute2Info route) {
+ public void selectRoute(@NonNull String packageName, @NonNull MediaRoute2Info route) {
if (mClient != null) {
try {
- mMediaRouterService.selectClientRoute2(mClient, uid, route);
+ mMediaRouterService.selectClientRoute2(mClient, packageName, route);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to select media route", ex);
}
@@ -174,14 +188,14 @@ public class MediaRouter2Manager {
}
/**
- * Unselects media route for the specified application uid.
+ * Unselects media route for the specified package name.
*
- * @param uid The uid of the application that should stop routing.
+ * @param packageName the package name of the application that should stop routing
*/
- public void unselectRoute(int uid) {
+ public void unselectRoute(@NonNull String packageName) {
if (mClient != null) {
try {
- mMediaRouterService.selectClientRoute2(mClient, uid, null);
+ mMediaRouterService.selectClientRoute2(mClient, packageName, null);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to select media route", ex);
}
@@ -260,31 +274,46 @@ public class MediaRouter2Manager {
}
}
+ void notifyRouteListChanged() {
+ for (CallbackRecord record: mCallbacks) {
+ record.mExecutor.execute(
+ () -> record.mCallback.onRouteListChanged(mRoutes));
+ }
+ }
+
void notifyProviderInfosUpdated(List<MediaRoute2ProviderInfo> providers) {
if (providers == null) {
Log.w(TAG, "Providers info is null.");
return;
}
+ ArrayList<MediaRoute2Info> routes = new ArrayList<>();
+
for (MediaRoute2ProviderInfo provider : providers) {
updateProvider(provider);
+ //TODO: Should we do this in updateProvider()?
+ routes.addAll(provider.getRoutes());
}
//TODO: Call notifyRouteRemoved for the routes of the removed providers.
- //TODO: Filter invalid providers.
+ //TODO: Filter invalid providers and invalid routes.
mProviders = providers;
+ mRoutes = routes;
+
+ //TODO: Call this when only the list is modified.
+ notifyRouteListChanged();
}
- void notifyRouteSelected(int uid, MediaRoute2Info route) {
+ void notifyRouteSelected(String packageName, MediaRoute2Info route) {
for (CallbackRecord record : mCallbacks) {
- record.mExecutor.execute(() -> record.mCallback.onRouteSelected(uid, route));
+ record.mExecutor.execute(() -> record.mCallback.onRouteSelected(packageName, route));
}
}
- void notifyControlCategoriesChanged(int uid, List<String> categories) {
+ void notifyControlCategoriesChanged(String packageName, List<String> categories) {
for (CallbackRecord record : mCallbacks) {
record.mExecutor.execute(
- () -> record.mCallback.onControlCategoriesChanged(uid, categories));
+ () -> record.mCallback.onControlCategoriesChanged(packageName, categories));
}
}
@@ -309,17 +338,27 @@ public class MediaRouter2Manager {
/**
* Called when a route is selected for an application.
- * @param uid uid of the application
- * @param route selected route of the application.
+ *
+ * @param packageName the package name of the application
+ * @param route the selected route of the application.
+ * It is null if the application has no selected route.
*/
- public void onRouteSelected(int uid, @Nullable MediaRoute2Info route) {}
+ public void onRouteSelected(@NonNull String packageName, @Nullable MediaRoute2Info route) {}
/**
* Called when the control categories of an application is changed.
- * @param uid the uid of the app that changed control categories
+ *
+ * @param packageName the package name of the app that changed control categories
* @param categories the changed categories
*/
- public void onControlCategoriesChanged(int uid, @NonNull List<String> categories) {}
+ public void onControlCategoriesChanged(@NonNull String packageName,
+ @NonNull List<String> categories) {}
+
+ /**
+ * Called when the list of routes are changed.
+ * A client may refresh available routes for each application.
+ */
+ public void onRouteListChanged(@NonNull List<MediaRoute2Info> routes) {}
}
final class CallbackRecord {
@@ -343,15 +382,15 @@ public class MediaRouter2Manager {
class Client extends IMediaRouter2Manager.Stub {
@Override
- public void notifyRouteSelected(int uid, MediaRoute2Info route) {
+ public void notifyRouteSelected(String packageName, MediaRoute2Info route) {
mHandler.sendMessage(obtainMessage(MediaRouter2Manager::notifyRouteSelected,
- MediaRouter2Manager.this, uid, route));
+ MediaRouter2Manager.this, packageName, route));
}
@Override
- public void notifyControlCategoriesChanged(int uid, List<String> categories) {
+ public void notifyControlCategoriesChanged(String packageName, List<String> categories) {
mHandler.sendMessage(obtainMessage(MediaRouter2Manager::notifyControlCategoriesChanged,
- MediaRouter2Manager.this, uid, categories));
+ MediaRouter2Manager.this, packageName, categories));
}
@Override
diff --git a/media/java/android/media/ThumbnailUtils.java b/media/java/android/media/ThumbnailUtils.java
index 534d63b4cca0..fb581b532dd2 100644
--- a/media/java/android/media/ThumbnailUtils.java
+++ b/media/java/android/media/ThumbnailUtils.java
@@ -356,19 +356,21 @@ public class ThumbnailUtils {
return ImageDecoder.decodeBitmap(ImageDecoder.createSource(raw), resizer);
}
- // Fall back to middle of video
final int width = Integer.parseInt(mmr.extractMetadata(METADATA_KEY_VIDEO_WIDTH));
final int height = Integer.parseInt(mmr.extractMetadata(METADATA_KEY_VIDEO_HEIGHT));
- final long duration = Long.parseLong(mmr.extractMetadata(METADATA_KEY_DURATION));
+ // Fall back to middle of video
+ // Note: METADATA_KEY_DURATION unit is in ms, not us.
+ final long thumbnailTimeUs =
+ Long.parseLong(mmr.extractMetadata(METADATA_KEY_DURATION)) * 1000 / 2;
// If we're okay with something larger than native format, just
// return a frame without up-scaling it
if (size.getWidth() > width && size.getHeight() > height) {
return Objects.requireNonNull(
- mmr.getFrameAtTime(duration / 2, OPTION_CLOSEST_SYNC));
+ mmr.getFrameAtTime(thumbnailTimeUs, OPTION_CLOSEST_SYNC));
} else {
return Objects.requireNonNull(
- mmr.getScaledFrameAtTime(duration / 2, OPTION_CLOSEST_SYNC,
+ mmr.getScaledFrameAtTime(thumbnailTimeUs, OPTION_CLOSEST_SYNC,
size.getWidth(), size.getHeight()));
}
} catch (RuntimeException e) {
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index a67a37eedd27..01e6ed5e9f35 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -62,7 +62,8 @@ interface ISessionManager {
// For PhoneWindowManager to precheck media keys
boolean isGlobalPriorityActive();
- void setCallback(in ICallback callback);
+ void registerCallback(in ICallback callback);
+ void unregisterCallback(in ICallback callback);
void setOnVolumeKeyLongPressListener(in IOnVolumeKeyLongPressListener listener);
void setOnMediaKeyListener(in IOnMediaKeyListener listener);
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 569d11e1dce6..1f2283c6381f 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -46,7 +46,9 @@ import android.view.KeyEvent;
import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
/**
@@ -72,6 +74,7 @@ public final class MediaSessionManager {
* @hide
*/
public static final int RESULT_MEDIA_KEY_HANDLED = 1;
+ private final ISessionManager mService;
private final Object mLock = new Object();
@GuardedBy("mLock")
@@ -80,13 +83,21 @@ public final class MediaSessionManager {
@GuardedBy("mLock")
private final ArrayMap<OnSession2TokensChangedListener, Session2TokensChangedWrapper>
mSession2TokensListeners = new ArrayMap<>();
- private final ISessionManager mService;
+ @GuardedBy("mLock")
+ private final CallbackStub mCbStub = new CallbackStub();
+ @GuardedBy("mLock")
+ private final Map<Callback, Handler> mCallbacks = new HashMap<>();
+ @GuardedBy("mLock")
+ private MediaSession.Token mCurMediaButtonSession;
+ @GuardedBy("mLock")
+ private ComponentName mCurMediaButtonReceiver;
private Context mContext;
-
- private CallbackImpl mCallback;
private OnVolumeKeyLongPressListenerImpl mOnVolumeKeyLongPressListener;
private OnMediaKeyListenerImpl mOnMediaKeyListener;
+ // TODO: Remove mLegacyCallback once Bluetooth app stop calling setCallback() method.
+ @GuardedBy("mLock")
+ private Callback mLegacyCallback;
/**
* @hide
@@ -119,6 +130,11 @@ public final class MediaSessionManager {
}
/**
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+ * Library</a> for consistent behavior across all devices.
+ * <p>
* Notifies that a new {@link MediaSession2} with type {@link Session2Token#TYPE_SESSION} is
* created.
* <p>
@@ -192,6 +208,11 @@ public final class MediaSessionManager {
}
/**
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+ * Library</a> for consistent behavior across all devices.
+ * <p>
* Gets a list of {@link Session2Token} with type {@link Session2Token#TYPE_SESSION} for the
* current user.
* <p>
@@ -335,12 +356,12 @@ public final class MediaSessionManager {
}
/**
- * Adds a listener to be notified when the {@link #getSession2Tokens()} changes.
- * <p>
* This API is not generally intended for third party application developers.
* Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
- * for consistent behavior across all devices.
+ * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+ * Library</a> for consistent behavior across all devices.
+ * <p>
+ * Adds a listener to be notified when the {@link #getSession2Tokens()} changes.
*
* @param listener The listener to add
*/
@@ -350,12 +371,12 @@ public final class MediaSessionManager {
}
/**
- * Adds a listener to be notified when the {@link #getSession2Tokens()} changes.
- * <p>
* This API is not generally intended for third party application developers.
* Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
- * for consistent behavior across all devices.
+ * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+ * Library</a> for consistent behavior across all devices.
+ * <p>
+ * Adds a listener to be notified when the {@link #getSession2Tokens()} changes.
*
* @param listener The listener to add
* @param handler The handler to call listener on.
@@ -366,12 +387,12 @@ public final class MediaSessionManager {
}
/**
- * Adds a listener to be notified when the {@link #getSession2Tokens()} changes.
- * <p>
* This API is not generally intended for third party application developers.
* Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
- * for consistent behavior across all devices.
+ * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+ * Library</a> for consistent behavior across all devices.
+ * <p>
+ * Adds a listener to be notified when the {@link #getSession2Tokens()} changes.
*
* @param userId The userId to listen for changes on
* @param listener The listener to add
@@ -402,6 +423,11 @@ public final class MediaSessionManager {
}
/**
+ * This API is not generally intended for third party application developers.
+ * Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+ * Library</a> for consistent behavior across all devices.
+ * <p>
* Removes the {@link OnSession2TokensChangedListener} to stop receiving session token updates.
*
* @param listener The listener to remove.
@@ -737,18 +763,71 @@ public final class MediaSessionManager {
* if the callback should be invoked on the calling thread's looper.
* @hide
*/
+ // TODO: Remove this method once Bluetooth app stop calling it.
public void setCallback(@Nullable Callback callback, @Nullable Handler handler) {
synchronized (mLock) {
+ if (mLegacyCallback != null) {
+ unregisterCallback(mLegacyCallback);
+ }
+ mLegacyCallback = callback;
+ if (callback != null) {
+ registerCallback(callback, handler);
+ }
+ }
+ }
+
+ /**
+ * Register a {@link Callback}.
+ *
+ * @param callback A {@link Callback}.
+ * @param handler The handler on which the callback should be invoked, or {@code null}
+ * if the callback should be invoked on the calling thread's looper.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
+ public void registerCallback(@NonNull Callback callback, @Nullable Handler handler) {
+ if (callback == null) {
+ throw new NullPointerException("callback shouldn't be null");
+ }
+ synchronized (mLock) {
try {
- if (callback == null) {
- mCallback = null;
- mService.setCallback(null);
- } else {
- if (handler == null) {
- handler = new Handler();
- }
- mCallback = new CallbackImpl(callback, handler);
- mService.setCallback(mCallback);
+ if (handler == null) {
+ handler = new Handler();
+ }
+ mCallbacks.put(callback, handler);
+ if (mCurMediaButtonSession != null) {
+ handler.post(() -> callback.onAddressedPlayerChanged(mCurMediaButtonSession));
+ } else if (mCurMediaButtonReceiver != null) {
+ handler.post(() -> callback.onAddressedPlayerChanged(mCurMediaButtonReceiver));
+ }
+
+ if (mCallbacks.size() == 1) {
+ mService.registerCallback(mCbStub);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to set media key callback", e);
+ }
+ }
+ }
+
+ /**
+ * Unregister a {@link Callback}.
+ *
+ * @param callback A {@link Callback}.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(value = android.Manifest.permission.MEDIA_CONTENT_CONTROL)
+ public void unregisterCallback(@NonNull Callback callback) {
+ if (callback == null) {
+ throw new NullPointerException("callback shouldn't be null");
+ }
+ synchronized (mLock) {
+ try {
+ mCallbacks.remove(callback);
+ if (mCallbacks.size() == 0) {
+ mService.unregisterCallback(mCbStub);
}
} catch (RemoteException e) {
Log.e(TAG, "Failed to set media key callback", e);
@@ -765,13 +844,13 @@ public final class MediaSessionManager {
}
/**
- * Listens for changes to the {@link #getSession2Tokens()}. This can be added
- * using {@link #addOnSession2TokensChangedListener(OnSession2TokensChangedListener, Handler)}.
- * <p>
* This API is not generally intended for third party application developers.
* Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/media2/package-summary.html">Media2 Library</a>
- * for consistent behavior across all devices.
+ * <a href="{@docRoot}reference/androidx/media2/session/package-summary.html">Media2 session
+ * Library</a> for consistent behavior across all devices.
+ * <p>
+ * Listens for changes to the {@link #getSession2Tokens()}. This can be added
+ * using {@link #addOnSession2TokensChangedListener(OnSession2TokensChangedListener, Handler)}.
*/
public interface OnSession2TokensChangedListener {
/**
@@ -820,6 +899,7 @@ public final class MediaSessionManager {
* receive media key events.
* @hide
*/
+ @SystemApi
public static abstract class Callback {
/**
* Called when a media key event is dispatched to the media session
@@ -846,7 +926,7 @@ public final class MediaSessionManager {
/**
* Called when the addressed player is changed to a media session.
* <p>One of the {@ #onAddressedPlayerChanged} will be also called immediately after
- * {@link #setCallback} if the addressed player exists.
+ * {@link #registerCallback} if the addressed player exists.
*
* @param sessionToken The media session's token.
*/
@@ -855,7 +935,7 @@ public final class MediaSessionManager {
/**
* Called when the addressed player is changed to the media button receiver.
* <p>One of the {@ #onAddressedPlayerChanged} will be also called immediately after
- * {@link #setCallback} if the addressed player exists.
+ * {@link #registerCallback} if the addressed player exists.
*
* @param mediaButtonReceiver The media button receiver.
*/
@@ -1061,56 +1141,52 @@ public final class MediaSessionManager {
}
}
- private static final class CallbackImpl extends ICallback.Stub {
- private final Callback mCallback;
- private final Handler mHandler;
-
- public CallbackImpl(@NonNull Callback callback, @NonNull Handler handler) {
- mCallback = callback;
- mHandler = handler;
- }
+ private final class CallbackStub extends ICallback.Stub {
@Override
public void onMediaKeyEventDispatchedToMediaSession(KeyEvent event,
MediaSession.Token sessionToken) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mCallback.onMediaKeyEventDispatched(event, sessionToken);
+ synchronized (mLock) {
+ for (Map.Entry<Callback, Handler> e : mCallbacks.entrySet()) {
+ e.getValue().post(
+ () -> e.getKey().onMediaKeyEventDispatched(event, sessionToken));
}
- });
+ }
}
@Override
public void onMediaKeyEventDispatchedToMediaButtonReceiver(KeyEvent event,
ComponentName mediaButtonReceiver) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mCallback.onMediaKeyEventDispatched(event, mediaButtonReceiver);
+ synchronized (mLock) {
+ for (Map.Entry<Callback, Handler> e : mCallbacks.entrySet()) {
+ e.getValue().post(
+ () -> e.getKey().onMediaKeyEventDispatched(event, mediaButtonReceiver));
}
- });
+ }
}
@Override
public void onAddressedPlayerChangedToMediaSession(MediaSession.Token sessionToken) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mCallback.onAddressedPlayerChanged(sessionToken);
+ synchronized (mLock) {
+ mCurMediaButtonSession = sessionToken;
+ mCurMediaButtonReceiver = null;
+ for (Map.Entry<Callback, Handler> e : mCallbacks.entrySet()) {
+ e.getValue().post(() -> e.getKey().onAddressedPlayerChanged(sessionToken));
}
- });
+ }
}
@Override
public void onAddressedPlayerChangedToMediaButtonReceiver(
ComponentName mediaButtonReceiver) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mCallback.onAddressedPlayerChanged(mediaButtonReceiver);
+ synchronized (mLock) {
+ mCurMediaButtonSession = null;
+ mCurMediaButtonReceiver = mediaButtonReceiver;
+ for (Map.Entry<Callback, Handler> e : mCallbacks.entrySet()) {
+ e.getValue().post(() -> e.getKey().onAddressedPlayerChanged(
+ mediaButtonReceiver));
}
- });
+ }
}
}
}
diff --git a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
index 21cb93d4f12e..2cdc6a8101d7 100644
--- a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
+++ b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java
@@ -59,8 +59,26 @@ public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService
}
@Override
- public void onSelect(int uid, String routeId) {
- updateProvider(uid, routeId);
+ public void onSelectRoute(String packageName, String routeId) {
+ MediaRoute2Info route = mRoutes.get(routeId);
+ if (route == null) {
+ return;
+ }
+ mRoutes.put(routeId, new MediaRoute2Info.Builder(route)
+ .setClientPackageName(packageName)
+ .build());
+ publishRoutes();
+ }
+
+ @Override
+ public void onUnselectRoute(String packageName, String routeId) {
+ MediaRoute2Info route = mRoutes.get(routeId);
+ if (route == null) {
+ return;
+ }
+ mRoutes.put(routeId, new MediaRoute2Info.Builder(route)
+ .setClientPackageName(null)
+ .build());
publishRoutes();
}
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
index aa062cd996ae..03b43e215c25 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
@@ -16,6 +16,8 @@
package com.android.mediaroutertest;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.timeout;
@@ -37,7 +39,9 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.SynchronousQueue;
@@ -49,8 +53,6 @@ import java.util.concurrent.TimeUnit;
public class MediaRouterManagerTest {
private static final String TAG = "MediaRouterManagerTest";
- private static final int TARGET_UID = 109992;
-
// Must be the same as SampleMediaRoute2ProviderService
public static final String ROUTE_ID1 = "route_id1";
public static final String ROUTE_NAME1 = "Sample Route 1";
@@ -59,13 +61,13 @@ public class MediaRouterManagerTest {
public static final String ACTION_REMOVE_ROUTE =
"com.android.mediarouteprovider.action_remove_route";
- private static final int AWAIT_MS = 1000;
private static final int TIMEOUT_MS = 5000;
private Context mContext;
private MediaRouter2Manager mManager;
private MediaRouter2 mRouter;
private Executor mExecutor;
+ private String mPackageName;
private static final List<String> TEST_CONTROL_CATEGORIES = new ArrayList();
private static final String CONTROL_CATEGORY_1 = "android.media.mediarouter.MEDIA1";
@@ -83,6 +85,20 @@ public class MediaRouterManagerTest {
mExecutor = new ThreadPoolExecutor(
1, 20, 3, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
+ mPackageName = mContext.getPackageName();
+ }
+
+ @Test
+ public void testMediaRoute2Info() {
+ MediaRoute2Info routeInfo1 = new MediaRoute2Info.Builder("id", "name")
+ .build();
+ MediaRoute2Info routeInfo2 = new MediaRoute2Info.Builder(routeInfo1).build();
+
+ MediaRoute2Info routeInfo3 = new MediaRoute2Info.Builder(routeInfo1)
+ .setClientPackageName(mPackageName).build();
+
+ assertEquals(routeInfo1, routeInfo2);
+ assertNotEquals(routeInfo1, routeInfo3);
}
//TODO: Test onRouteChanged when it's properly implemented.
@@ -124,34 +140,30 @@ public class MediaRouterManagerTest {
@Test
public void controlCategoryTest() throws Exception {
- final int uid = android.os.Process.myUid();
-
MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class);
mManager.addCallback(mExecutor, mockCallback);
MediaRouter2.Callback mockRouterCallback = mock(MediaRouter2.Callback.class);
InstrumentationRegistry.getInstrumentation().runOnMainSync(
- (Runnable) () -> {
+ () -> {
mRouter.addCallback(TEST_CONTROL_CATEGORIES, mExecutor, mockRouterCallback);
mRouter.removeCallback(mockRouterCallback);
}
);
verify(mockCallback, timeout(TIMEOUT_MS).atLeastOnce())
- .onControlCategoriesChanged(uid, TEST_CONTROL_CATEGORIES);
+ .onControlCategoriesChanged(mPackageName, TEST_CONTROL_CATEGORIES);
mManager.removeCallback(mockCallback);
}
@Test
- public void selectRouteTest() throws Exception {
- final int uid = android.os.Process.myUid();
-
+ public void onRouteSelectedTest() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
MediaRouter2.Callback mockRouterCallback = mock(MediaRouter2.Callback.class);
InstrumentationRegistry.getInstrumentation().runOnMainSync(
- (Runnable) () -> {
+ () -> {
mRouter.addCallback(TEST_CONTROL_CATEGORIES, mExecutor, mockRouterCallback);
}
);
@@ -163,22 +175,19 @@ public class MediaRouterManagerTest {
public void onRouteAdded(MediaRoute2Info routeInfo) {
if (mSelectedRoute == null) {
mSelectedRoute = routeInfo;
- mManager.selectRoute(uid, mSelectedRoute);
+ mManager.selectRoute(mPackageName, mSelectedRoute);
}
}
@Override
- public void onRouteSelected(int uid, MediaRoute2Info route) {
- if (mSelectedRoute != null && route != null
+ public void onRouteSelected(String packageName, MediaRoute2Info route) {
+ if (TextUtils.equals(packageName, mPackageName)
+ && mSelectedRoute != null
+ && route != null
&& TextUtils.equals(route.getId(), mSelectedRoute.getId())) {
latch.countDown();
}
}
-
- @Override
- public void onControlCategoriesChanged(int uid, List<String> categories) {
-
- }
};
mManager.addCallback(mExecutor, managerCallback);
@@ -187,4 +196,55 @@ public class MediaRouterManagerTest {
mManager.removeCallback(managerCallback);
}
+
+ @Test
+ /**
+ * Tests selecting and unselecting routes of a single provider.
+ */
+ public void testSingleProviderSelect() {
+ MediaRouter2Manager.Callback managerCallback = mock(MediaRouter2Manager.Callback.class);
+ MediaRouter2.Callback routerCallback = mock(MediaRouter2.Callback.class);
+
+ mManager.addCallback(mExecutor, managerCallback);
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(
+ () -> {
+ mRouter.addCallback(TEST_CONTROL_CATEGORIES, mExecutor, routerCallback);
+ }
+ );
+ verify(managerCallback, timeout(TIMEOUT_MS))
+ .onRouteListChanged(argThat(routes -> routes.size() > 0));
+
+ Map<String, MediaRoute2Info> routes =
+ createRouteMap(mManager.getAvailableRoutes(mPackageName));
+
+ mManager.selectRoute(mPackageName, routes.get(ROUTE_ID1));
+ verify(managerCallback, timeout(TIMEOUT_MS))
+ .onRouteChanged(argThat(routeInfo -> TextUtils.equals(ROUTE_ID1, routeInfo.getId())
+ && TextUtils.equals(routeInfo.getClientPackageName(), mPackageName)));
+
+ mManager.selectRoute(mPackageName, routes.get(ROUTE_ID2));
+ verify(managerCallback, timeout(TIMEOUT_MS))
+ .onRouteChanged(argThat(routeInfo -> TextUtils.equals(ROUTE_ID2, routeInfo.getId())
+ && TextUtils.equals(routeInfo.getClientPackageName(), mPackageName)));
+
+ mManager.unselectRoute(mPackageName);
+ verify(managerCallback, timeout(TIMEOUT_MS))
+ .onRouteChanged(argThat(routeInfo -> TextUtils.equals(ROUTE_ID2, routeInfo.getId())
+ && TextUtils.equals(routeInfo.getClientPackageName(), null)));
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(
+ () -> {
+ mRouter.removeCallback(routerCallback);
+ }
+ );
+ mManager.removeCallback(managerCallback);
+ }
+
+ Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) {
+ Map<String, MediaRoute2Info> routeMap = new HashMap<>();
+ for (MediaRoute2Info route : routes) {
+ routeMap.put(route.getId(), route);
+ }
+ return routeMap;
+ }
}
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index 589623b0d6cd..61cab73c226a 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -26,8 +26,8 @@ android_app {
],
static_libs: [
- "CarNotificationLib",
"SystemUI-core",
+ "CarNotificationLib",
"SystemUIPluginLib",
"SystemUISharedLib",
"SettingsLib",
diff --git a/packages/CarSystemUI/res/values-night/colors.xml b/packages/CarSystemUI/res/values-night/colors.xml
index dad94a894603..a2edd7dc5b4e 100644
--- a/packages/CarSystemUI/res/values-night/colors.xml
+++ b/packages/CarSystemUI/res/values-night/colors.xml
@@ -19,6 +19,9 @@
<color name="status_bar_background_color">#ff000000</color>
<color name="system_bar_background_opaque">#ff0c1013</color>
+ <!-- The background color of the notification shade -->
+ <color name="notification_shade_background_color">#E0000000</color>
+
<!-- The color of the ripples on the untinted notifications -->
<color name="notification_ripple_untinted_color">@color/ripple_material_dark</color>
</resources>
diff --git a/packages/CarSystemUI/res/values/colors.xml b/packages/CarSystemUI/res/values/colors.xml
index e13c94052281..e0ae45662390 100644
--- a/packages/CarSystemUI/res/values/colors.xml
+++ b/packages/CarSystemUI/res/values/colors.xml
@@ -35,7 +35,7 @@
<drawable name="system_bar_background">@android:color/transparent</drawable>
<!-- The background color of the notification shade -->
- <color name="notification_shade_background_color">#DD000000</color>
+ <color name="notification_shade_background_color">#D6000000</color>
<!-- The background color of the car volume dialog -->
<color name="car_volume_dialog_background_color">@color/system_bar_background_opaque</color>
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
index 44f0494c69d7..0f4cf21e07c2 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
@@ -118,6 +118,8 @@ public class CarFacetButton extends LinearLayout {
options.setLaunchDisplayId(mContext.getDisplayId());
intent.putExtra(EXTRA_FACET_LAUNCH_PICKER, mSelected);
mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
+ mContext.sendBroadcastAsUser(
+ new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), UserHandle.CURRENT);
});
if (longPressIntentString != null) {
@@ -128,6 +130,8 @@ public class CarFacetButton extends LinearLayout {
options.setLaunchDisplayId(mContext.getDisplayId());
mContext.startActivityAsUser(longPressIntent, options.toBundle(),
UserHandle.CURRENT);
+ mContext.sendBroadcastAsUser(
+ new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), UserHandle.CURRENT);
return true;
});
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
index 1bc1e6f5e94a..9de4ef5eafcb 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
@@ -95,6 +95,9 @@ public class CarNavigationButton extends com.android.keyguard.AlphaOptimizedImag
try {
if (mBroadcastIntent) {
mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
+ mContext.sendBroadcastAsUser(
+ new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS),
+ UserHandle.CURRENT);
return;
}
ActivityOptions options = ActivityOptions.makeBasic();
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 358e2cd4ee33..71b9dc3e923f 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -27,6 +27,7 @@ import android.car.drivingstate.CarDrivingStateEvent;
import android.car.drivingstate.CarUxRestrictionsManager;
import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
import android.content.Context;
+import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -61,9 +62,9 @@ import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.classifier.FalsingLog;
-import com.android.systemui.classifier.FalsingManagerFactory;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.qs.car.CarQSFragment;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -877,7 +878,7 @@ public class CarStatusBar extends StatusBar implements
KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args);
}
- FalsingManagerFactory.getInstance(mContext).dump(pw);
+ Dependency.get(FalsingManager.class).dump(pw);
FalsingLog.dump(pw);
pw.println("SharedPreferences:");
@@ -1078,6 +1079,21 @@ public class CarStatusBar extends StatusBar implements
}
}
+ @Override
+ public void onConfigChanged(Configuration newConfig) {
+ super.onConfigChanged(newConfig);
+
+ int uiModeNightMask = (newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK);
+
+ boolean dayNightModeChanged = uiModeNightMask == Configuration.UI_MODE_NIGHT_YES
+ || uiModeNightMask == Configuration.UI_MODE_NIGHT_NO;
+
+ if (dayNightModeChanged) {
+ mNotificationView.setBackgroundColor(
+ mContext.getColor(R.color.notification_shade_background_color));
+ }
+ }
+
private void calculatePercentageFromBottom(float height) {
if (mNotificationView.getHeight() > 0) {
mPercentageFromBottom = (int) Math.abs(
diff --git a/packages/EasterEgg/AndroidManifest.xml b/packages/EasterEgg/AndroidManifest.xml
index c7dd40d7afdb..7f76a4529963 100644
--- a/packages/EasterEgg/AndroidManifest.xml
+++ b/packages/EasterEgg/AndroidManifest.xml
@@ -1,40 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.egg"
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="28" />
+ <uses-permission android:name="android.permission.WRITE_SETTINGS" />
<application
- android:icon="@drawable/icon"
+ android:icon="@drawable/q_icon"
android:label="@string/app_name">
+ <activity android:name=".quares.QuaresActivity"
+ android:icon="@drawable/q_icon"
+ android:label="@string/q_egg_name"
+ android:theme="@style/QuaresTheme">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <!-- <category android:name="android.intent.category.LAUNCHER" /> -->
+ <category android:name="com.android.internal.category.PLATLOGO" />
+ </intent-filter>
+ </activity>
<activity
android:name=".paint.PaintActivity"
android:configChanges="orientation|keyboardHidden|screenSize|uiMode"
- android:label="@string/app_name"
+ android:icon="@drawable/p_icon"
+ android:label="@string/p_egg_name"
android:theme="@style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.DEFAULT" />
- <!--<category android:name="android.intent.category.LAUNCHER" />-->
- <category android:name="com.android.internal.category.PLATLOGO" />
+
+ <!-- <category android:name="android.intent.category.DEFAULT" /> -->
+ <!-- <category android:name="android.intent.category.LAUNCHER" /> -->
+ <!-- <category android:name="com.android.internal.category.PLATLOGO" /> -->
</intent-filter>
</activity>
</application>
diff --git a/packages/EasterEgg/res/drawable/icon_bg.xml b/packages/EasterEgg/res/drawable/icon_bg.xml
index c1553ce50946..659f98be4f43 100644
--- a/packages/EasterEgg/res/drawable/icon_bg.xml
+++ b/packages/EasterEgg/res/drawable/icon_bg.xml
@@ -15,4 +15,4 @@
limitations under the License.
-->
<color xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="#C5E1A5" /> \ No newline at end of file
+ android:color="@color/q_clue_text" />
diff --git a/packages/EasterEgg/res/drawable/icon.xml b/packages/EasterEgg/res/drawable/p_icon.xml
index 2306b7b554c5..2306b7b554c5 100644
--- a/packages/EasterEgg/res/drawable/icon.xml
+++ b/packages/EasterEgg/res/drawable/p_icon.xml
diff --git a/packages/EasterEgg/res/drawable/pixel_bg.xml b/packages/EasterEgg/res/drawable/pixel_bg.xml
new file mode 100644
index 000000000000..4d4a113cce53
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/pixel_bg.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:exitFadeDuration="100">
+ <item android:state_pressed="true">
+ <shape><solid android:color="@color/red"/></shape>
+ </item>
+ <item android:state_checked="true">
+ <shape><solid android:color="@color/pixel_on"/></shape>
+ </item>
+ <item>
+ <shape><solid android:color="@color/pixel_off"/></shape>
+ </item>
+</selector> \ No newline at end of file
diff --git a/packages/EasterEgg/res/drawable/q.xml b/packages/EasterEgg/res/drawable/q.xml
new file mode 100644
index 000000000000..75baa47e3aa6
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/q.xml
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="@color/q_icon_fg"
+ android:pathData="M19.45,22.89l-10.250001,-10.249999l-2.6599998,2.6599998l-1.77,-1.7600002l4.43,-4.4300003l12.0199995,12.0199995l-1.7699986,1.7600002z"/>
+ <path
+ android:fillColor="@color/q_icon_fg"
+ android:pathData="M12,6a6,6 0,1 1,-6 6,6 6,0 0,1 6,-6m0,-2.5A8.5,8.5 0,1 0,20.5 12,8.51 8.51,0 0,0 12,3.5Z"/>
+</vector>
diff --git a/packages/EasterEgg/res/drawable/q_icon.xml b/packages/EasterEgg/res/drawable/q_icon.xml
new file mode 100644
index 000000000000..ef4b0a362043
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/q_icon.xml
@@ -0,0 +1,19 @@
+<!--
+ 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.
+-->
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/icon_bg"/>
+ <foreground android:drawable="@drawable/q_smaller"/>
+</adaptive-icon>
diff --git a/packages/EasterEgg/res/drawable/q_smaller.xml b/packages/EasterEgg/res/drawable/q_smaller.xml
new file mode 100644
index 000000000000..c71dff094235
--- /dev/null
+++ b/packages/EasterEgg/res/drawable/q_smaller.xml
@@ -0,0 +1,23 @@
+<!--
+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.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:insetBottom="5dp"
+ android:insetLeft="5dp"
+ android:insetRight="5dp"
+ android:insetTop="5dp"
+ android:drawable="@drawable/q" />
diff --git a/packages/EasterEgg/res/layout/activity_quares.xml b/packages/EasterEgg/res/layout/activity_quares.xml
new file mode 100644
index 000000000000..dcc90f6f77ae
--- /dev/null
+++ b/packages/EasterEgg/res/layout/activity_quares.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:animateLayoutChanges="true"
+ tools:context="com.android.egg.quares.QuaresActivity">
+
+ <GridLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:alignmentMode="alignBounds"
+ android:id="@+id/grid"
+ />
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/label"
+ android:layout_gravity="center_horizontal|bottom"
+ android:gravity="center"
+ android:textSize="18dp"
+ android:visibility="gone"
+ android:drawablePadding="8dp"
+ android:padding="12dp"
+ android:backgroundTint="@color/q_clue_bg_correct"
+ android:textColor="@color/q_clue_text"
+ android:layout_marginBottom="48dp"
+ android:elevation="30dp"
+ />
+</FrameLayout>
diff --git a/packages/EasterEgg/res/values-night/q_colors.xml b/packages/EasterEgg/res/values-night/q_colors.xml
new file mode 100644
index 000000000000..191bd944b7dc
--- /dev/null
+++ b/packages/EasterEgg/res/values-night/q_colors.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<resources>
+ <color name="pixel_off">#000000</color>
+ <color name="pixel_on">#FFFFFF</color>
+
+ <color name="q_clue_bg">@color/navy</color>
+ <color name="q_clue_text">@color/tan</color>
+</resources> \ No newline at end of file
diff --git a/packages/EasterEgg/res/values/q_colors.xml b/packages/EasterEgg/res/values/q_colors.xml
new file mode 100644
index 000000000000..5e92c84fd97d
--- /dev/null
+++ b/packages/EasterEgg/res/values/q_colors.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+<resources>
+ <color name="emerald">#3ddc84</color>
+ <color name="red">#f8c734</color>
+ <color name="navy">#073042</color>
+ <color name="vapor">#d7effe</color>
+ <color name="tan">#eff7cf</color>
+
+ <color name="pixel_off">#FFFFFF</color>
+ <color name="pixel_on">#000000</color>
+
+ <color name="q_clue_bg">@color/tan</color>
+ <color name="q_clue_text">@color/navy</color>
+ <color name="q_clue_bg_correct">@color/emerald</color>
+
+ <color name="q_icon_fg">@color/emerald</color>
+</resources>
diff --git a/packages/EasterEgg/res/values/q_puzzles.xml b/packages/EasterEgg/res/values/q_puzzles.xml
new file mode 100644
index 000000000000..7c2eff152ffe
--- /dev/null
+++ b/packages/EasterEgg/res/values/q_puzzles.xml
@@ -0,0 +1,214 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string-array name="puzzles">
+
+ <item>q</item>
+ <item>q</item>
+ <item>q</item>
+ <item>q</item>
+ <item>q</item>
+
+ <item>android:drawable/ic_info</item>
+
+ <item>android:drawable/stat_sys_adb</item>
+ <item>android:drawable/stat_sys_battery</item>
+ <item>android:drawable/stat_sys_phone_call</item>
+ <item>android:drawable/stat_sys_certificate_info</item>
+ <item>android:drawable/stat_sys_data_bluetooth</item>
+ <item>android:drawable/stat_sys_data_usb</item>
+ <item>android:drawable/stat_sys_download</item>
+ <item>android:drawable/stat_sys_gps_on</item>
+ <item>android:drawable/stat_sys_phone_call</item>
+ <item>android:drawable/stat_sys_tether_wifi</item>
+ <item>android:drawable/stat_sys_throttled</item>
+ <item>android:drawable/stat_sys_upload</item>
+
+ <item>android:drawable/stat_notify_car_mode</item>
+ <item>android:drawable/stat_notify_chat</item>
+ <item>android:drawable/stat_notify_disk_full</item>
+ <item>android:drawable/stat_notify_email_generic</item>
+ <item>android:drawable/stat_notify_error</item>
+ <item>android:drawable/stat_notify_gmail</item>
+ <item>android:drawable/stat_notify_missed_call</item>
+ <item>android:drawable/stat_notify_mmcc_indication_icn</item>
+ <item>android:drawable/stat_notify_more</item>
+ <item>android:drawable/stat_notify_rssi_in_range</item>
+ <item>android:drawable/stat_notify_sdcard</item>
+ <item>android:drawable/stat_notify_sdcard_prepare</item>
+ <item>android:drawable/stat_notify_sdcard_usb</item>
+ <item>android:drawable/stat_notify_sim_toolkit</item>
+ <item>android:drawable/stat_notify_sync</item>
+ <item>android:drawable/stat_notify_sync_anim0</item>
+ <item>android:drawable/stat_notify_sync_error</item>
+ <item>android:drawable/stat_notify_voicemail</item>
+
+ <item>android:drawable/ic_audio_alarm</item>
+ <item>android:drawable/ic_audio_alarm_mute</item>
+ <item>android:drawable/ic_bluetooth_share_icon</item>
+ <item>android:drawable/ic_bt_headphones_a2dp</item>
+ <item>android:drawable/ic_bt_headset_hfp</item>
+ <item>android:drawable/ic_bt_hearing_aid</item>
+ <item>android:drawable/ic_bt_laptop</item>
+ <item>android:drawable/ic_bt_misc_hid</item>
+ <item>android:drawable/ic_bt_network_pan</item>
+ <item>android:drawable/ic_bt_pointing_hid</item>
+ <item>android:drawable/ic_corp_badge</item>
+ <item>android:drawable/ic_expand_more</item>
+ <item>android:drawable/ic_faster_emergency</item>
+ <item>android:drawable/ic_file_copy</item>
+ <item>android:drawable/ic_info_outline_24</item>
+ <item>android:drawable/ic_lock</item>
+ <item>android:drawable/ic_lock_bugreport</item>
+ <item>android:drawable/ic_lock_open</item>
+ <item>android:drawable/ic_lock_power_off</item>
+ <item>android:drawable/ic_lockscreen_ime</item>
+ <item>android:drawable/ic_mode_edit</item>
+ <item>android:drawable/ic_phone</item>
+ <item>android:drawable/ic_qs_airplane</item>
+ <item>android:drawable/ic_qs_auto_rotate</item>
+ <item>android:drawable/ic_qs_battery_saver</item>
+ <item>android:drawable/ic_qs_bluetooth</item>
+ <item>android:drawable/ic_qs_dnd</item>
+ <item>android:drawable/ic_qs_flashlight</item>
+ <item>android:drawable/ic_qs_night_display_on</item>
+ <item>android:drawable/ic_restart</item>
+ <item>android:drawable/ic_screenshot</item>
+ <item>android:drawable/ic_settings_bluetooth</item>
+ <item>android:drawable/ic_signal_cellular_0_4_bar</item>
+ <item>android:drawable/ic_signal_cellular_0_5_bar</item>
+ <item>android:drawable/ic_signal_cellular_1_4_bar</item>
+ <item>android:drawable/ic_signal_cellular_1_5_bar</item>
+ <item>android:drawable/ic_signal_cellular_2_4_bar</item>
+ <item>android:drawable/ic_signal_cellular_2_5_bar</item>
+ <item>android:drawable/ic_signal_cellular_3_4_bar</item>
+ <item>android:drawable/ic_signal_cellular_3_5_bar</item>
+ <item>android:drawable/ic_signal_cellular_4_4_bar</item>
+ <item>android:drawable/ic_signal_cellular_4_5_bar</item>
+ <item>android:drawable/ic_signal_cellular_5_5_bar</item>
+ <item>android:drawable/ic_signal_location</item>
+ <item>android:drawable/ic_wifi_signal_0</item>
+ <item>android:drawable/ic_wifi_signal_1</item>
+ <item>android:drawable/ic_wifi_signal_2</item>
+ <item>android:drawable/ic_wifi_signal_3</item>
+ <item>android:drawable/ic_wifi_signal_4</item>
+ <item>android:drawable/perm_group_activity_recognition</item>
+ <item>android:drawable/perm_group_calendar</item>
+ <item>android:drawable/perm_group_call_log</item>
+ <item>android:drawable/perm_group_camera</item>
+ <item>android:drawable/perm_group_contacts</item>
+ <item>android:drawable/perm_group_location</item>
+ <item>android:drawable/perm_group_microphone</item>
+ <item>android:drawable/perm_group_phone_calls</item>
+ <item>android:drawable/perm_group_sensors</item>
+ <item>android:drawable/perm_group_sms</item>
+ <item>android:drawable/perm_group_storage</item>
+ <item>android:drawable/perm_group_visual</item>
+
+ <item>com.android.settings:drawable/ic_add_24dp</item>
+ <item>com.android.settings:drawable/ic_airplanemode_active</item>
+ <item>com.android.settings:drawable/ic_android</item>
+ <item>com.android.settings:drawable/ic_apps</item>
+ <item>com.android.settings:drawable/ic_arrow_back</item>
+ <item>com.android.settings:drawable/ic_arrow_down_24dp</item>
+ <item>com.android.settings:drawable/ic_battery_charging_full</item>
+ <item>com.android.settings:drawable/ic_battery_status_bad_24dp</item>
+ <item>com.android.settings:drawable/ic_battery_status_good_24dp</item>
+ <item>com.android.settings:drawable/ic_battery_status_maybe_24dp</item>
+ <item>com.android.settings:drawable/ic_call_24dp</item>
+ <item>com.android.settings:drawable/ic_cancel</item>
+ <item>com.android.settings:drawable/ic_cast_24dp</item>
+ <item>com.android.settings:drawable/ic_chevron_right_24dp</item>
+ <item>com.android.settings:drawable/ic_data_saver</item>
+ <item>com.android.settings:drawable/ic_delete</item>
+ <item>com.android.settings:drawable/ic_devices_other</item>
+ <item>com.android.settings:drawable/ic_devices_other_opaque_black</item>
+ <item>com.android.settings:drawable/ic_do_not_disturb_on_24dp</item>
+ <item>com.android.settings:drawable/ic_eject_24dp</item>
+ <item>com.android.settings:drawable/ic_expand_less</item>
+ <item>com.android.settings:drawable/ic_expand_more_inverse</item>
+ <item>com.android.settings:drawable/ic_folder_vd_theme_24</item>
+ <item>com.android.settings:drawable/ic_friction_lock_closed</item>
+ <item>com.android.settings:drawable/ic_gray_scale_24dp</item>
+ <item>com.android.settings:drawable/ic_headset_24dp</item>
+ <item>com.android.settings:drawable/ic_help</item>
+ <item>com.android.settings:drawable/ic_local_movies</item>
+ <item>com.android.settings:drawable/ic_lock</item>
+ <item>com.android.settings:drawable/ic_media_stream</item>
+ <item>com.android.settings:drawable/ic_network_cell</item>
+ <item>com.android.settings:drawable/ic_notifications</item>
+ <item>com.android.settings:drawable/ic_notifications_off_24dp</item>
+ <item>com.android.settings:drawable/ic_phone_info</item>
+ <item>com.android.settings:drawable/ic_photo_library</item>
+ <item>com.android.settings:drawable/ic_settings_accessibility</item>
+ <item>com.android.settings:drawable/ic_settings_accounts</item>
+ <item>com.android.settings:drawable/ic_settings_backup</item>
+ <item>com.android.settings:drawable/ic_settings_battery_white</item>
+ <item>com.android.settings:drawable/ic_settings_data_usage</item>
+ <item>com.android.settings:drawable/ic_settings_date_time</item>
+ <item>com.android.settings:drawable/ic_settings_delete</item>
+ <item>com.android.settings:drawable/ic_settings_display_white</item>
+ <item>com.android.settings:drawable/ic_settings_home</item>
+ <item>com.android.settings:drawable/ic_settings_location</item>
+ <item>com.android.settings:drawable/ic_settings_night_display</item>
+ <item>com.android.settings:drawable/ic_settings_open</item>
+ <item>com.android.settings:drawable/ic_settings_print</item>
+ <item>com.android.settings:drawable/ic_settings_privacy</item>
+ <item>com.android.settings:drawable/ic_settings_security_white</item>
+ <item>com.android.settings:drawable/ic_settings_sim</item>
+ <item>com.android.settings:drawable/ic_settings_wireless</item>
+ <item>com.android.settings:drawable/ic_storage</item>
+ <item>com.android.settings:drawable/ic_storage_white</item>
+ <item>com.android.settings:drawable/ic_suggestion_night_display</item>
+ <item>com.android.settings:drawable/ic_sync</item>
+ <item>com.android.settings:drawable/ic_system_update</item>
+ <item>com.android.settings:drawable/ic_videogame_vd_theme_24</item>
+ <item>com.android.settings:drawable/ic_volume_ringer_vibrate</item>
+ <item>com.android.settings:drawable/ic_volume_up_24dp</item>
+ <item>com.android.settings:drawable/ic_vpn_key</item>
+ <item>com.android.settings:drawable/ic_wifi_tethering</item>
+
+ <item>com.android.systemui:drawable/ic_alarm</item>
+ <item>com.android.systemui:drawable/ic_alarm_dim</item>
+ <item>com.android.systemui:drawable/ic_arrow_back</item>
+ <item>com.android.systemui:drawable/ic_bluetooth_connected</item>
+ <item>com.android.systemui:drawable/ic_brightness_thumb</item>
+ <item>com.android.systemui:drawable/ic_camera</item>
+ <item>com.android.systemui:drawable/ic_cast</item>
+ <item>com.android.systemui:drawable/ic_cast_connected</item>
+ <item>com.android.systemui:drawable/ic_cast_connected_fill</item>
+ <item>com.android.systemui:drawable/ic_close_white</item>
+ <item>com.android.systemui:drawable/ic_data_saver</item>
+ <item>com.android.systemui:drawable/ic_data_saver_off</item>
+ <item>com.android.systemui:drawable/ic_drag_handle</item>
+ <item>com.android.systemui:drawable/ic_headset</item>
+ <item>com.android.systemui:drawable/ic_headset_mic</item>
+ <item>com.android.systemui:drawable/ic_hotspot</item>
+ <item>com.android.systemui:drawable/ic_invert_colors</item>
+ <item>com.android.systemui:drawable/ic_location</item>
+ <item>com.android.systemui:drawable/ic_lockscreen_ime</item>
+ <item>com.android.systemui:drawable/ic_notifications_alert</item>
+ <item>com.android.systemui:drawable/ic_notifications_silence</item>
+ <item>com.android.systemui:drawable/ic_power_low</item>
+ <item>com.android.systemui:drawable/ic_power_saver</item>
+ <item>com.android.systemui:drawable/ic_qs_bluetooth_connecting</item>
+ <item>com.android.systemui:drawable/ic_qs_bluetooth_on</item>
+ <item>com.android.systemui:drawable/ic_qs_cancel</item>
+ <item>com.android.systemui:drawable/ic_qs_no_sim</item>
+ <item>com.android.systemui:drawable/ic_screenshot_delete</item>
+ <item>com.android.systemui:drawable/ic_settings</item>
+ <item>com.android.systemui:drawable/ic_swap_vert</item>
+ <item>com.android.systemui:drawable/ic_volume_alarm</item>
+ <item>com.android.systemui:drawable/ic_volume_alarm_mute</item>
+ <item>com.android.systemui:drawable/ic_volume_media</item>
+ <item>com.android.systemui:drawable/ic_volume_media_mute</item>
+ <item>com.android.systemui:drawable/ic_volume_ringer</item>
+ <item>com.android.systemui:drawable/ic_volume_ringer_mute</item>
+ <item>com.android.systemui:drawable/ic_volume_ringer_vibrate</item>
+ <item>com.android.systemui:drawable/ic_volume_voice</item>
+ <item>com.android.systemui:drawable/stat_sys_camera</item>
+ <item>com.android.systemui:drawable/stat_sys_managed_profile_status</item>
+ <item>com.android.systemui:drawable/stat_sys_mic_none</item>
+ <item>com.android.systemui:drawable/stat_sys_vpn_ic</item>
+
+ </string-array>
+</resources>
diff --git a/packages/EasterEgg/res/values/strings.xml b/packages/EasterEgg/res/values/strings.xml
index 32dbc97a00fb..b95ec6be4c84 100644
--- a/packages/EasterEgg/res/values/strings.xml
+++ b/packages/EasterEgg/res/values/strings.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
Copyright (C) 2018 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,5 +14,11 @@ Copyright (C) 2018 The Android Open Source Project
limitations under the License.
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <string name="app_name" translatable="false">PAINT.APK</string>
+ <string name="app_name" translatable="false">Android Q Easter Egg</string>
+
+ <!-- name of the Q easter egg, a nonogram-style icon puzzle -->
+ <string name="q_egg_name" translatable="false">Icon Quiz</string>
+
+ <!-- name of the P easter egg, a humble paint program -->
+ <string name="p_egg_name" translatable="false">PAINT.APK</string>
</resources>
diff --git a/packages/EasterEgg/res/values/styles.xml b/packages/EasterEgg/res/values/styles.xml
index 44e2ce52aab8..e576526f49b7 100644
--- a/packages/EasterEgg/res/values/styles.xml
+++ b/packages/EasterEgg/res/values/styles.xml
@@ -20,4 +20,16 @@
<item name="android:windowLightNavigationBar">true</item>
</style>
+ <style name="QuaresTheme" parent="@android:style/Theme.DeviceDefault.DayNight">
+ <item name="android:windowIsTranslucent">true</item>
+ <item name="android:windowBackground">@android:color/transparent</item>
+ <item name="android:colorBackgroundCacheHint">@null</item>
+ <item name="android:windowShowWallpaper">true</item>
+ <item name="android:windowContentOverlay">@null</item>
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowFullscreen">true</item>
+ <item name="android:statusBarColor">@android:color/transparent</item>
+ <item name="android:navigationBarColor">@android:color/transparent</item>
+ </style>
+
</resources>
diff --git a/packages/EasterEgg/src/com/android/egg/quares/Quare.kt b/packages/EasterEgg/src/com/android/egg/quares/Quare.kt
new file mode 100644
index 000000000000..eb77362a0be2
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/quares/Quare.kt
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.egg.quares
+
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.Icon
+import android.os.Parcel
+import android.os.Parcelable
+import java.util.ArrayList
+import kotlin.math.abs
+import kotlin.math.round
+
+class Quare(val width: Int, val height: Int, val depth: Int) : Parcelable {
+ private val data: IntArray = IntArray(width * height)
+ private val user: IntArray = data.copyOf()
+
+ private fun loadAndQuantize(bitmap8bpp: Bitmap) {
+ bitmap8bpp.getPixels(data, 0, width, 0, 0, width, height)
+ if (depth == 8) return
+ val s = (255f / depth)
+ for (i in 0 until data.size) {
+ var f = (data[i] ushr 24).toFloat() / s
+ // f = f.pow(0.75f) // gamma adjust for bolder lines
+ f *= 1.25f // brightness adjust for bolder lines
+ f.coerceAtMost(1f)
+ data[i] = (round(f) * s).toInt() shl 24
+ }
+ }
+
+ fun isBlank(): Boolean {
+ return data.sum() == 0
+ }
+
+ fun load(drawable: Drawable) {
+ val resized = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8)
+ val canvas = Canvas(resized)
+ drawable.setBounds(0, 0, width, height)
+ drawable.setTint(0xFF000000.toInt())
+ drawable.draw(canvas)
+ loadAndQuantize(resized)
+ resized.recycle()
+ }
+
+ fun load(context: Context, icon: Icon) {
+ icon.loadDrawable(context)?.let {
+ load(it)
+ }
+ }
+
+ fun bitmap(): Bitmap {
+ return Bitmap.createBitmap(data, width, height, Bitmap.Config.ALPHA_8)
+ }
+
+ fun getUserMark(x: Int, y: Int): Int {
+ return user[y * width + x] ushr 24
+ }
+
+ fun setUserMark(x: Int, y: Int, v: Int) {
+ user[y * width + x] = v shl 24
+ }
+
+ fun getDataAt(x: Int, y: Int): Int {
+ return data[y * width + x] ushr 24
+ }
+
+ fun check(): Boolean {
+ return data.contentEquals(user)
+ }
+
+ fun check(xSel: Int, ySel: Int): Boolean {
+ val xStart = if (xSel < 0) 0 else xSel
+ val xEnd = if (xSel < 0) width - 1 else xSel
+ val yStart = if (ySel < 0) 0 else ySel
+ val yEnd = if (ySel < 0) height - 1 else ySel
+ for (y in yStart..yEnd)
+ for (x in xStart..xEnd)
+ if (getDataAt(x, y) != getUserMark(x, y)) return false
+ return true
+ }
+
+ fun errors(): IntArray {
+ return IntArray(width * height) {
+ abs(data[it] - user[it])
+ }
+ }
+
+ fun getRowClue(y: Int): IntArray {
+ return getClue(-1, y)
+ }
+ fun getColumnClue(x: Int): IntArray {
+ return getClue(x, -1)
+ }
+ fun getClue(xSel: Int, ySel: Int): IntArray {
+ val arr = ArrayList<Int>()
+ var len = 0
+ val xStart = if (xSel < 0) 0 else xSel
+ val xEnd = if (xSel < 0) width - 1 else xSel
+ val yStart = if (ySel < 0) 0 else ySel
+ val yEnd = if (ySel < 0) height - 1 else ySel
+ for (y in yStart..yEnd)
+ for (x in xStart..xEnd)
+ if (getDataAt(x, y) != 0) {
+ len++
+ } else if (len > 0) {
+ arr.add(len)
+ len = 0
+ }
+ if (len > 0) arr.add(len)
+ else if (arr.size == 0) arr.add(0)
+ return arr.toIntArray()
+ }
+
+ fun resetUserMarks() {
+ user.forEachIndexed { index, _ -> user[index] = 0 }
+ }
+
+ // Parcelable interface
+
+ override fun describeContents(): Int {
+ return 0
+ }
+
+ override fun writeToParcel(p: Parcel?, flags: Int) {
+ p?.let {
+ p.writeInt(width)
+ p.writeInt(height)
+ p.writeInt(depth)
+ p.writeIntArray(data)
+ p.writeIntArray(user)
+ }
+ }
+
+ companion object CREATOR : Parcelable.Creator<Quare> {
+ override fun createFromParcel(p: Parcel?): Quare {
+ return p!!.let {
+ Quare(
+ p.readInt(), // width
+ p.readInt(), // height
+ p.readInt() // depth
+ ).also {
+ p.readIntArray(it.data)
+ p.readIntArray(it.user)
+ }
+ }
+ }
+
+ override fun newArray(size: Int): Array<Quare?> {
+ return arrayOfNulls(size)
+ }
+ }
+}
diff --git a/packages/EasterEgg/src/com/android/egg/quares/QuaresActivity.kt b/packages/EasterEgg/src/com/android/egg/quares/QuaresActivity.kt
new file mode 100644
index 000000000000..ce439a9a663c
--- /dev/null
+++ b/packages/EasterEgg/src/com/android/egg/quares/QuaresActivity.kt
@@ -0,0 +1,312 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.egg.quares
+
+import android.app.Activity
+import android.content.Context
+import android.content.res.Configuration
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.Typeface
+import android.graphics.drawable.Icon
+import android.os.Bundle
+import android.text.StaticLayout
+import android.text.TextPaint
+import android.util.Log
+import android.view.View
+import android.view.View.GONE
+import android.view.View.VISIBLE
+import android.widget.Button
+import android.widget.CompoundButton
+import android.widget.GridLayout
+
+import java.util.Random
+
+import com.android.egg.R
+
+const val TAG = "Quares"
+
+class QuaresActivity : Activity() {
+ private var q: Quare = Quare(16, 16, 1)
+ private var resId = 0
+ private var resName = ""
+ private var icon: Icon? = null
+
+ private lateinit var label: Button
+ private lateinit var grid: GridLayout
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ window.decorView.systemUiVisibility =
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+
+ actionBar?.hide()
+
+ setContentView(R.layout.activity_quares)
+
+ grid = findViewById(R.id.grid)
+ label = findViewById(R.id.label)
+
+ if (savedInstanceState != null) {
+ Log.v(TAG, "restoring puzzle from state")
+ q = savedInstanceState.getParcelable("q") ?: q
+ resId = savedInstanceState.getInt("resId")
+ resName = savedInstanceState.getString("resName", "")
+ loadPuzzle()
+ }
+
+ label.setOnClickListener { newPuzzle() }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ if (resId == 0) {
+ // lazy init from onCreate
+ newPuzzle()
+ }
+ checkVictory()
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+
+ outState.putParcelable("q", q)
+ outState.putInt("resId", resId)
+ outState.putString("resName", resName)
+ }
+
+ fun newPuzzle() {
+ Log.v(TAG, "new puzzle...")
+
+ q.resetUserMarks()
+ val oldResId = resId
+ resId = android.R.drawable.stat_sys_warning
+ try {
+ for (tries in 0..3) {
+ val ar = resources.obtainTypedArray(R.array.puzzles)
+ val newName = ar.getString(Random().nextInt(ar.length()))
+ if (newName == null) continue
+
+ Log.v(TAG, "Looking for icon " + newName)
+
+ val pkg = getPackageNameForResourceName(newName)
+ val newId = packageManager.getResourcesForApplication(pkg)
+ .getIdentifier(newName, "drawable", pkg)
+ if (newId == 0) {
+ Log.v(TAG, "oops, " + newName + " doesn't resolve from pkg " + pkg)
+ } else if (newId != oldResId) {
+ // got a good one
+ resId = newId
+ resName = newName
+ break
+ }
+ }
+ } catch (e: RuntimeException) {
+ Log.v(TAG, "problem loading puzzle, using fallback", e)
+ }
+ loadPuzzle()
+ }
+
+ fun getPackageNameForResourceName(name: String): String {
+ return if (name.contains(":") && !name.startsWith("android:")) {
+ name.substring(0, name.indexOf(":"))
+ } else {
+ packageName
+ }
+ }
+
+ fun checkVictory() {
+ if (q.check()) {
+ val dp = resources.displayMetrics.density
+
+ val label: Button = findViewById(R.id.label)
+ label.text = resName.replace(Regex("^.*/"), "")
+ val drawable = icon?.loadDrawable(this)?.also {
+ it.setBounds(0, 0, (32 * dp).toInt(), (32 * dp).toInt())
+ it.setTint(label.currentTextColor)
+ }
+ label.setCompoundDrawables(drawable, null, null, null)
+
+ label.visibility = VISIBLE
+ } else {
+ label.visibility = GONE
+ }
+ }
+
+ fun loadPuzzle() {
+ Log.v(TAG, "loading " + resName + " at " + q.width + "x" + q.height)
+
+ val dp = resources.displayMetrics.density
+
+ icon = Icon.createWithResource(getPackageNameForResourceName(resName), resId)
+ q.load(this, icon!!)
+
+ if (q.isBlank()) {
+ // this is a really boring puzzle, let's try again
+ resId = 0
+ resName = ""
+ recreate()
+ return
+ }
+
+ grid.removeAllViews()
+ grid.columnCount = q.width + 1
+ grid.rowCount = q.height + 1
+
+ label.visibility = GONE
+
+ val orientation = resources.configuration.orientation
+
+ // clean this up a bit
+ val minSide = resources.configuration.smallestScreenWidthDp - 25 // ish
+ val size = (minSide / (q.height + 0.5) * dp).toInt()
+
+ val sb = StringBuffer()
+
+ for (j in 0 until grid.rowCount) {
+ for (i in 0 until grid.columnCount) {
+ val tv: View
+ val params = GridLayout.LayoutParams().also {
+ it.width = size
+ it.height = size
+ it.setMargins(1, 1, 1, 1)
+ it.rowSpec = GridLayout.spec(GridLayout.UNDEFINED, GridLayout.TOP) // UGH
+ }
+ val x = i - 1
+ val y = j - 1
+ if (i > 0 && j > 0) {
+ if (i == 1 && j > 1) sb.append("\n")
+ sb.append(if (q.getDataAt(x, y) == 0) " " else "X")
+ tv = PixelButton(this)
+ tv.isChecked = q.getUserMark(x, y) != 0
+ tv.setOnClickListener {
+ q.setUserMark(x, y, if (tv.isChecked) 0xFF else 0)
+ val columnCorrect = (grid.getChildAt(i) as? ClueView)?.check(q) ?: false
+ val rowCorrect = (grid.getChildAt(j*(grid.columnCount)) as? ClueView)
+ ?.check(q) ?: false
+ if (columnCorrect && rowCorrect) {
+ checkVictory()
+ } else {
+ label.visibility = GONE
+ }
+ }
+ } else if (i == j) { // 0,0
+ tv = View(this)
+ tv.visibility = GONE
+ } else {
+ tv = ClueView(this)
+ if (j == 0) {
+ tv.textRotation = 90f
+ if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ params.height /= 2
+ tv.showText = false
+ } else {
+ params.height = (96 * dp).toInt()
+ }
+ if (x >= 0) {
+ tv.setColumn(q, x)
+ }
+ }
+ if (i == 0) {
+ if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ params.width /= 2
+ tv.showText = false
+ } else {
+ params.width = (96 * dp).toInt()
+ }
+ if (y >= 0) {
+ tv.setRow(q, y)
+ }
+ }
+ }
+ grid.addView(tv, params)
+ }
+ }
+
+ Log.v(TAG, "icon: \n" + sb)
+ }
+}
+
+class PixelButton(context: Context) : CompoundButton(context) {
+ init {
+ setBackgroundResource(R.drawable.pixel_bg)
+ isClickable = true
+ isEnabled = true
+ }
+}
+
+class ClueView(context: Context) : View(context) {
+ var row: Int = -1
+ var column: Int = -1
+ var textRotation: Float = 0f
+ var text: CharSequence = ""
+ var showText = true
+ val paint: TextPaint
+ val incorrectColor: Int
+ val correctColor: Int
+
+ init {
+ setBackgroundColor(0)
+ paint = TextPaint().also {
+ it.textSize = 14f * context.resources.displayMetrics.density
+ it.color = context.getColor(R.color.q_clue_text)
+ it.typeface = Typeface.DEFAULT_BOLD
+ it.textAlign = Paint.Align.CENTER
+ }
+ incorrectColor = context.getColor(R.color.q_clue_bg)
+ correctColor = context.getColor(R.color.q_clue_bg_correct)
+ }
+
+ fun setRow(q: Quare, row: Int): Boolean {
+ this.row = row
+ this.column = -1
+ this.textRotation = 0f
+ text = q.getRowClue(row).joinToString("-")
+ return check(q)
+ }
+ fun setColumn(q: Quare, column: Int): Boolean {
+ this.column = column
+ this.row = -1
+ this.textRotation = 90f
+ text = q.getColumnClue(column).joinToString("-")
+ return check(q)
+ }
+ fun check(q: Quare): Boolean {
+ val correct = q.check(column, row)
+ setBackgroundColor(if (correct) correctColor else incorrectColor)
+ return correct
+ }
+
+ override fun onDraw(canvas: Canvas?) {
+ super.onDraw(canvas)
+ if (!showText) return
+ canvas?.let {
+ val x = canvas.width / 2f
+ val y = canvas.height / 2f
+ var textWidth = canvas.width
+ if (textRotation != 0f) {
+ canvas.rotate(textRotation, x, y)
+ textWidth = canvas.height
+ }
+ val textLayout = StaticLayout.Builder.obtain(
+ text, 0, text.length, paint, textWidth).build()
+ canvas.translate(x, y - textLayout.height / 2)
+ textLayout.draw(canvas)
+ }
+ }
+}
diff --git a/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml b/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml
index 96046ad5f3df..35de8ef46508 100644
--- a/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml
+++ b/packages/ExternalStorageProvider/res/values-pt-rPT/strings.xml
@@ -19,5 +19,5 @@
<string name="app_label" msgid="7123375275748530234">"Armazenamento externo"</string>
<string name="storage_description" msgid="8541974407321172792">"Armazenamento local"</string>
<string name="root_internal_storage" msgid="827844243068584127">"Armazenamento interno"</string>
- <string name="root_documents" msgid="4051252304075469250">"Documentos"</string>
+ <string name="root_documents" msgid="4051252304075469250">"Docs"</string>
</resources>
diff --git a/packages/SettingsLib/AppPreference/res/layout/preference_app.xml b/packages/SettingsLib/AppPreference/res/layout/preference_app.xml
index dbc51958ae0b..8c208e35a371 100644
--- a/packages/SettingsLib/AppPreference/res/layout/preference_app.xml
+++ b/packages/SettingsLib/AppPreference/res/layout/preference_app.xml
@@ -61,6 +61,7 @@
android:id="@android:id/summary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:textDirection="locale"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"/>
diff --git a/packages/SettingsLib/OWNERS b/packages/SettingsLib/OWNERS
index d87908738b56..a28ba8584054 100644
--- a/packages/SettingsLib/OWNERS
+++ b/packages/SettingsLib/OWNERS
@@ -1,21 +1,13 @@
# People who can approve changes for submission
-asapperstein@google.com
-asargent@google.com
-dehboxturtle@google.com
-dhnishi@google.com
-dling@google.com
dsandler@android.com
+edgarwang@google.com
+emilychuang@google.com
evanlaird@google.com
-jackqdyulei@google.com
-jmonk@google.com
leifhendrik@google.com
-mfritze@google.com
-rogerxue@google.com
+rafftsai@google.com
+tmfang@google.com
virgild@google.com
zhfan@google.com
-# Emergency approvers in case the above are not available
-miket@google.com
-
# Exempt resource files (because they are in a flat directory and too hard to manage via OWNERS)
per-file *.xml=*
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 57f5d5a5f614..63463b1b31f1 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -408,7 +408,7 @@
<string name="battery_info_status_charging" msgid="1705179948350365604">"Charging"</string>
<string name="battery_info_status_charging_lower" msgid="8689770213898117994">"charging"</string>
<string name="battery_info_status_discharging" msgid="310932812698268588">"Not charging"</string>
- <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Plugged in, can\'t charge right now"</string>
+ <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Plugged in, can\'t charge at the moment"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Full"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlled by admin"</string>
<string name="disabled" msgid="9206776641295849915">"Disabled"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 57f5d5a5f614..63463b1b31f1 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -408,7 +408,7 @@
<string name="battery_info_status_charging" msgid="1705179948350365604">"Charging"</string>
<string name="battery_info_status_charging_lower" msgid="8689770213898117994">"charging"</string>
<string name="battery_info_status_discharging" msgid="310932812698268588">"Not charging"</string>
- <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Plugged in, can\'t charge right now"</string>
+ <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Plugged in, can\'t charge at the moment"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Full"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlled by admin"</string>
<string name="disabled" msgid="9206776641295849915">"Disabled"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 57f5d5a5f614..63463b1b31f1 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -408,7 +408,7 @@
<string name="battery_info_status_charging" msgid="1705179948350365604">"Charging"</string>
<string name="battery_info_status_charging_lower" msgid="8689770213898117994">"charging"</string>
<string name="battery_info_status_discharging" msgid="310932812698268588">"Not charging"</string>
- <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Plugged in, can\'t charge right now"</string>
+ <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Plugged in, can\'t charge at the moment"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Full"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlled by admin"</string>
<string name="disabled" msgid="9206776641295849915">"Disabled"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 57f5d5a5f614..63463b1b31f1 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -408,7 +408,7 @@
<string name="battery_info_status_charging" msgid="1705179948350365604">"Charging"</string>
<string name="battery_info_status_charging_lower" msgid="8689770213898117994">"charging"</string>
<string name="battery_info_status_discharging" msgid="310932812698268588">"Not charging"</string>
- <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Plugged in, can\'t charge right now"</string>
+ <string name="battery_info_status_not_charging" msgid="8523453668342598579">"Plugged in, can\'t charge at the moment"</string>
<string name="battery_info_status_full" msgid="2824614753861462808">"Full"</string>
<string name="disabled_by_admin_summary_text" msgid="6750513964908334617">"Controlled by admin"</string>
<string name="disabled" msgid="9206776641295849915">"Disabled"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 798ea3c80cb0..7fe1ef9213ed 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -293,8 +293,8 @@
<string name="strict_mode_summary" msgid="142834318897332338">"Kedipkan layar saat apl beroperasi lama pada utas utama"</string>
<string name="pointer_location" msgid="6084434787496938001">"Lokasi penunjuk"</string>
<string name="pointer_location_summary" msgid="840819275172753713">"Hamparan layar menampilkan data sentuhan saat ini"</string>
- <string name="show_touches" msgid="2642976305235070316">"Tampilkan tap"</string>
- <string name="show_touches_summary" msgid="6101183132903926324">"Tampilkan masukan visual untuk tap"</string>
+ <string name="show_touches" msgid="2642976305235070316">"Tampilkan ketukan"</string>
+ <string name="show_touches_summary" msgid="6101183132903926324">"Tampilkan masukan untuk ketukan"</string>
<string name="show_screen_updates" msgid="5470814345876056420">"Lihat pembaruan permukaan"</string>
<string name="show_screen_updates_summary" msgid="2569622766672785529">"Sorot seluruh permukaan jendela saat diperbarui"</string>
<string name="show_hw_screen_updates" msgid="4117270979975470789">"Tampilkan update tampilan"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 4b38383545e5..7a054bbec646 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -307,7 +307,7 @@
<string name="simulate_color_space" msgid="6745847141353345872">"Simulo hapësirën e ngjyrës"</string>
<string name="enable_opengl_traces_title" msgid="6790444011053219871">"Aktivizo gjurmët e OpenGL-së"</string>
<string name="usb_audio_disable_routing" msgid="8114498436003102671">"Çaktivizo rrugëzuezin e audios përmes USB-së"</string>
- <string name="usb_audio_disable_routing_summary" msgid="980282760277312264">"Çaktivizo rrugëzuesin automatik për te kufjet ose altoparlantët"</string>
+ <string name="usb_audio_disable_routing_summary" msgid="980282760277312264">"Çaktivizo router-in automatik për te kufjet ose altoparlantët"</string>
<string name="debug_layout" msgid="5981361776594526155">"Shfaq konturet e kuadrit"</string>
<string name="debug_layout_summary" msgid="2001775315258637682">"Shfaq konturet e klipit, hapësirat etj."</string>
<string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Detyro drejtimin e shkrimit nga e djathta në të majtë"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
index 7f906f6c5b06..6d874ab2be9b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
@@ -117,7 +117,7 @@ public class HidProfile implements LocalBluetoothProfile {
public boolean isPreferred(BluetoothDevice device) {
if (mService == null) return false;
- return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+ return mService.getPriority(device) != BluetoothProfile.PRIORITY_OFF;
}
public int getPreferred(BluetoothDevice device) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java
index 0b6996365372..ac7a12187fd6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java
+++ b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java
@@ -38,7 +38,7 @@ public class LicenseHtmlLoaderCompat extends AsyncLoaderCompat<File> {
"/odm/etc/NOTICE.xml.gz",
"/oem/etc/NOTICE.xml.gz",
"/product/etc/NOTICE.xml.gz",
- "/product_services/etc/NOTICE.xml.gz"};
+ "/system_ext/etc/NOTICE.xml.gz"};
static final String NOTICE_HTML_FILE_NAME = "NOTICE.html";
private final Context mContext;
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java
index de38e8a366b4..b15ea980ae15 100644
--- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java
@@ -18,15 +18,11 @@ package com.android.settingslib.net;
import android.content.Context;
import android.net.NetworkTemplate;
-import android.os.ParcelUuid;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;
-import java.util.ArrayList;
-import java.util.List;
-
/**
* Utils class for data usage
*/
@@ -38,7 +34,7 @@ public class DataUsageUtils {
*/
public static NetworkTemplate getMobileTemplate(Context context, int subId) {
final TelephonyManager telephonyManager = context.getSystemService(
- TelephonyManager.class);
+ TelephonyManager.class).createForSubscriptionId(subId);
final SubscriptionManager subscriptionManager = context.getSystemService(
SubscriptionManager.class);
final SubscriptionInfo info = subscriptionManager.getActiveSubscriptionInfo(subId);
@@ -49,23 +45,8 @@ public class DataUsageUtils {
Log.i(TAG, "Subscription is not active: " + subId);
return mobileAll;
}
- final ParcelUuid groupUuid = info.getGroupUuid();
- if (groupUuid == null) {
- Log.i(TAG, "Subscription doesn't have valid group uuid: " + subId);
- return mobileAll;
- }
- // Otherwise merge other subscriberId to create new NetworkTemplate
- final List<SubscriptionInfo> groupInfos = subscriptionManager.getSubscriptionsInGroup(
- groupUuid);
- final List<String> mergedSubscriberIds = new ArrayList<>();
- for (SubscriptionInfo subInfo : groupInfos) {
- final String subscriberId = telephonyManager.getSubscriberId(
- subInfo.getSubscriptionId());
- if (subscriberId != null) {
- mergedSubscriberIds.add(subscriberId);
- }
- }
- return NetworkTemplate.normalize(mobileAll, mergedSubscriberIds.toArray(new String[0]));
+ // Use old API to build networkTemplate
+ return NetworkTemplate.normalize(mobileAll, telephonyManager.getMergedSubscriberIds());
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java
index dc33cfe4b2f8..821c0b3a23f7 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java
@@ -44,7 +44,6 @@ import java.util.List;
public class DataUsageUtilsTest {
private static final int SUB_ID = 1;
- private static final int SUB_ID_2 = 2;
private static final String SUBSCRIBER_ID = "Test Subscriber";
private static final String SUBSCRIBER_ID_2 = "Test Subscriber 2";
@@ -67,11 +66,11 @@ public class DataUsageUtilsTest {
mContext = spy(RuntimeEnvironment.application);
when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
+ when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager);
when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager);
when(mTelephonyManager.getSubscriberId(SUB_ID)).thenReturn(SUBSCRIBER_ID);
- when(mTelephonyManager.getSubscriberId(SUB_ID_2)).thenReturn(SUBSCRIBER_ID_2);
- when(mInfo1.getSubscriptionId()).thenReturn(SUB_ID);
- when(mInfo2.getSubscriptionId()).thenReturn(SUB_ID_2);
+ when(mTelephonyManager.getMergedSubscriberIds()).thenReturn(
+ new String[]{SUBSCRIBER_ID, SUBSCRIBER_ID_2});
mInfos = new ArrayList<>();
mInfos.add(mInfo1);
@@ -89,17 +88,7 @@ public class DataUsageUtilsTest {
}
@Test
- public void getMobileTemplate_groupUuidNull_returnMobileAll() {
- when(mSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(mInfo1);
- when(mInfo1.getGroupUuid()).thenReturn(null);
-
- final NetworkTemplate networkTemplate = DataUsageUtils.getMobileTemplate(mContext, SUB_ID);
- assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID)).isTrue();
- assertThat(networkTemplate.matchesSubscriberId(SUBSCRIBER_ID_2)).isFalse();
- }
-
- @Test
- public void getMobileTemplate_groupUuidExist_returnMobileMerged() {
+ public void getMobileTemplate_infoExisted_returnMobileMerged() {
when(mSubscriptionManager.getActiveSubscriptionInfo(SUB_ID)).thenReturn(mInfo1);
when(mInfo1.getGroupUuid()).thenReturn(mParcelUuid);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 98c6702f899d..8689eef79583 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -101,6 +101,8 @@
<uses-permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS" />
<uses-permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS" />
<uses-permission android:name="android.permission.WHITELIST_RESTRICTED_PERMISSIONS" />
+ <!-- Permission required to test onPermissionsChangedListener -->
+ <uses-permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS" />
<uses-permission android:name="android.permission.SET_KEYBOARD_LAYOUT" />
<uses-permission android:name="android.permission.GET_DETAILED_TASKS" />
<uses-permission android:name="android.permission.SET_SCREEN_COMPATIBILITY" />
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 17274f418a1e..4f74605b4003 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -20,6 +20,7 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
package="com.android.systemui"
android:sharedUserId="android.uid.systemui"
+ xmlns:tools="http://schemas.android.com/tools"
coreApp="true">
<!-- Using OpenGL ES 2.0 -->
@@ -259,7 +260,8 @@
android:theme="@style/Theme.SystemUI"
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true"
- android:appComponentFactory="androidx.core.app.CoreComponentFactory">
+ tools:replace="android:appComponentFactory"
+ android:appComponentFactory=".SystemUIAppComponentFactory">
<!-- Keep theme in sync with SystemUIApplication.onCreate().
Setting the theme on the application does not affect views inflated by services.
The application theme is set again from onCreate to take effect for those views. -->
diff --git a/packages/SystemUI/docs/dagger.md b/packages/SystemUI/docs/dagger.md
index c2159df1cee1..c440fba10135 100644
--- a/packages/SystemUI/docs/dagger.md
+++ b/packages/SystemUI/docs/dagger.md
@@ -53,7 +53,7 @@ variants (like other form factors e.g. Car).
### Adding injection to a new SystemUI object
Anything that depends on any `@Singleton` provider from SystemUIRootComponent
-should be declared as an `@Subcomponent` of the root component, this requires
+should be declared as a `@Subcomponent` of the root component. This requires
declaring your own interface for generating your own modules or just the
object you need injected. The subcomponent also needs to be added to
SystemUIRootComponent in SystemUIFactory so it can be acquired.
@@ -204,6 +204,13 @@ public CustomView(@Named(VIEW_CONTEXT) Context themedViewContext, AttributeSet a
}
```
+## Updating Dagger2
+
+Binaries can be downloaded from https://repo1.maven.org/maven2/com/google/dagger/ and then loaded
+into
+[/prebuilts/tools/common/m2/repository/com/google/dagger/](http://cs/android/prebuilts/tools/common/m2/repository/com/google/dagger/)
+
+
## TODO List
- Eliminate usages of Dependency#get
diff --git a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackView.java
index 14fd149d22f4..b89218c81a91 100644
--- a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackView.java
@@ -41,8 +41,10 @@ import android.widget.ScrollView;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.recents.LegacyRecentsImpl;
import com.android.systemui.recents.RecentsActivity;
import com.android.systemui.recents.RecentsActivityLaunchState;
@@ -86,15 +88,15 @@ import com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent;
import com.android.systemui.recents.misc.DozeTrigger;
import com.android.systemui.recents.misc.ReferenceCountedTrigger;
import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.TaskStack;
import com.android.systemui.recents.utilities.AnimationProps;
import com.android.systemui.recents.utilities.Utilities;
-import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.recents.model.TaskStack;
import com.android.systemui.recents.views.grid.GridTaskView;
import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm;
import com.android.systemui.recents.views.grid.TaskViewFocusFrame;
-
+import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -256,7 +258,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
mLayoutAlgorithm = new TaskStackLayoutAlgorithm(context, this);
mStableLayoutAlgorithm = new TaskStackLayoutAlgorithm(context, null);
mStackScroller = new TaskStackViewScroller(context, this, mLayoutAlgorithm);
- mTouchHandler = new TaskStackViewTouchHandler(context, this, mStackScroller);
+ mTouchHandler = new TaskStackViewTouchHandler(
+ context, this, mStackScroller, Dependency.get(FalsingManager.class));
mAnimationHelper = new TaskStackAnimationHelper(context, this);
mTaskCornerRadiusPx = LegacyRecentsImpl.getConfiguration().isGridEnabled ?
res.getDimensionPixelSize(R.dimen.recents_grid_task_view_rounded_corners_radius) :
diff --git a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index dd6926c848b4..a7fb4fae09ec 100644
--- a/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/legacy/recents/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -37,6 +37,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.LegacyRecentsImpl;
import com.android.systemui.recents.events.EventBus;
@@ -107,7 +108,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
boolean mInterceptedBySwipeHelper;
public TaskStackViewTouchHandler(Context context, TaskStackView sv,
- TaskStackViewScroller scroller) {
+ TaskStackViewScroller scroller, FalsingManager falsingManager) {
Resources res = context.getResources();
ViewConfiguration configuration = ViewConfiguration.get(context);
mContext = context;
@@ -119,7 +120,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
mWindowTouchSlop = configuration.getScaledWindowTouchSlop();
mFlingAnimUtils = new FlingAnimationUtils(context, 0.2f);
mOverscrollSize = res.getDimensionPixelSize(R.dimen.recents_fling_overscroll_distance);
- mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, context) {
+ mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, context, falsingManager) {
@Override
protected float getSize(View v) {
return getScaledDismissSize();
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index a549870ec780..7c2413039ae4 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -480,4 +480,10 @@
<!-- ThemePicker package name for overlaying icons. -->
<string name="themepicker_overlayable_package" translatable="false">com.android.wallpaper</string>
+ <!-- Default rounded corner curve (a Bezier). Must match (the curved path in) rounded.xml.
+ Note that while rounded.xml includes the entire path (including the horizontal and vertical
+ corner edges), this pulls out just the curve.
+ -->
+ <string name="config_rounded_mask" translatable="false">"M8,0C3.6,0,0,3.6,0,8"</string>
+
</resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 2e2666ec3c8d..66f19495dfa6 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -98,6 +98,12 @@
<item type="id" name="keyguard_hun_animator_start_tag"/>
<item type="id" name="keyguard_hun_animator_end_tag"/>
+ <item type="id" name="view_group_fade_helper_modified_views"/>
+ <item type="id" name="view_group_fade_helper_animator"/>
+ <item type="id" name="view_group_fade_helper_previous_value_tag"/>
+ <item type="id" name="view_group_fade_helper_restore_tag"/>
+ <item type="id" name="view_group_fade_helper_hardware_layer"/>
+
<!-- Accessibility actions for the notification menu -->
<item type="id" name="action_snooze_undo"/>
<item type="id" name="action_snooze_shorter"/>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index a2abb4b1695c..506813beadf6 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -307,28 +307,22 @@ public class ActivityManagerWrapper {
}
final ActivityOptions finalOptions = options;
- // Execute this from another thread such that we can do other things (like caching the
- // bitmap for the thumbnail) while AM is busy starting our activity.
- mBackgroundExecutor.submit(new Runnable() {
- @Override
- public void run() {
- boolean result = false;
- try {
- result = startActivityFromRecents(taskKey.id, finalOptions);
- } catch (Exception e) {
- // Fall through
- }
- final boolean finalResult = result;
- if (resultCallback != null) {
- resultCallbackHandler.post(new Runnable() {
- @Override
- public void run() {
- resultCallback.accept(finalResult);
- }
- });
+
+ boolean result = false;
+ try {
+ result = startActivityFromRecents(taskKey.id, finalOptions);
+ } catch (Exception e) {
+ // Fall through
+ }
+ final boolean finalResult = result;
+ if (resultCallback != null) {
+ resultCallbackHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ resultCallback.accept(finalResult);
}
- }
- });
+ });
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 0a834c88d803..05e14a779a17 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -30,6 +30,12 @@ import static android.os.BatteryManager.EXTRA_PLUGGED;
import static android.os.BatteryManager.EXTRA_STATUS;
import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
+
import android.annotation.AnyThread;
import android.annotation.MainThread;
import android.app.ActivityManager;
@@ -672,8 +678,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
if (msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT) {
- mLockPatternUtils.requireStrongAuth(
- LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
+ mLockPatternUtils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
getCurrentUser());
}
@@ -833,8 +838,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
if (msgId == FaceManager.FACE_ERROR_LOCKOUT_PERMANENT) {
- mLockPatternUtils.requireStrongAuth(
- LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
+ mLockPatternUtils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
getCurrentUser());
}
@@ -953,8 +957,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
public boolean isUserInLockdown(int userId) {
- return mStrongAuthTracker.getStrongAuthForUser(userId)
- == LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
+ return containsFlag(mStrongAuthTracker.getStrongAuthForUser(userId),
+ STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
}
public boolean userNeedsStrongAuth() {
@@ -962,6 +966,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
!= LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
}
+ private boolean containsFlag(int haystack, int needle) {
+ return (haystack & needle) != 0;
+ }
+
public boolean needsSlowUnlockTransition() {
return mNeedsSlowUnlockTransition;
}
@@ -1680,8 +1688,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
final int user = getCurrentUser();
final int strongAuth = mStrongAuthTracker.getStrongAuthForUser(user);
final boolean isLockOutOrLockDown =
- strongAuth == StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT
- || strongAuth == StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
+ containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_LOCKOUT)
+ || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW)
+ || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+ final boolean isEncryptedOrTimedOut =
+ containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_BOOT)
+ || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_TIMEOUT);
boolean canBypass = mKeyguardBypassController != null
&& mKeyguardBypassController.canBypass();
@@ -1690,13 +1702,18 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
// TrustAgents or biometrics are keeping the device unlocked.
boolean becauseCannotSkipBouncer = !getUserCanSkipBouncer(user) || canBypass;
+ // Scan even when encrypted or timeout to show a preemptive bouncer when bypassing.
+ // Lockout/lockdown modes shouldn't scan, since they are more explicit.
+ boolean strongAuthAllowsScanning = (!isEncryptedOrTimedOut || canBypass && !mBouncer)
+ && !isLockOutOrLockDown;
+
// Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an
// instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
return (mBouncer || mAuthInterruptActive || awakeKeyguard || shouldListenForFaceAssistant())
&& !mSwitchingUser && !isFaceDisabled(user) && becauseCannotSkipBouncer
&& !mKeyguardGoingAway && mFaceSettingEnabledForUser && !mLockIconPressed
- && mUserManager.isUserUnlocked(user) && mIsPrimaryUser
- && !mSecureCameraLaunched && !isLockOutOrLockDown;
+ && strongAuthAllowsScanning && mIsPrimaryUser
+ && !mSecureCameraLaunched;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/ContextComponentHelper.java b/packages/SystemUI/src/com/android/systemui/ContextComponentHelper.java
new file mode 100644
index 000000000000..8fabe7aa9eb6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ContextComponentHelper.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+/**
+ * Interface necessary to make Dagger happy. See {@link ContextComponentResolver}.
+ */
+public interface ContextComponentHelper {
+ /** Turns a classname into an instance of the class or returns null. */
+ <T> T resolve(String className);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ContextComponentResolver.java b/packages/SystemUI/src/com/android/systemui/ContextComponentResolver.java
new file mode 100644
index 000000000000..09bccd993f39
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ContextComponentResolver.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.inject.Provider;
+
+/**
+ * Used during Service and Activity instantiation to make them injectable.
+ */
+public class ContextComponentResolver implements ContextComponentHelper {
+ private final Map<Class<?>, Provider<Object>> mCreators;
+
+ @Inject
+ ContextComponentResolver(Map<Class<?>, Provider<Object>> creators) {
+ mCreators = creators;
+ }
+
+ /**
+ * Looks up the class name to see if Dagger has an instance of it.
+ */
+ @Override
+ public <T> T resolve(String className) {
+ for (Map.Entry<Class<?>, Provider<Object>> p : mCreators.entrySet()) {
+ if (p.getKey().getName().equals(className)) {
+ return (T) p.getValue().get();
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 9a0e9fc92af6..c9d4957494e4 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -46,6 +46,8 @@ public class ImageWallpaper extends WallpaperService {
// We delayed destroy render context that subsequent render requests have chance to cancel it.
// This is to avoid destroying then recreating render context in a very short time.
private static final int DELAY_FINISH_RENDERING = 1000;
+ private static final int INTERVAL_WAIT_FOR_RENDERING = 100;
+ private static final int PATIENCE_WAIT_FOR_RENDERING = 5;
private HandlerThread mWorker;
@Override
@@ -80,7 +82,10 @@ public class ImageWallpaper extends WallpaperService {
private StatusBarStateController mController;
private final Runnable mFinishRenderingTask = this::finishRendering;
private final boolean mNeedTransition;
+ private final Object mMonitor = new Object();
private boolean mNeedRedraw;
+ // This variable can only be accessed in synchronized block.
+ private boolean mWaitingForRendering;
GLEngine(Context context) {
mNeedTransition = ActivityManager.isHighEndGfx()
@@ -122,6 +127,27 @@ public class ImageWallpaper extends WallpaperService {
long duration = mNeedTransition || animationDuration != 0 ? animationDuration : 0;
mWorker.getThreadHandler().post(
() -> mRenderer.updateAmbientMode(inAmbientMode, duration));
+ if (inAmbientMode && duration == 0) {
+ // This means that we are transiting from home to aod, to avoid
+ // race condition between window visibility and transition,
+ // we don't return until the transition is finished. See b/136643341.
+ waitForBackgroundRendering();
+ }
+ }
+
+ private void waitForBackgroundRendering() {
+ synchronized (mMonitor) {
+ try {
+ mWaitingForRendering = true;
+ for (int patience = 1; mWaitingForRendering; patience++) {
+ mMonitor.wait(INTERVAL_WAIT_FOR_RENDERING);
+ mWaitingForRendering &= patience < PATIENCE_WAIT_FOR_RENDERING;
+ }
+ } catch (InterruptedException ex) {
+ } finally {
+ mWaitingForRendering = false;
+ }
+ }
}
@Override
@@ -178,7 +204,8 @@ public class ImageWallpaper extends WallpaperService {
@Override
public void preRender() {
- mWorker.getThreadHandler().post(this::preRenderInternal);
+ // This method should only be invoked from worker thread.
+ preRenderInternal();
}
private void preRenderInternal() {
@@ -212,7 +239,8 @@ public class ImageWallpaper extends WallpaperService {
@Override
public void requestRender() {
- mWorker.getThreadHandler().post(this::requestRenderInternal);
+ // This method should only be invoked from worker thread.
+ requestRenderInternal();
}
private void requestRenderInternal() {
@@ -234,7 +262,21 @@ public class ImageWallpaper extends WallpaperService {
@Override
public void postRender() {
- mWorker.getThreadHandler().post(this::scheduleFinishRendering);
+ // This method should only be invoked from worker thread.
+ notifyWaitingThread();
+ scheduleFinishRendering();
+ }
+
+ private void notifyWaitingThread() {
+ synchronized (mMonitor) {
+ if (mWaitingForRendering) {
+ try {
+ mWaitingForRendering = false;
+ mMonitor.notify();
+ } catch (IllegalMonitorStateException ex) {
+ }
+ }
+ }
}
private void cancelFinishRenderingTask() {
diff --git a/packages/SystemUI/src/com/android/systemui/ServiceBinder.java b/packages/SystemUI/src/com/android/systemui/ServiceBinder.java
new file mode 100644
index 000000000000..6282c6e5282f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ServiceBinder.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import com.android.systemui.doze.DozeService;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.multibindings.ClassKey;
+import dagger.multibindings.IntoMap;
+
+/**
+ * Services and Activities that are injectable should go here.
+ */
+@Module
+public abstract class ServiceBinder {
+
+ @Binds
+ public abstract ContextComponentHelper bindComponentHelper(
+ ContextComponentResolver componentHelper);
+
+ @Binds
+ @IntoMap
+ @ClassKey(DozeService.class)
+ public abstract Object bindDozeService(DozeService service);
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 84e0238fdd3a..58c52a1fc50e 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -34,7 +34,6 @@ import android.view.View;
import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
-import com.android.systemui.classifier.FalsingManagerFactory;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.statusbar.FlingAnimationUtils;
@@ -98,7 +97,8 @@ public class SwipeHelper implements Gefingerpoken {
private final ArrayMap<View, Animator> mDismissPendingMap = new ArrayMap<>();
- public SwipeHelper(int swipeDirection, Callback callback, Context context) {
+ public SwipeHelper(
+ int swipeDirection, Callback callback, Context context, FalsingManager falsingManager) {
mContext = context;
mCallback = callback;
mHandler = new Handler();
@@ -113,7 +113,7 @@ public class SwipeHelper implements Gefingerpoken {
mDensityScale = res.getDisplayMetrics().density;
mFalsingThreshold = res.getDimensionPixelSize(R.dimen.swipe_helper_falsing_threshold);
mFadeDependingOnAmountSwiped = res.getBoolean(R.bool.config_fadeDependingOnAmountSwiped);
- mFalsingManager = FalsingManagerFactory.getInstance(context);
+ mFalsingManager = falsingManager;
mFlingAnimationUtils = new FlingAnimationUtils(context, getMaxEscapeAnimDuration() / 1000f);
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java
new file mode 100644
index 000000000000..00ae99295768
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.app.Application;
+import android.app.Service;
+import android.content.Intent;
+
+import androidx.core.app.CoreComponentFactory;
+
+import javax.inject.Inject;
+
+/**
+ * Implementation of AppComponentFactory that injects into constructors.
+ */
+public class SystemUIAppComponentFactory extends CoreComponentFactory {
+
+ @Inject
+ public ContextComponentHelper mComponentHelper;
+
+ public SystemUIAppComponentFactory() {
+ super();
+ }
+
+ @Override
+ public Application instantiateApplication(ClassLoader cl, String className)
+ throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+ Application app = super.instantiateApplication(cl, className);
+ if (app instanceof SystemUIApplication) {
+ ((SystemUIApplication) app).setContextAvailableCallback(
+ context -> {
+ SystemUIFactory.createFromConfig(context);
+ SystemUIFactory.getInstance().getRootComponent().inject(
+ SystemUIAppComponentFactory.this);
+ }
+ );
+ }
+
+ return app;
+ }
+
+ @Override
+ public Service instantiateService(ClassLoader cl, String className, Intent intent)
+ throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+ Service service = mComponentHelper.resolve(className);
+ if (service != null) {
+ return checkCompatWrapper(service);
+ }
+ return super.instantiateService(cl, className, intent);
+ }
+
+ static <T> T checkCompatWrapper(T obj) {
+ if (obj instanceof CompatWrapped) {
+ T wrapper = (T) ((CompatWrapped) obj).getWrapper();
+ if (wrapper != null) {
+ return wrapper;
+ }
+ }
+
+ return obj;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index e89e6cb269f8..f8449add6dce 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -60,16 +60,20 @@ public class SystemUIApplication extends Application implements SysUiServiceProv
private boolean mServicesStarted;
private boolean mBootCompleted;
private final Map<Class<?>, Object> mComponents = new HashMap<>();
+ private ContextAvailableCallback mContextAvailableCallback;
@Override
public void onCreate() {
super.onCreate();
+ // This line is used to setup Dagger's dependency injection and should be kept at the
+ // top of this method.
+ mContextAvailableCallback.onContextAvailable(this);
+
// Set the application theme that is inherited by all services. Note that setting the
// application theme in the manifest does only work for activities. Keep this in sync with
// the theme set there.
setTheme(R.style.Theme_SystemUI);
- SystemUIFactory.createFromConfig(this);
if (Process.myUserHandle().equals(UserHandle.SYSTEM)) {
IntentFilter bootCompletedFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
@@ -286,4 +290,12 @@ public class SystemUIApplication extends Application implements SysUiServiceProv
public SystemUI[] getServices() {
return mServices;
}
+
+ void setContextAvailableCallback(ContextAvailableCallback callback) {
+ mContextAvailableCallback = callback;
+ }
+
+ interface ContextAvailableCallback {
+ void onContextAvailable(Context context);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 4d42e0c66817..311ed8a913f1 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -19,8 +19,8 @@ package com.android.systemui;
import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
import static com.android.systemui.Dependency.LEAK_REPORT_EMAIL_NAME;
-import android.annotation.Nullable;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.AlarmManager;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -29,17 +29,15 @@ import android.os.Looper;
import android.util.Log;
import android.view.ViewGroup;
-
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.internal.util.function.TriConsumer;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.assist.AssistManager;
-import com.android.systemui.classifier.FalsingManagerFactory;
import com.android.systemui.dock.DockManager;
-import com.android.systemui.fragments.FragmentService;
import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.power.EnhancedEstimates;
import com.android.systemui.power.EnhancedEstimatesImpl;
@@ -69,8 +67,6 @@ import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.UnlockMethodCache;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.util.AsyncSensorManager;
-import com.android.systemui.util.InjectionInflationController;
-import com.android.systemui.util.leak.GarbageMonitor;
import com.android.systemui.volume.VolumeDialogComponent;
import java.util.function.Consumer;
@@ -78,7 +74,6 @@ import java.util.function.Consumer;
import javax.inject.Named;
import javax.inject.Singleton;
-import dagger.Component;
import dagger.Module;
import dagger.Provides;
@@ -116,7 +111,7 @@ public class SystemUIFactory {
public SystemUIFactory() {}
protected void init(Context context) {
- initWithRootComponent(DaggerSystemUIFactory_SystemUIRootComponent.builder()
+ initWithRootComponent(DaggerSystemUIRootComponent.builder()
.systemUIFactory(this)
.dependencyProvider(new com.android.systemui.DependencyProvider())
.contextHolder(new ContextHolder(context))
@@ -143,9 +138,10 @@ public class SystemUIFactory {
public KeyguardBouncer createKeyguardBouncer(Context context, ViewMediatorCallback callback,
LockPatternUtils lockPatternUtils, ViewGroup container,
DismissCallbackRegistry dismissCallbackRegistry,
- KeyguardBouncer.BouncerExpansionCallback expansionCallback) {
+ KeyguardBouncer.BouncerExpansionCallback expansionCallback,
+ FalsingManager falsingManager) {
return new KeyguardBouncer(context, callback, lockPatternUtils, container,
- dismissCallbackRegistry, FalsingManagerFactory.getInstance(context),
+ dismissCallbackRegistry, falsingManager,
expansionCallback, UnlockMethodCache.getInstance(context),
KeyguardUpdateMonitor.getInstance(context), new Handler(Looper.getMainLooper()));
}
@@ -276,29 +272,4 @@ public class SystemUIFactory {
return mContext;
}
}
-
- @Singleton
- @Component(modules = {SystemUIFactory.class, DependencyProvider.class, DependencyBinder.class,
- ContextHolder.class})
- public interface SystemUIRootComponent {
- @Singleton
- Dependency.DependencyInjector createDependency();
-
- @Singleton
- StatusBar.StatusBarInjector getStatusBarInjector();
-
- /**
- * FragmentCreator generates all Fragments that need injection.
- */
- @Singleton
- FragmentService.FragmentCreator createFragmentCreator();
-
- /**
- * ViewCreator generates all Views that need injection.
- */
- InjectionInflationController.ViewCreator createViewCreator();
-
- @Singleton
- GarbageMonitor createGarbageMonitor();
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java b/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java
new file mode 100644
index 000000000000..c732df3fdb9f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIRootComponent.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import com.android.systemui.fragments.FragmentService;
+import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.util.InjectionInflationController;
+import com.android.systemui.util.leak.GarbageMonitor;
+
+import javax.inject.Singleton;
+
+import dagger.Component;
+
+/**
+ * Root component for Dagger injection.
+ */
+@Singleton
+@Component(modules = {SystemUIFactory.class, DependencyProvider.class, DependencyBinder.class,
+ ServiceBinder.class, SystemUIFactory.ContextHolder.class})
+public interface SystemUIRootComponent {
+ /**
+ * Main dependency providing module.
+ */
+ @Singleton
+ Dependency.DependencyInjector createDependency();
+
+ /**
+ * Injects the StatusBar.
+ */
+ @Singleton
+ StatusBar.StatusBarInjector getStatusBarInjector();
+
+ /**
+ * FragmentCreator generates all Fragments that need injection.
+ */
+ @Singleton
+ FragmentService.FragmentCreator createFragmentCreator();
+
+ /**
+ * ViewCreator generates all Views that need injection.
+ */
+ InjectionInflationController.ViewCreator createViewCreator();
+
+ /**
+ * Creatse a GarbageMonitor.
+ */
+ @Singleton
+ GarbageMonitor createGarbageMonitor();
+
+ /**
+ * Injects into the supplied argument.
+ */
+ void inject(SystemUIAppComponentFactory factory);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/CircularCornerPathRenderer.java b/packages/SystemUI/src/com/android/systemui/assist/ui/CircularCornerPathRenderer.java
index 00346a36d3f1..e61e47a2201f 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/CircularCornerPathRenderer.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/CircularCornerPathRenderer.java
@@ -16,6 +16,7 @@
package com.android.systemui.assist.ui;
+import android.content.Context;
import android.graphics.Path;
/**
@@ -29,12 +30,11 @@ public final class CircularCornerPathRenderer extends CornerPathRenderer {
private final int mWidth;
private final Path mPath = new Path();
- public CircularCornerPathRenderer(int cornerRadiusBottom, int cornerRadiusTop,
- int width, int height) {
- mCornerRadiusBottom = cornerRadiusBottom;
- mCornerRadiusTop = cornerRadiusTop;
- mHeight = height;
- mWidth = width;
+ public CircularCornerPathRenderer(Context context) {
+ mCornerRadiusBottom = DisplayUtils.getCornerRadiusBottom(context);
+ mCornerRadiusTop = DisplayUtils.getCornerRadiusTop(context);
+ mHeight = DisplayUtils.getHeight(context);
+ mWidth = DisplayUtils.getWidth(context);
}
@Override // CornerPathRenderer
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java b/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java
index 43e7045511c5..bc782a7d62eb 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/InvocationLightsView.java
@@ -247,13 +247,9 @@ public class InvocationLightsView extends View
* To render corners that aren't circular, override this method in a subclass.
*/
protected CornerPathRenderer createCornerPathRenderer(Context context) {
- int displayWidth = DisplayUtils.getWidth(context);
- int displayHeight = DisplayUtils.getHeight(context);
- int cornerRadiusBottom = DisplayUtils.getCornerRadiusBottom(context);
- int cornerRadiusTop = DisplayUtils.getCornerRadiusTop(context);
- return new CircularCornerPathRenderer(
- cornerRadiusBottom, cornerRadiusTop, displayWidth, displayHeight);
+ return new CircularCornerPathRenderer(context);
}
+
/**
* Receives an intensity from 0 (lightest) to 1 (darkest) and sets the handle color
* appropriately. Intention is to match the home handle color.
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/PathSpecCornerPathRenderer.java b/packages/SystemUI/src/com/android/systemui/assist/ui/PathSpecCornerPathRenderer.java
new file mode 100644
index 000000000000..2bad7fc9583a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/PathSpecCornerPathRenderer.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.assist.ui;
+
+import android.content.Context;
+import android.graphics.Matrix;
+import android.graphics.Path;
+import android.graphics.RectF;
+import android.util.Log;
+import android.util.PathParser;
+
+import com.android.systemui.R;
+
+/**
+ * Parses a path describing rounded corners from a string.
+ */
+public final class PathSpecCornerPathRenderer extends CornerPathRenderer {
+ private static final String TAG = "PathSpecCornerPathRenderer";
+
+ private final int mHeight;
+ private final int mWidth;
+ private final float mPathScale;
+ private final int mBottomCornerRadius;
+ private final int mTopCornerRadius;
+
+ private final Path mPath = new Path();
+ private final Path mRoundedPath;
+ private final Matrix mMatrix = new Matrix();
+
+ public PathSpecCornerPathRenderer(Context context) {
+ mWidth = DisplayUtils.getWidth(context);
+ mHeight = DisplayUtils.getHeight(context);
+
+ mBottomCornerRadius = DisplayUtils.getCornerRadiusBottom(context);
+ mTopCornerRadius = DisplayUtils.getCornerRadiusTop(context);
+
+ String pathData = context.getResources().getString(R.string.config_rounded_mask);
+ Path path = PathParser.createPathFromPathData(pathData);
+ if (path == null) {
+ Log.e(TAG, "No rounded corner path found!");
+ mRoundedPath = new Path();
+ } else {
+ mRoundedPath = path;
+
+ }
+
+ RectF bounds = new RectF();
+ mRoundedPath.computeBounds(bounds, true);
+
+ // we use this to scale the path such that the larger of its [width, height] is scaled to
+ // the corner radius (to account for asymmetric paths)
+ mPathScale = Math.min(
+ Math.abs(bounds.right - bounds.left),
+ Math.abs(bounds.top - bounds.bottom));
+ }
+
+ /**
+ * Scales and rotates each corner from the path specification to its correct position.
+ *
+ * Note: the rounded corners are passed in as the full shape (a curved triangle), but we only
+ * want the actual corner curve. Therefore we call getSegment to jump past the horizontal and
+ * vertical lines.
+ */
+ @Override
+ public Path getCornerPath(Corner corner) {
+ if (mRoundedPath.isEmpty()) {
+ return mRoundedPath;
+ }
+ int cornerRadius;
+ int rotateDegrees;
+ int translateX;
+ int translateY;
+ switch (corner) {
+ case TOP_LEFT:
+ cornerRadius = mTopCornerRadius;
+ rotateDegrees = 0;
+ translateX = 0;
+ translateY = 0;
+ break;
+ case TOP_RIGHT:
+ cornerRadius = mTopCornerRadius;
+ rotateDegrees = 90;
+ translateX = mWidth;
+ translateY = 0;
+ break;
+ case BOTTOM_RIGHT:
+ cornerRadius = mBottomCornerRadius;
+ rotateDegrees = 180;
+ translateX = mWidth;
+ translateY = mHeight;
+ break;
+ case BOTTOM_LEFT:
+ default:
+ cornerRadius = mBottomCornerRadius;
+ rotateDegrees = 270;
+ translateX = 0;
+ translateY = mHeight;
+ break;
+ }
+ mPath.reset();
+ mMatrix.reset();
+ mPath.addPath(mRoundedPath);
+
+ mMatrix.preScale(cornerRadius / mPathScale, cornerRadius / mPathScale);
+ mMatrix.postRotate(rotateDegrees);
+ mMatrix.postTranslate(translateX, translateY);
+ mPath.transform(mMatrix);
+ return mPath;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/ui/PerimeterPathGuide.java b/packages/SystemUI/src/com/android/systemui/assist/ui/PerimeterPathGuide.java
index 65a9fcc3a955..fb41b1c4715f 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/ui/PerimeterPathGuide.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/ui/PerimeterPathGuide.java
@@ -102,7 +102,7 @@ public class PerimeterPathGuide {
* Sets the rotation.
*
* @param rotation one of Surface.ROTATION_0, Surface.ROTATION_90, Surface.ROTATION_180,
- * Surface.ROTATION_270
+ * Surface.ROTATION_270
*/
public void setRotation(int rotation) {
if (rotation != mRotation) {
@@ -229,14 +229,14 @@ public class PerimeterPathGuide {
- mDeviceWidthPx) / 2, (mDeviceWidthPx - mDeviceHeightPx) / 2);
}
- CircularCornerPathRenderer.Corner screenBottomLeft = getRotatedCorner(
- CircularCornerPathRenderer.Corner.BOTTOM_LEFT);
- CircularCornerPathRenderer.Corner screenBottomRight = getRotatedCorner(
- CircularCornerPathRenderer.Corner.BOTTOM_RIGHT);
- CircularCornerPathRenderer.Corner screenTopLeft = getRotatedCorner(
- CircularCornerPathRenderer.Corner.TOP_LEFT);
- CircularCornerPathRenderer.Corner screenTopRight = getRotatedCorner(
- CircularCornerPathRenderer.Corner.TOP_RIGHT);
+ CornerPathRenderer.Corner screenBottomLeft = getRotatedCorner(
+ CornerPathRenderer.Corner.BOTTOM_LEFT);
+ CornerPathRenderer.Corner screenBottomRight = getRotatedCorner(
+ CornerPathRenderer.Corner.BOTTOM_RIGHT);
+ CornerPathRenderer.Corner screenTopLeft = getRotatedCorner(
+ CornerPathRenderer.Corner.TOP_LEFT);
+ CornerPathRenderer.Corner screenTopRight = getRotatedCorner(
+ CornerPathRenderer.Corner.TOP_RIGHT);
mRegions[Region.BOTTOM_LEFT.ordinal()].path =
mCornerPathRenderer.getInsetPath(screenBottomLeft, mEdgeInset);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
index 932e40c77af0..a5857df8ba5a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDialogView.java
@@ -282,6 +282,7 @@ public abstract class BiometricDialogView extends LinearLayout {
if (mRestoredState == null) {
updateState(STATE_AUTHENTICATING);
+ mNegativeButton.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT));
final int hint = getHintStringResourceId();
if (hint != 0) {
mErrorText.setText(hint);
@@ -319,8 +320,6 @@ public abstract class BiometricDialogView extends LinearLayout {
mDescriptionText.setText(descriptionText);
}
- mNegativeButton.setText(mBundle.getCharSequence(BiometricPrompt.KEY_NEGATIVE_TEXT));
-
if (requiresConfirmation() && mRestoredState == null) {
mPositiveButton.setVisibility(View.VISIBLE);
mPositiveButton.setEnabled(false);
@@ -474,6 +473,8 @@ public abstract class BiometricDialogView extends LinearLayout {
mHandler.removeMessages(MSG_RESET_MESSAGE);
mErrorText.setTextColor(mTextColor);
mErrorText.setText(R.string.biometric_dialog_tap_confirm);
+ mErrorText.setContentDescription(
+ getResources().getString(R.string.biometric_dialog_tap_confirm));
mErrorText.setVisibility(View.VISIBLE);
announceAccessibilityEvent();
mPositiveButton.setVisibility(View.VISIBLE);
@@ -487,6 +488,7 @@ public abstract class BiometricDialogView extends LinearLayout {
if (newState == STATE_PENDING_CONFIRMATION || newState == STATE_AUTHENTICATED) {
mNegativeButton.setText(R.string.cancel);
+ mNegativeButton.setContentDescription(getResources().getString(R.string.cancel));
}
updateIcon(mState, newState);
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFactory.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFactory.java
deleted file mode 100644
index 01921f0d9a60..000000000000
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFactory.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.classifier;
-
-import android.content.Context;
-
-import com.android.systemui.Dependency;
-import com.android.systemui.plugins.FalsingManager;
-
-/**
- * When the phone is locked, listens to touch, sensor and phone events and sends them to
- * DataCollector and HumanInteractionClassifier.
- *
- * It does not collect touch events when the bouncer shows up.
- *
- * TODO: FalsingManager supports dependency injection. Use it.
- */
-public class FalsingManagerFactory {
- private static FalsingManager sInstance = null;
-
- private FalsingManagerFactory() {}
-
- public static FalsingManager getInstance(Context context) {
- if (sInstance == null) {
- sInstance = Dependency.get(FalsingManager.class);
- }
- return sInstance;
- }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
new file mode 100644
index 000000000000..0041b0c9a469
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManagerFake.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.classifier;
+
+import android.net.Uri;
+import android.view.MotionEvent;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.plugins.FalsingManager;
+
+import java.io.PrintWriter;
+
+/**
+ * Simple Fake for testing where {@link FalsingManager} is required.
+ */
+public class FalsingManagerFake implements FalsingManager {
+ private boolean mIsFalseTouch;
+ private boolean mIsUnlockingDisabled;
+ private boolean mIsClassiferEnabled;
+ private boolean mShouldEnforceBouncer;
+ private boolean mIsReportingEnabled;
+
+ @Override
+ public void onSucccessfulUnlock() {
+
+ }
+
+ @Override
+ public void onNotificationActive() {
+
+ }
+
+ @Override
+ public void setShowingAod(boolean showingAod) {
+
+ }
+
+ @Override
+ public void onNotificatonStartDraggingDown() {
+
+ }
+
+ @VisibleForTesting
+ public void setIsUnlockingDisabled(boolean isUnlockingDisabled) {
+ mIsUnlockingDisabled = isUnlockingDisabled;
+ }
+
+ @Override
+ public boolean isUnlockingDisabled() {
+ return mIsUnlockingDisabled;
+ }
+
+ @VisibleForTesting
+ public void setIsFalseTouch(boolean isFalseTouch) {
+ mIsFalseTouch = isFalseTouch;
+ }
+
+ @Override
+ public boolean isFalseTouch() {
+ return mIsFalseTouch;
+ }
+
+ @Override
+ public void onNotificatonStopDraggingDown() {
+
+ }
+
+ @Override
+ public void setNotificationExpanded() {
+
+ }
+
+ @VisibleForTesting
+ public void setIsClassiferEnabled(boolean isClassiferEnabled) {
+ mIsClassiferEnabled = isClassiferEnabled;
+ }
+
+ @Override
+ public boolean isClassiferEnabled() {
+ return mIsClassiferEnabled;
+ }
+
+ @Override
+ public void onQsDown() {
+
+ }
+
+ @Override
+ public void setQsExpanded(boolean expanded) {
+
+ }
+
+ @VisibleForTesting
+ public void setShouldEnforceBouncer(boolean shouldEnforceBouncer) {
+ mShouldEnforceBouncer = shouldEnforceBouncer;
+ }
+
+ @Override
+ public boolean shouldEnforceBouncer() {
+ return mShouldEnforceBouncer;
+ }
+
+ @Override
+ public void onTrackingStarted(boolean secure) {
+
+ }
+
+ @Override
+ public void onTrackingStopped() {
+
+ }
+
+ @Override
+ public void onLeftAffordanceOn() {
+
+ }
+
+ @Override
+ public void onCameraOn() {
+
+ }
+
+ @Override
+ public void onAffordanceSwipingStarted(boolean rightCorner) {
+
+ }
+
+ @Override
+ public void onAffordanceSwipingAborted() {
+
+ }
+
+ @Override
+ public void onStartExpandingFromPulse() {
+
+ }
+
+ @Override
+ public void onExpansionFromPulseStopped() {
+
+ }
+
+ @Override
+ public Uri reportRejectedTouch() {
+ return null;
+ }
+
+ @Override
+ public void onScreenOnFromTouch() {
+
+ }
+
+
+ @VisibleForTesting
+ public void setIsReportingEnabled(boolean isReportingEnabled) {
+ mIsReportingEnabled = isReportingEnabled;
+ }
+
+ @Override
+ public boolean isReportingEnabled() {
+ return mIsReportingEnabled;
+ }
+
+ @Override
+ public void onUnlockHintStarted() {
+
+ }
+
+ @Override
+ public void onCameraHintStarted() {
+
+ }
+
+ @Override
+ public void onLeftAffordanceHintStarted() {
+
+ }
+
+ @Override
+ public void onScreenTurningOn() {
+
+ }
+
+ @Override
+ public void onScreenOff() {
+
+ }
+
+ @Override
+ public void onNotificatonStopDismissing() {
+
+ }
+
+ @Override
+ public void onNotificationDismissed() {
+
+ }
+
+ @Override
+ public void onNotificatonStartDismissing() {
+
+ }
+
+ @Override
+ public void onNotificationDoubleTap(boolean accepted, float dx, float dy) {
+
+ }
+
+ @Override
+ public void onBouncerShown() {
+
+ }
+
+ @Override
+ public void onBouncerHidden() {
+
+ }
+
+ @Override
+ public void onTouchEvent(MotionEvent ev, int width, int height) {
+
+ }
+
+ @Override
+ public void dump(PrintWriter pw) {
+
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index fc3d1a52342f..537c09ed3199 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -28,8 +28,8 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SystemUIApplication;
-import com.android.systemui.classifier.FalsingManagerFactory;
import com.android.systemui.dock.DockManager;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.util.AsyncSensorManager;
import com.android.systemui.util.wakelock.DelayedWakeLock;
@@ -41,7 +41,7 @@ public class DozeFactory {
}
/** Creates a DozeMachine with its parts for {@code dozeService}. */
- public DozeMachine assembleMachine(DozeService dozeService) {
+ public DozeMachine assembleMachine(DozeService dozeService, FalsingManager falsingManager) {
Context context = dozeService;
SensorManager sensorManager = Dependency.get(AsyncSensorManager.class);
AlarmManager alarmManager = context.getSystemService(AlarmManager.class);
@@ -63,7 +63,7 @@ public class DozeFactory {
DozeMachine machine = new DozeMachine(wrappedService, config, wakeLock);
machine.setParts(new DozeMachine.Part[]{
new DozePauser(handler, machine, alarmManager, params.getPolicy()),
- new DozeFalsingManagerAdapter(FalsingManagerFactory.getInstance(context)),
+ new DozeFalsingManagerAdapter(falsingManager),
createDozeTriggers(context, sensorManager, host, alarmManager, config, params,
handler, wakeLock, machine, dockManager),
createDozeUi(context, host, wakeLock, machine, handler, alarmManager, params),
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 2db73065fe19..e92acfc7f219 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -25,23 +25,29 @@ import android.util.Log;
import com.android.systemui.Dependency;
import com.android.systemui.plugins.DozeServicePlugin;
import com.android.systemui.plugins.DozeServicePlugin.RequestDoze;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.shared.plugins.PluginManager;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import javax.inject.Inject;
+
public class DozeService extends DreamService
implements DozeMachine.Service, RequestDoze, PluginListener<DozeServicePlugin> {
private static final String TAG = "DozeService";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private final FalsingManager mFalsingManager;
private DozeMachine mDozeMachine;
private DozeServicePlugin mDozePlugin;
private PluginManager mPluginManager;
- public DozeService() {
+ @Inject
+ public DozeService(FalsingManager falsingManager) {
setDebug(DEBUG);
+ mFalsingManager = falsingManager;
}
@Override
@@ -56,7 +62,7 @@ public class DozeService extends DreamService
}
mPluginManager = Dependency.get(PluginManager.class);
mPluginManager.addPluginListener(this, DozeServicePlugin.class, false /* allowMultiple */);
- mDozeMachine = new DozeFactory().assembleMachine(this);
+ mDozeMachine = new DozeFactory().assembleMachine(this, mFalsingManager);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
index 8dbaf0f681cf..b4cc571be061 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java
@@ -22,7 +22,7 @@ import android.view.View;
import com.android.systemui.ConfigurationChangedReceiver;
import com.android.systemui.Dumpable;
-import com.android.systemui.SystemUIFactory;
+import com.android.systemui.SystemUIRootComponent;
import com.android.systemui.qs.QSFragment;
import com.android.systemui.statusbar.phone.NavigationBarFragment;
@@ -51,7 +51,7 @@ public class FragmentService implements ConfigurationChangedReceiver, Dumpable {
private final FragmentCreator mFragmentCreator;
@Inject
- public FragmentService(SystemUIFactory.SystemUIRootComponent rootComponent) {
+ public FragmentService(SystemUIRootComponent rootComponent) {
mFragmentCreator = rootComponent.createFragmentCreator();
initInjectionMap();
}
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java
index 6a1f24afe620..45e97b38d87e 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java
@@ -84,7 +84,17 @@ class ImageRevealHelper {
void updateAwake(boolean awake, long duration) {
mAwake = awake;
mAnimator.setDuration(duration);
- animate();
+ if (!mAwake && duration == 0) {
+ // We are transiting from home to aod,
+ // since main thread is waiting for rendering finished, we only need draw
+ // the last state directly, which is a black screen.
+ mReveal = MIN_REVEAL;
+ mRevealListener.onRevealStart();
+ mRevealListener.onRevealStateChanged();
+ mRevealListener.onRevealEnd();
+ } else {
+ animate();
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index d7ca4d006082..6b2721a8440e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -61,6 +61,7 @@ import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
+import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManagerPolicyConstants;
import android.view.animation.Animation;
@@ -83,8 +84,9 @@ import com.android.systemui.Dependency;
import com.android.systemui.SystemUI;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.UiOffloadThread;
-import com.android.systemui.classifier.FalsingManagerFactory;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationPanelView;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -208,6 +210,7 @@ public class KeyguardViewMediator extends SystemUI {
private boolean mBootCompleted;
private boolean mBootSendUserPresent;
private boolean mShuttingDown;
+ private boolean mDozing;
/** High level access to the power manager for WakeLocks */
private PowerManager mPM;
@@ -711,11 +714,10 @@ public class KeyguardViewMediator extends SystemUI {
com.android.keyguard.R.bool.config_enableKeyguardService)) {
setShowingLocked(!shouldWaitForProvisioning()
&& !mLockPatternUtils.isLockScreenDisabled(
- KeyguardUpdateMonitor.getCurrentUser()),
- mAodShowing, true /* forceCallbacks */);
+ KeyguardUpdateMonitor.getCurrentUser()), true /* forceCallbacks */);
} else {
// The system's keyguard is disabled or missing.
- setShowingLocked(false, mAodShowing, true);
+ setShowingLocked(false /* showing */, true /* forceCallbacks */);
}
mStatusBarKeyguardViewManager =
@@ -1324,7 +1326,7 @@ public class KeyguardViewMediator extends SystemUI {
if (mLockPatternUtils.checkVoldPassword(KeyguardUpdateMonitor.getCurrentUser())) {
if (DEBUG) Log.d(TAG, "Not showing lock screen since just decrypted");
// Without this, settings is not enabled until the lock screen first appears
- setShowingLocked(false, mAodShowing);
+ setShowingLocked(false);
hideLocked();
return;
}
@@ -1594,7 +1596,7 @@ public class KeyguardViewMediator extends SystemUI {
Trace.beginSection("KeyguardViewMediator#handleMessage START_KEYGUARD_EXIT_ANIM");
StartKeyguardExitAnimParams params = (StartKeyguardExitAnimParams) msg.obj;
handleStartKeyguardExitAnimation(params.startTime, params.fadeoutDuration);
- FalsingManagerFactory.getInstance(mContext).onSucccessfulUnlock();
+ Dependency.get(FalsingManager.class).onSucccessfulUnlock();
Trace.endSection();
break;
case KEYGUARD_DONE_PENDING_TIMEOUT:
@@ -1740,6 +1742,9 @@ public class KeyguardViewMediator extends SystemUI {
private void updateActivityLockScreenState(boolean showing, boolean aodShowing) {
mUiOffloadThread.submit(() -> {
+ if (DEBUG) {
+ Log.d(TAG, "updateActivityLockScreenState(" + showing + ", " + aodShowing + ")");
+ }
try {
ActivityTaskManager.getService().setLockScreenShown(showing, aodShowing);
} catch (RemoteException e) {
@@ -1765,10 +1770,10 @@ public class KeyguardViewMediator extends SystemUI {
if (DEBUG) Log.d(TAG, "handleShow");
}
- setShowingLocked(true, mAodShowing);
- mStatusBarKeyguardViewManager.show(options);
mHiding = false;
mWakeAndUnlocking = false;
+ setShowingLocked(true);
+ mStatusBarKeyguardViewManager.show(options);
resetKeyguardDonePendingLocked();
mHideAnimationRun = false;
adjustStatusBarLocked();
@@ -1875,7 +1880,7 @@ public class KeyguardViewMediator extends SystemUI {
if (!mHiding) {
// Tell ActivityManager that we canceled the keyguardExitAnimation.
- setShowingLocked(mShowing, mAodShowing, true /* force */);
+ setShowingLocked(mShowing, true /* force */);
return;
}
mHiding = false;
@@ -1896,8 +1901,8 @@ public class KeyguardViewMediator extends SystemUI {
playSounds(false);
}
+ setShowingLocked(false);
mWakeAndUnlocking = false;
- setShowingLocked(false, mAodShowing);
mDismissCallbackRegistry.notifyDismissSucceeded();
mStatusBarKeyguardViewManager.hide(startTime, fadeoutDuration);
resetKeyguardDonePendingLocked();
@@ -1957,7 +1962,7 @@ public class KeyguardViewMediator extends SystemUI {
Trace.beginSection("KeyguardViewMediator#handleVerifyUnlock");
synchronized (KeyguardViewMediator.this) {
if (DEBUG) Log.d(TAG, "handleVerifyUnlock");
- setShowingLocked(true, mAodShowing);
+ setShowingLocked(true);
mStatusBarKeyguardViewManager.dismissAndCollapse();
}
Trace.endSection();
@@ -2060,9 +2065,12 @@ public class KeyguardViewMediator extends SystemUI {
public StatusBarKeyguardViewManager registerStatusBar(StatusBar statusBar,
ViewGroup container, NotificationPanelView panelView,
- BiometricUnlockController biometricUnlockController, ViewGroup lockIconContainer) {
+ BiometricUnlockController biometricUnlockController, ViewGroup lockIconContainer,
+ View notificationContainer, KeyguardBypassController bypassController,
+ FalsingManager falsingManager) {
mStatusBarKeyguardViewManager.registerStatusBar(statusBar, container, panelView,
- biometricUnlockController, mDismissCallbackRegistry, lockIconContainer);
+ biometricUnlockController, mDismissCallbackRegistry, lockIconContainer,
+ notificationContainer, bypassController, falsingManager);
return mStatusBarKeyguardViewManager;
}
@@ -2102,6 +2110,8 @@ public class KeyguardViewMediator extends SystemUI {
pw.print(" mDeviceInteractive: "); pw.println(mDeviceInteractive);
pw.print(" mGoingToSleep: "); pw.println(mGoingToSleep);
pw.print(" mHiding: "); pw.println(mHiding);
+ pw.print(" mDozing: "); pw.println(mDozing);
+ pw.print(" mAodShowing: "); pw.println(mAodShowing);
pw.print(" mWaitingUntilKeyguardVisible: "); pw.println(mWaitingUntilKeyguardVisible);
pw.print(" mKeyguardDonePending: "); pw.println(mKeyguardDonePending);
pw.print(" mHideAnimationRun: "); pw.println(mHideAnimationRun);
@@ -2112,10 +2122,14 @@ public class KeyguardViewMediator extends SystemUI {
}
/**
- * @param aodShowing true when AOD - or ambient mode - is showing.
+ * @param dozing true when AOD - or ambient mode - is showing.
*/
- public void setAodShowing(boolean aodShowing) {
- setShowingLocked(mShowing, aodShowing);
+ public void setDozing(boolean dozing) {
+ if (dozing == mDozing) {
+ return;
+ }
+ mDozing = dozing;
+ setShowingLocked(mShowing);
}
/**
@@ -2136,19 +2150,18 @@ public class KeyguardViewMediator extends SystemUI {
}
}
- private void setShowingLocked(boolean showing, boolean aodShowing) {
- setShowingLocked(showing, aodShowing, false /* forceCallbacks */);
+ private void setShowingLocked(boolean showing) {
+ setShowingLocked(showing, false /* forceCallbacks */);
}
- private void setShowingLocked(boolean showing, boolean aodShowing, boolean forceCallbacks) {
+ private void setShowingLocked(boolean showing, boolean forceCallbacks) {
+ final boolean aodShowing = mDozing && !mWakeAndUnlocking;
final boolean notifyDefaultDisplayCallbacks = showing != mShowing
|| aodShowing != mAodShowing || forceCallbacks;
+ mShowing = showing;
+ mAodShowing = aodShowing;
if (notifyDefaultDisplayCallbacks) {
- mShowing = showing;
- mAodShowing = aodShowing;
- if (notifyDefaultDisplayCallbacks) {
- notifyDefaultDisplayCallbacks(showing);
- }
+ notifyDefaultDisplayCallbacks(showing);
updateActivityLockScreenState(showing, aodShowing);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index ed6f599b69a6..19edc94a3871 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -120,6 +120,8 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
private int mCurrentBoundedUserId = -1;
private float mNavBarButtonAlpha;
private boolean mInputFocusTransferStarted;
+ private float mInputFocusTransferStartY;
+ private long mInputFocusTransferStartMillis;
private float mWindowCornerRadius;
private boolean mSupportsRoundedCornersOnWindows;
private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
@@ -180,12 +182,16 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
int action = event.getActionMasked();
if (action == ACTION_DOWN) {
mInputFocusTransferStarted = true;
-
+ mInputFocusTransferStartY = event.getY();
+ mInputFocusTransferStartMillis = event.getEventTime();
+ bar.onInputFocusTransfer(mInputFocusTransferStarted, 0 /* velocity */);
}
if (action == ACTION_UP || action == ACTION_CANCEL) {
mInputFocusTransferStarted = false;
+ bar.onInputFocusTransfer(mInputFocusTransferStarted,
+ (event.getY() - mInputFocusTransferStartY)
+ / (event.getEventTime() - mInputFocusTransferStartMillis));
}
- bar.onInputFocusTransfer(mInputFocusTransferStarted);
event.recycle();
}
});
@@ -596,7 +602,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
StatusBar bar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
if (bar != null) {
mInputFocusTransferStarted = false;
- bar.onInputFocusTransfer(false);
+ bar.onInputFocusTransfer(false, 0 /* velocity */);
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index 514a2ae7a74e..d93982889655 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -29,7 +29,6 @@ import com.android.systemui.ExpandHelper;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.classifier.FalsingManagerFactory;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -59,14 +58,15 @@ public class DragDownHelper implements Gefingerpoken {
private FalsingManager mFalsingManager;
public DragDownHelper(Context context, View host, ExpandHelper.Callback callback,
- DragDownCallback dragDownCallback) {
+ DragDownCallback dragDownCallback,
+ FalsingManager falsingManager) {
mMinDragDistance = context.getResources().getDimensionPixelSize(
R.dimen.keyguard_drag_down_min_distance);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mCallback = callback;
mDragDownCallback = dragDownCallback;
mHost = host;
- mFalsingManager = FalsingManagerFactory.getInstance(context);
+ mFalsingManager = falsingManager;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 1440803f1524..70ee752dd8ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -52,6 +52,7 @@ import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -121,6 +122,7 @@ public class NotificationRemoteInputManager implements Dumpable {
protected final Context mContext;
private final UserManager mUserManager;
private final KeyguardManager mKeyguardManager;
+ private final StatusBarStateController mStatusBarStateController;
protected RemoteInputController mRemoteInputController;
protected NotificationLifetimeExtender.NotificationSafeToRemoveCallback
@@ -259,6 +261,7 @@ public class NotificationRemoteInputManager implements Dumpable {
SmartReplyController smartReplyController,
NotificationEntryManager notificationEntryManager,
Lazy<ShadeController> shadeController,
+ StatusBarStateController statusBarStateController,
@Named(MAIN_HANDLER_NAME) Handler mainHandler) {
mContext = context;
mLockscreenUserManager = lockscreenUserManager;
@@ -271,6 +274,7 @@ public class NotificationRemoteInputManager implements Dumpable {
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
addLifetimeExtenders();
mKeyguardManager = context.getSystemService(KeyguardManager.class);
+ mStatusBarStateController = statusBarStateController;
notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
@@ -380,7 +384,10 @@ public class NotificationRemoteInputManager implements Dumpable {
if (!mLockscreenUserManager.shouldAllowLockscreenRemoteInput()) {
final int userId = pendingIntent.getCreatorUserHandle().getIdentifier();
- if (mLockscreenUserManager.isLockscreenPublicMode(userId)) {
+ if (mLockscreenUserManager.isLockscreenPublicMode(userId)
+ || mStatusBarStateController.getState() == StatusBarState.KEYGUARD) {
+ // Even if we don't have security we should go through this flow, otherwise we won't
+ // go to the shade
mCallback.onLockedRemoteInput(row, view);
return true;
}
@@ -391,6 +398,11 @@ public class NotificationRemoteInputManager implements Dumpable {
}
}
+ if (!riv.isAttachedToWindow()) {
+ // the remoteInput isn't attached to the window anymore :/ Let's focus on the expanded
+ // one instead if it's available
+ riv = null;
+ }
if (riv == null) {
riv = findRemoteInputView(row.getPrivateLayout().getExpandedChild());
if (riv == null) {
@@ -405,6 +417,10 @@ public class NotificationRemoteInputManager implements Dumpable {
return true;
}
+ if (!riv.isAttachedToWindow()) {
+ // if we still didn't find a view that is attached, let's abort.
+ return false;
+ }
int width = view.getWidth();
if (view instanceof TextView) {
// Center the reveal on the text which might be off-center from the TextView
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index aeb85748fd1a..22c91647d7f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -468,14 +468,14 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
private void beginUpdate() {
if (mPerformingUpdate) {
- throw new IllegalStateException("Re-entrant code during update.");
+ Log.wtf(TAG, "Re-entrant code during update", new Exception());
}
mPerformingUpdate = true;
}
private void endUpdate() {
if (!mPerformingUpdate) {
- throw new IllegalStateException("Manager state has become desynced.");
+ Log.wtf(TAG, "Manager state has become desynced", new Exception());
}
mPerformingUpdate = false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
index 986486ac14d4..48d6de964b08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/PulseExpansionHandler.kt
@@ -27,11 +27,11 @@ import android.os.SystemClock
import android.view.MotionEvent
import android.view.VelocityTracker
import android.view.ViewConfiguration
+import com.android.systemui.Dependency
import com.android.systemui.Gefingerpoken
import com.android.systemui.Interpolators
import com.android.systemui.R
-import com.android.systemui.classifier.FalsingManagerFactory
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
@@ -115,7 +115,7 @@ constructor(context: Context,
mMinDragDistance = context.resources.getDimensionPixelSize(
R.dimen.keyguard_drag_down_min_distance)
mTouchSlop = ViewConfiguration.get(context).scaledTouchSlop.toFloat()
- mFalsingManager = FalsingManagerFactory.getInstance(context)
+ mFalsingManager = Dependency.get(FalsingManager::class.java)
mPowerManager = context.getSystemService(PowerManager::class.java)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt
new file mode 100644
index 000000000000..847d1ccddddf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ViewGroupFadeHelper.kt
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
+import android.view.View
+import android.view.ViewGroup
+import com.android.systemui.Interpolators
+import com.android.systemui.R
+
+/**
+ * Class to help with fading of view groups without fading one subview
+ */
+class ViewGroupFadeHelper {
+ companion object {
+ private val visibilityIncluder = {
+ view: View -> view.visibility == View.VISIBLE
+ }
+
+ /**
+ * Fade out all views of a root except a single child. This will iterate over all children
+ * of the view and make sure that the animation works smoothly.
+ * @param root the view root to fade the children away
+ * @param excludedView which view should remain
+ * @param duration the duration of the animation
+ */
+ @JvmStatic
+ fun fadeOutAllChildrenExcept(root: ViewGroup, excludedView: View, duration: Long,
+ endRunnable: Runnable?) {
+ // starting from the view going up, we are adding the siblings of the child to the set
+ // of views that need to be faded.
+ val viewsToFadeOut = gatherViews(root, excludedView, visibilityIncluder)
+
+ // Applying the right layertypes for the animation
+ for (viewToFade in viewsToFadeOut) {
+ if (viewToFade.hasOverlappingRendering
+ && viewToFade.layerType == View.LAYER_TYPE_NONE) {
+ viewToFade.setLayerType(View.LAYER_TYPE_HARDWARE, null)
+ viewToFade.setTag(R.id.view_group_fade_helper_hardware_layer, true)
+ }
+ }
+
+ val animator = ValueAnimator.ofFloat(1.0f, 0.0f).apply {
+ this.duration = duration
+ interpolator = Interpolators.ALPHA_OUT
+ addUpdateListener { animation ->
+ val previousSetAlpha = root.getTag(
+ R.id.view_group_fade_helper_previous_value_tag) as Float?
+ val newAlpha = animation.animatedValue as Float
+ for (viewToFade in viewsToFadeOut) {
+ if (viewToFade.alpha != previousSetAlpha) {
+ // A value was set that wasn't set from our view, let's store it and restore
+ // it at the end
+ viewToFade.setTag(R.id.view_group_fade_helper_restore_tag, viewToFade.alpha)
+ }
+ viewToFade.alpha = newAlpha
+ }
+ root.setTag(R.id.view_group_fade_helper_previous_value_tag, newAlpha)
+ }
+ addListener(object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ endRunnable?.run()
+ }
+ })
+ start()
+ }
+ root.setTag(R.id.view_group_fade_helper_modified_views, viewsToFadeOut)
+ root.setTag(R.id.view_group_fade_helper_animator, animator)
+ }
+
+ private fun gatherViews(root: ViewGroup, excludedView: View,
+ shouldInclude: (View) -> Boolean): MutableSet<View> {
+ val viewsToFadeOut = mutableSetOf<View>()
+ var parent = excludedView.parent as ViewGroup?
+ var viewContainingExcludedView = excludedView;
+ while (parent != null) {
+ for (i in 0 until parent.childCount) {
+ val child = parent.getChildAt(i)
+ if (shouldInclude.invoke(child) && viewContainingExcludedView != child) {
+ viewsToFadeOut.add(child)
+ }
+ }
+ if (parent == root) {
+ break;
+ }
+ viewContainingExcludedView = parent
+ parent = parent.parent as ViewGroup?
+ }
+ return viewsToFadeOut
+ }
+
+ /**
+ * Reset all view alphas for views previously transformed away.
+ */
+ @JvmStatic
+ fun reset(root: ViewGroup) {
+ @Suppress("UNCHECKED_CAST")
+ val modifiedViews = root.getTag(R.id.view_group_fade_helper_modified_views)
+ as MutableSet<View>?
+ val animator = root.getTag(R.id.view_group_fade_helper_animator) as Animator?
+ if (modifiedViews == null || animator == null) {
+ // nothing to restore
+ return
+ }
+ animator.cancel()
+ val lastSetValue = root.getTag(
+ R.id.view_group_fade_helper_previous_value_tag) as Float?
+ for (viewToFade in modifiedViews) {
+ val restoreAlpha = viewToFade.getTag(
+ R.id.view_group_fade_helper_restore_tag) as Float?
+ if (restoreAlpha == null) {
+ continue
+ }
+ if (lastSetValue == viewToFade.alpha) {
+ // it was modified after the transition!
+ viewToFade.alpha = restoreAlpha
+ }
+ val needsLayerReset = viewToFade.getTag(
+ R.id.view_group_fade_helper_hardware_layer) as Boolean?
+ if (needsLayerReset == true) {
+ viewToFade.setLayerType(View.LAYER_TYPE_NONE, null)
+ viewToFade.setTag(R.id.view_group_fade_helper_hardware_layer, null)
+ }
+ viewToFade.setTag(R.id.view_group_fade_helper_restore_tag, null)
+ }
+ root.setTag(R.id.view_group_fade_helper_modified_views, null)
+ root.setTag(R.id.view_group_fade_helper_previous_value_tag, null)
+ root.setTag(R.id.view_group_fade_helper_animator, null)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
index dca152fbe37a..8d7325118139 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java
@@ -33,9 +33,9 @@ import android.view.accessibility.AccessibilityManager;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.classifier.FalsingManagerFactory;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.notification.FakeShadowView;
@@ -130,7 +130,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
private boolean mLastInSection;
private boolean mFirstInSection;
private boolean mIsBelowSpeedBump;
- private FalsingManager mFalsingManager;
+ private final FalsingManager mFalsingManager;
private float mNormalBackgroundVisibilityAmount;
private float mDimmedBackgroundFadeInAmount = -1;
@@ -164,10 +164,10 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
super(context, attrs);
mSlowOutFastInInterpolator = new PathInterpolator(0.8f, 0.0f, 0.6f, 1.0f);
mSlowOutLinearInInterpolator = new PathInterpolator(0.8f, 0.0f, 1.0f, 1.0f);
+ mFalsingManager = Dependency.get(FalsingManager.class); // TODO: inject into a controller.
setClipChildren(false);
setClipToPadding(false);
updateColors();
- mFalsingManager = FalsingManagerFactory.getInstance(context);
mAccessibilityManager = AccessibilityManager.getInstance(mContext);
mDoubleTapHelper = new DoubleTapHelper(this, (active) -> {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index a8327f63dcf7..6e84089e8ff5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -74,7 +74,6 @@ import com.android.internal.widget.CachingIconView;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.classifier.FalsingManagerFactory;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
@@ -1635,7 +1634,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
public ExpandableNotificationRow(Context context, AttributeSet attrs) {
super(context, attrs);
- mFalsingManager = FalsingManagerFactory.getInstance(context);
+ mFalsingManager = Dependency.get(FalsingManager.class); // TODO: inject into a controller.
mNotificationInflater = new NotificationContentInflater(this);
mMenuRow = new NotificationMenuRow(mContext);
mImageResolver = new NotificationInlineImageResolver(context,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 9e3d74b138fa..bec95201e4b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -86,7 +86,6 @@ import com.android.systemui.ExpandHelper;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
-import com.android.systemui.classifier.FalsingManagerFactory;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
@@ -512,7 +511,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
ActivityStarter activityStarter,
StatusBarStateController statusBarStateController,
HeadsUpManagerPhone headsUpManager,
- KeyguardBypassController keyguardBypassController) {
+ KeyguardBypassController keyguardBypassController,
+ FalsingManager falsingManager) {
super(context, attrs, 0, 0);
Resources res = getResources();
@@ -527,6 +527,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mHeadsUpManager.addListener(mRoundnessManager);
mHeadsUpManager.setAnimationStateHandler(this::setHeadsUpGoingAwayAnimationsAllowed);
mKeyguardBypassController = keyguardBypassController;
+ mFalsingManager = falsingManager;
mSectionsManager =
new NotificationSectionsManager(
@@ -551,10 +552,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
mExpandHelper.setEventSource(this);
mExpandHelper.setScrollAdapter(this);
mSwipeHelper = new NotificationSwipeHelper(SwipeHelper.X, mNotificationCallback,
- getContext(), mMenuEventListener);
+ getContext(), mMenuEventListener, mFalsingManager);
mStackScrollAlgorithm = createStackScrollAlgorithm(context);
initView(context);
- mFalsingManager = FalsingManagerFactory.getInstance(context);
mShouldDrawNotificationBackground =
res.getBoolean(R.bool.config_drawNotificationBackground);
mFadeNotificationsOnDismiss =
@@ -4967,7 +4967,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd
public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
super.onInitializeAccessibilityEventInternal(event);
event.setScrollable(mScrollable);
- event.setScrollX(mScrollX);
event.setMaxScrollX(mScrollX);
if (ANCHOR_SCROLLING) {
// TODO
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
index 4dfc343df283..0968674d31cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java
@@ -28,6 +28,7 @@ import android.view.View;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.SwipeHelper;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -50,9 +51,11 @@ class NotificationSwipeHelper extends SwipeHelper
private boolean mIsExpanded;
private boolean mPulsing;
- public NotificationSwipeHelper(int swipeDirection, NotificationCallback callback,
- Context context, NotificationMenuRowPlugin.OnMenuEventListener menuListener) {
- super(swipeDirection, callback, context);
+ NotificationSwipeHelper(
+ int swipeDirection, NotificationCallback callback, Context context,
+ NotificationMenuRowPlugin.OnMenuEventListener menuListener,
+ FalsingManager falsingManager) {
+ super(swipeDirection, callback, context, falsingManager);
mMenuListener = menuListener;
mCallback = callback;
mFalsingCheck = new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index fdf18e0c7912..05d26b0a6a17 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import android.annotation.IntDef;
import android.content.Context;
import android.hardware.biometrics.BiometricSourceType;
import android.metrics.LogMaker;
@@ -39,6 +40,8 @@ import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.statusbar.NotificationMediaManager;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* Controller which coordinates all the biometric unlocking actions with the UI.
@@ -50,6 +53,20 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
private static final long BIOMETRIC_WAKELOCK_TIMEOUT_MS = 15 * 1000;
private static final String BIOMETRIC_WAKE_LOCK_NAME = "wake-and-unlock wakelock";
+ @IntDef(prefix = { "MODE_" }, value = {
+ MODE_NONE,
+ MODE_WAKE_AND_UNLOCK,
+ MODE_WAKE_AND_UNLOCK_PULSING,
+ MODE_SHOW_BOUNCER,
+ MODE_ONLY_WAKE,
+ MODE_UNLOCK_COLLAPSING,
+ MODE_UNLOCK_FADING,
+ MODE_DISMISS_BOUNCER,
+ MODE_WAKE_AND_UNLOCK_FROM_DREAM
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface WakeAndUnlockMode {}
+
/**
* Mode in which we don't need to wake up the device when we authenticate.
*/
@@ -81,7 +98,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
/**
* Mode in which fingerprint unlocks the device.
*/
- public static final int MODE_UNLOCK = 5;
+ public static final int MODE_UNLOCK_COLLAPSING = 5;
/**
* Mode in which fingerprint wakes and unlocks the device from a dream.
@@ -89,6 +106,17 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
public static final int MODE_WAKE_AND_UNLOCK_FROM_DREAM = 6;
/**
+ * Faster mode of dismissing the lock screen when we cross fade to an app
+ * (used for keyguard bypass.)
+ */
+ public static final int MODE_UNLOCK_FADING = 7;
+
+ /**
+ * When bouncer is visible and will be dismissed.
+ */
+ public static final int MODE_DISMISS_BOUNCER = 8;
+
+ /**
* How much faster we collapse the lockscreen when authenticating with biometric.
*/
private static final float BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR = 1.1f;
@@ -240,8 +268,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
startWakeAndUnlock(calculateMode(biometricSourceType));
}
- public void startWakeAndUnlock(int mode) {
- // TODO(b/62444020): remove when this bug is fixed
+ public void startWakeAndUnlock(@WakeAndUnlockMode int mode) {
Log.v(TAG, "startWakeAndUnlock(" + mode + ")");
boolean wasDeviceInteractive = mUpdateMonitor.isDeviceInteractive();
mMode = mode;
@@ -277,18 +304,16 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
wakeUp.run();
}
switch (mMode) {
- case MODE_UNLOCK:
- Trace.beginSection("MODE_UNLOCK");
- if (!wasDeviceInteractive) {
- mPendingShowBouncer = true;
- } else {
- mStatusBarKeyguardViewManager.notifyKeyguardAuthenticated(
- false /* strongAuth */);
- }
+ case MODE_DISMISS_BOUNCER:
+ case MODE_UNLOCK_FADING:
+ Trace.beginSection("MODE_DISMISS_BOUNCER or MODE_UNLOCK_FADING");
+ mStatusBarKeyguardViewManager.notifyKeyguardAuthenticated(
+ false /* strongAuth */);
Trace.endSection();
break;
+ case MODE_UNLOCK_COLLAPSING:
case MODE_SHOW_BOUNCER:
- Trace.beginSection("MODE_SHOW_BOUNCER");
+ Trace.beginSection("MODE_UNLOCK_COLLAPSING or MODE_SHOW_BOUNCER");
if (!wasDeviceInteractive) {
mPendingShowBouncer = true;
} else {
@@ -368,51 +393,83 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
return mMode;
}
- private int calculateMode(BiometricSourceType biometricSourceType) {
+ private @WakeAndUnlockMode int calculateMode(BiometricSourceType biometricSourceType) {
+ if (biometricSourceType == BiometricSourceType.FACE
+ || biometricSourceType == BiometricSourceType.IRIS) {
+ return calculateModeForPassiveAuth();
+ } else {
+ return calculateModeForFingerprint();
+ }
+ }
+
+ private @WakeAndUnlockMode int calculateModeForFingerprint() {
boolean unlockingAllowed = mUpdateMonitor.isUnlockingWithBiometricAllowed();
boolean deviceDreaming = mUpdateMonitor.isDreaming();
- boolean face = biometricSourceType == BiometricSourceType.FACE;
- boolean faceStayingOnKeyguard = face && !mKeyguardBypassController.getBypassEnabled();
if (!mUpdateMonitor.isDeviceInteractive()) {
if (!mStatusBarKeyguardViewManager.isShowing()) {
return MODE_ONLY_WAKE;
} else if (mDozeScrimController.isPulsing() && unlockingAllowed) {
+ return MODE_WAKE_AND_UNLOCK_PULSING;
+ } else if (unlockingAllowed || !mUnlockMethodCache.isMethodSecure()) {
+ return MODE_WAKE_AND_UNLOCK;
+ } else {
+ return MODE_SHOW_BOUNCER;
+ }
+ }
+ if (unlockingAllowed && deviceDreaming) {
+ return MODE_WAKE_AND_UNLOCK_FROM_DREAM;
+ }
+ if (mStatusBarKeyguardViewManager.isShowing()) {
+ if (mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing() && unlockingAllowed) {
+ return MODE_DISMISS_BOUNCER;
+ } else if (unlockingAllowed) {
+ return MODE_UNLOCK_COLLAPSING;
+ } else if (!mStatusBarKeyguardViewManager.isBouncerShowing()) {
+ return MODE_SHOW_BOUNCER;
+ }
+ }
+ return MODE_NONE;
+ }
+
+ private @WakeAndUnlockMode int calculateModeForPassiveAuth() {
+ boolean unlockingAllowed = mUpdateMonitor.isUnlockingWithBiometricAllowed();
+ boolean deviceDreaming = mUpdateMonitor.isDreaming();
+ boolean bypass = mKeyguardBypassController.getBypassEnabled();
+
+ if (!mUpdateMonitor.isDeviceInteractive()) {
+ if (!mStatusBarKeyguardViewManager.isShowing()) {
+ return bypass ? MODE_WAKE_AND_UNLOCK : MODE_ONLY_WAKE;
+ } else if (mDozeScrimController.isPulsing() && unlockingAllowed) {
// Let's not wake-up to lock screen when not bypassing, otherwise the notification
// would move as the user tried to tap it.
- return faceStayingOnKeyguard ? MODE_NONE : MODE_WAKE_AND_UNLOCK_PULSING;
- } else if (!face && (unlockingAllowed || !mUnlockMethodCache.isMethodSecure())) {
- return MODE_WAKE_AND_UNLOCK;
- } else if (face) {
+ return bypass ? MODE_WAKE_AND_UNLOCK_PULSING : MODE_NONE;
+ } else {
if (!(mDozeScrimController.isPulsing() && !unlockingAllowed)) {
Log.wtf(TAG, "Face somehow arrived when the device was not interactive");
}
- if (faceStayingOnKeyguard) {
+ if (bypass) {
+ // Wake-up fading out nicely
+ return MODE_WAKE_AND_UNLOCK_PULSING;
+ } else {
// We could theoretically return MODE_NONE, but this means that the device
// would be not interactive, unlocked, and the user would not see the device
// state.
return MODE_ONLY_WAKE;
- } else {
- // Wake-up fading out nicely
- return MODE_WAKE_AND_UNLOCK_PULSING;
}
- } else {
- return MODE_SHOW_BOUNCER;
}
}
- if (unlockingAllowed && deviceDreaming && !faceStayingOnKeyguard) {
- return MODE_WAKE_AND_UNLOCK_FROM_DREAM;
+ if (unlockingAllowed && deviceDreaming) {
+ return bypass ? MODE_WAKE_AND_UNLOCK_FROM_DREAM : MODE_ONLY_WAKE;
}
if (mStatusBarKeyguardViewManager.isShowing()) {
- if ((mStatusBarKeyguardViewManager.isBouncerShowing())
- && unlockingAllowed) {
- return MODE_UNLOCK;
+ if (mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing() && unlockingAllowed) {
+ return bypass && !mKeyguardBypassController.canPlaySubtleWindowAnimations()
+ ? MODE_UNLOCK_COLLAPSING : MODE_UNLOCK_FADING;
} else if (unlockingAllowed) {
- return faceStayingOnKeyguard ? MODE_ONLY_WAKE : MODE_UNLOCK;
- } else if (face) {
- return MODE_NONE;
- } else if (!mStatusBarKeyguardViewManager.isBouncerShowing()) {
- return MODE_SHOW_BOUNCER;
+ return bypass ? MODE_UNLOCK_FADING : MODE_NONE;
+ } else {
+ return bypass ? MODE_SHOW_BOUNCER : MODE_NONE;
}
}
return MODE_NONE;
@@ -504,7 +561,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback {
* on or off.
*/
public boolean isBiometricUnlock() {
- return isWakeAndUnlock() || mMode == MODE_UNLOCK;
+ return isWakeAndUnlock() || mMode == MODE_UNLOCK_COLLAPSING || mMode == MODE_UNLOCK_FADING;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index c44f953615e3..cbaf85c511dd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
+import android.graphics.Region;
import android.util.Log;
import android.util.Pools;
import android.view.DisplayCutout;
@@ -88,7 +89,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
private int[] mTmpTwoArray = new int[2];
private boolean mHeadsUpGoingAway;
private int mStatusBarState;
- private Rect mTouchableRegion = new Rect();
+ private Region mTouchableRegion = new Region();
private AnimationStateHandler mAnimationStateHandler;
@@ -365,10 +366,11 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
info.touchableRegion.set(calculateTouchableRegion());
}
- public Rect calculateTouchableRegion() {
+ public Region calculateTouchableRegion() {
if (!hasPinnedHeadsUp()) {
mTouchableRegion.set(0, 0, mStatusBarWindowView.getWidth(), mStatusBarHeight);
updateRegionForNotch(mTouchableRegion);
+
} else {
NotificationEntry topEntry = getTopEntry();
if (topEntry.isChildInGroup()) {
@@ -388,7 +390,7 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
return mTouchableRegion;
}
- private void updateRegionForNotch(Rect region) {
+ private void updateRegionForNotch(Region region) {
DisplayCutout cutout = mStatusBarWindowView.getRootWindowInsets().getDisplayCutout();
if (cutout == null) {
return;
@@ -460,6 +462,8 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
super.dumpInternal(fd, pw, args);
pw.print(" mBarState=");
pw.println(mStatusBarState);
+ pw.print(" mTouchableRegion=");
+ pw.println(mTouchableRegion);
}
///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index 4691a31fad21..66b1dd8db123 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -27,7 +27,6 @@ import android.view.ViewConfiguration;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.classifier.FalsingManagerFactory;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.KeyguardAffordanceView;
@@ -59,7 +58,7 @@ public class KeyguardAffordanceHelper {
private KeyguardAffordanceView mLeftIcon;
private KeyguardAffordanceView mRightIcon;
private Animator mSwipeAnimator;
- private FalsingManager mFalsingManager;
+ private final FalsingManager mFalsingManager;
private int mMinBackgroundRadius;
private boolean mMotionCancelled;
private int mTouchTargetSize;
@@ -80,12 +79,13 @@ public class KeyguardAffordanceHelper {
}
};
- KeyguardAffordanceHelper(Callback callback, Context context) {
+ KeyguardAffordanceHelper(Callback callback, Context context, FalsingManager falsingManager) {
mContext = context;
mCallback = callback;
initIcons();
updateIcon(mLeftIcon, 0.0f, mLeftIcon.getRestingAlpha(), false, false, true, false);
updateIcon(mRightIcon, 0.0f, mRightIcon.getRestingAlpha(), false, false, true, false);
+ mFalsingManager = falsingManager;
initDimens();
}
@@ -102,7 +102,6 @@ public class KeyguardAffordanceHelper {
mHintGrowAmount =
mContext.getResources().getDimensionPixelSize(R.dimen.hint_grow_amount_sideways);
mFlingAnimationUtils = new FlingAnimationUtils(mContext, 0.4f);
- mFalsingManager = FalsingManagerFactory.getInstance(mContext);
}
private void initIcons() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 4b198dac8145..21a22eccf509 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -346,6 +346,13 @@ public class KeyguardBouncer {
}
/**
+ * {@link #show(boolean)} was called but we're not showing yet.
+ */
+ public boolean willShowSoon() {
+ return mShowingSoon;
+ }
+
+ /**
* @return {@code true} when bouncer's pre-hide animation already started but isn't completely
* hidden yet, {@code false} otherwise.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
index af23ac3e35c6..d7deedce3c2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt
@@ -138,6 +138,20 @@ class KeyguardBypassController {
return false
}
+ /**
+ * If shorter animations should be played when unlocking.
+ */
+ fun canPlaySubtleWindowAnimations(): Boolean {
+ if (bypassEnabled) {
+ return when {
+ statusBarStateController.state != StatusBarState.KEYGUARD -> false
+ qSExpanded -> false
+ else -> true
+ }
+ }
+ return false
+ }
+
fun onStartedGoingToSleep() {
pendingUnlockType = null
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
index 6111178bbac9..b11329ad0135 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissHandler.java
@@ -24,6 +24,7 @@ public interface KeyguardDismissHandler {
/**
* Executes an action that requres the screen to be unlocked, showing the keyguard if
* necessary. Does not close the notification shade (in case it was open).
+ * @param requiresShadeOpen does the shade need to be forced open when hiding the keyguard?
*/
- void executeWhenUnlocked(OnDismissAction action);
+ void executeWhenUnlocked(OnDismissAction action, boolean requiresShadeOpen);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
index e541e14b3d91..834d2a5ae4a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardDismissUtil.java
@@ -37,7 +37,7 @@ public class KeyguardDismissUtil implements KeyguardDismissHandler {
public KeyguardDismissUtil() {
}
- /** Sets the actual {@link DismissHandler} implementation. */
+ /** Sets the actual {@link KeyguardDismissHandler} implementation. */
public void setDismissHandler(KeyguardDismissHandler dismissHandler) {
mDismissHandler = dismissHandler;
}
@@ -46,15 +46,17 @@ public class KeyguardDismissUtil implements KeyguardDismissHandler {
* Executes an action that requires the screen to be unlocked.
*
* <p>Must be called after {@link #setDismissHandler}.
+ *
+ * @param requiresShadeOpen does the shade need to be forced open when hiding the keyguard?
*/
@Override
- public void executeWhenUnlocked(OnDismissAction action) {
+ public void executeWhenUnlocked(OnDismissAction action, boolean requiresShadeOpen) {
KeyguardDismissHandler dismissHandler = mDismissHandler;
if (dismissHandler == null) {
Log.wtf(TAG, "KeyguardDismissHandler not set.");
action.onDismiss();
return;
}
- dismissHandler.executeWhenUnlocked(action);
+ dismissHandler.executeWhenUnlocked(action, requiresShadeOpen);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 6eeb96813c94..971a7eeaca12 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -38,6 +38,7 @@ import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
+import android.graphics.Region;
import android.os.PowerManager;
import android.util.AttributeSet;
import android.util.Log;
@@ -61,7 +62,6 @@ import com.android.systemui.DejankUtils;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.classifier.FalsingManagerFactory;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
import com.android.systemui.plugins.FalsingManager;
@@ -290,7 +290,11 @@ public class NotificationPanelView extends PanelView implements
private boolean mIsFullWidth;
private boolean mBlockingExpansionForCurrentTouch;
- private boolean mExpectingOpenPanelGesture;
+ /**
+ * Following variables maintain state of events when input focus transfer may occur.
+ */
+ private boolean mExpectingSynthesizedDown; // expecting to see synthesized DOWN event
+ private boolean mLastEventSynthesizedDown; // last event was synthesized DOWN event
/**
* Current dark amount that follows regular interpolation curve of animation.
@@ -377,11 +381,12 @@ public class NotificationPanelView extends PanelView implements
NotificationWakeUpCoordinator coordinator,
PulseExpansionHandler pulseExpansionHandler,
DynamicPrivacyController dynamicPrivacyController,
- KeyguardBypassController bypassController) {
+ KeyguardBypassController bypassController,
+ FalsingManager falsingManager) {
super(context, attrs);
setWillNotDraw(!DEBUG);
mInjectionInflationController = injectionInflationController;
- mFalsingManager = FalsingManagerFactory.getInstance(context);
+ mFalsingManager = falsingManager;
mPowerManager = context.getSystemService(PowerManager.class);
mWakeUpCoordinator = coordinator;
mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
@@ -606,7 +611,7 @@ public class NotificationPanelView extends PanelView implements
}
private void initBottomArea() {
- mAffordanceHelper = new KeyguardAffordanceHelper(this, getContext());
+ mAffordanceHelper = new KeyguardAffordanceHelper(this, getContext(), mFalsingManager);
mKeyguardBottomArea.setAffordanceHelper(mAffordanceHelper);
mKeyguardBottomArea.setStatusBar(mStatusBar);
mKeyguardBottomArea.setUserSetupComplete(mUserSetupComplete);
@@ -672,9 +677,10 @@ public class NotificationPanelView extends PanelView implements
private Rect calculateGestureExclusionRect() {
Rect exclusionRect = null;
- if (isFullyCollapsed()) {
+ Region touchableRegion = mHeadsUpManager.calculateTouchableRegion();
+ if (isFullyCollapsed() && touchableRegion != null) {
// Note: The heads up manager also calculates the non-pinned touchable region
- exclusionRect = mHeadsUpManager.calculateTouchableRegion();
+ exclusionRect = touchableRegion.getBounds();
}
return exclusionRect != null
? exclusionRect
@@ -1059,6 +1065,15 @@ public class NotificationPanelView extends PanelView implements
mDownY = event.getY();
mCollapsedOnDown = isFullyCollapsed();
mListenForHeadsUp = mCollapsedOnDown && mHeadsUpManager.hasPinnedHeadsUp();
+ if (mExpectingSynthesizedDown) {
+ mLastEventSynthesizedDown = true;
+ } else {
+ // down but not synthesized motion event.
+ mLastEventSynthesizedDown = false;
+ }
+ } else {
+ // not down event at all.
+ mLastEventSynthesizedDown = false;
}
}
@@ -1124,12 +1139,18 @@ public class NotificationPanelView extends PanelView implements
return false;
}
- initDownStates(event);
// Make sure the next touch won't the blocked after the current ends.
if (event.getAction() == MotionEvent.ACTION_UP
|| event.getAction() == MotionEvent.ACTION_CANCEL) {
mBlockingExpansionForCurrentTouch = false;
}
+ // When touch focus transfer happens, ACTION_DOWN->ACTION_UP may happen immediately
+ // without any ACTION_MOVE event.
+ // In such case, simply expand the panel instead of being stuck at the bottom bar.
+ if (mLastEventSynthesizedDown && event.getAction() == MotionEvent.ACTION_UP) {
+ expand(true /* animate */);
+ }
+ initDownStates(event);
if (!mIsExpanding && !shouldQuickSettingsIntercept(mDownX, mDownY, 0)
&& mPulseExpansionHandler.onTouchEvent(event)) {
// We're expanding all the other ones shouldn't get this anymore
@@ -1255,17 +1276,28 @@ public class NotificationPanelView extends PanelView implements
if (!isFullyCollapsed()) {
return;
}
- mExpectingOpenPanelGesture = true;
+ mExpectingSynthesizedDown = true;
onTrackingStarted();
}
/**
- * Input focus transfer has already happened as this view decided to intercept
- * very first down event.
+ * Called when this view is no longer waiting for input focus transfer.
+ *
+ * There are two scenarios behind this function call. First, input focus transfer
+ * has successfully happened and this view already received synthetic DOWN event.
+ * (mExpectingSynthesizedDown == false). Do nothing.
+ *
+ * Second, before input focus transfer finished, user may have lifted finger
+ * in previous window and this window never received synthetic DOWN event.
+ * (mExpectingSynthesizedDown == true).
+ * In this case, we use the velocity to trigger fling event.
+ *
+ * @param velocity unit is in px / millis
*/
- public void stopWaitingForOpenPanelGesture() {
- if (mExpectingOpenPanelGesture) {
- mExpectingOpenPanelGesture = false;
+ public void stopWaitingForOpenPanelGesture(float velocity) {
+ if (mExpectingSynthesizedDown) {
+ mExpectingSynthesizedDown = false;
+ fling(velocity > 1f ? 1000f * velocity : 0, true /* animate */);
onTrackingStopped(false);
}
}
@@ -1283,8 +1315,8 @@ public class NotificationPanelView extends PanelView implements
@Override
protected boolean shouldGestureWaitForTouchSlop() {
- if (mExpectingOpenPanelGesture) {
- mExpectingOpenPanelGesture = false;
+ if (mExpectingSynthesizedDown) {
+ mExpectingSynthesizedDown = false;
return false;
}
return isFullyCollapsed() || mBarState != StatusBarState.SHADE;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index a5b221bbad8c..853faabbbc81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -42,7 +42,6 @@ import com.android.systemui.DejankUtils;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
-import com.android.systemui.classifier.FalsingManagerFactory;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -110,7 +109,7 @@ public abstract class PanelView extends FrameLayout {
private FlingAnimationUtils mFlingAnimationUtils;
private FlingAnimationUtils mFlingAnimationUtilsClosing;
private FlingAnimationUtils mFlingAnimationUtilsDismissing;
- private FalsingManager mFalsingManager;
+ private final FalsingManager mFalsingManager;
private final VibratorHelper mVibratorHelper;
/**
@@ -213,7 +212,7 @@ public abstract class PanelView extends FrameLayout {
0.5f /* maxLengthSeconds */, 0.2f /* speedUpFactor */, 0.6f /* x2 */,
0.84f /* y2 */);
mBounceInterpolator = new BounceInterpolator();
- mFalsingManager = FalsingManagerFactory.getInstance(context);
+ mFalsingManager = Dependency.get(FalsingManager.class); // TODO: inject into a controller.
mNotificationsDragEnabled =
getResources().getBoolean(R.bool.config_enableNotificationShadeDrag);
mVibratorHelper = Dependency.get(VibratorHelper.class);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 55f61fa8a6a0..aebf1c8e2169 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -80,7 +80,6 @@ import android.metrics.LogMaker;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.os.Debug;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -148,7 +147,6 @@ import com.android.systemui.assist.AssistManager;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.charging.WirelessChargingAnimation;
import com.android.systemui.classifier.FalsingLog;
-import com.android.systemui.classifier.FalsingManagerFactory;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.doze.DozeHost;
import com.android.systemui.doze.DozeLog;
@@ -202,6 +200,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationListController;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
+import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
@@ -695,6 +694,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mRecents = getComponent(Recents.class);
mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+ mFalsingManager = Dependency.get(FalsingManager.class);
// Connect in to the status bar manager service
mCommandQueue = getComponent(CommandQueue.class);
@@ -770,7 +770,6 @@ public class StatusBar extends SystemUI implements DemoMode,
putComponent(DozeHost.class, mDozeServiceHost);
mScreenPinningRequest = new ScreenPinningRequest(mContext);
- mFalsingManager = FalsingManagerFactory.getInstance(mContext);
Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this);
@@ -1232,7 +1231,8 @@ public class StatusBar extends SystemUI implements DemoMode,
new Handler(), mKeyguardUpdateMonitor, mKeyguardBypassController);
mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
getBouncerContainer(), mNotificationPanel, mBiometricUnlockController,
- mStatusBarWindow.findViewById(R.id.lock_icon_container));
+ mStatusBarWindow.findViewById(R.id.lock_icon_container), mStackScroller,
+ mKeyguardBypassController, mFalsingManager);
mKeyguardIndicationController
.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
@@ -1930,15 +1930,16 @@ public class StatusBar extends SystemUI implements DemoMode,
/**
* Called when another window is about to transfer it's input focus.
*/
- public void onInputFocusTransfer(boolean start) {
+ public void onInputFocusTransfer(boolean start, float velocity) {
if (!mCommandQueue.panelsEnabled()) {
return;
}
if (start) {
mNotificationPanel.startWaitingForOpenPanelGesture();
+ setPanelExpanded(true);
} else {
- mNotificationPanel.stopWaitingForOpenPanelGesture();
+ mNotificationPanel.stopWaitingForOpenPanelGesture(velocity);
}
}
@@ -2389,7 +2390,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mKeyguardUpdateMonitor.dump(fd, pw, args);
}
- FalsingManagerFactory.getInstance(mContext).dump(pw);
+ Dependency.get(FalsingManager.class).dump(pw);
FalsingLog.dump(pw);
pw.println("SharedPreferences:");
@@ -2618,8 +2619,8 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}
- private void executeWhenUnlocked(OnDismissAction action) {
- if (mStatusBarKeyguardViewManager.isShowing()) {
+ private void executeWhenUnlocked(OnDismissAction action, boolean requiresShadeOpen) {
+ if (mStatusBarKeyguardViewManager.isShowing() && requiresShadeOpen) {
mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
}
dismissKeyguardThenExecute(action, null /* cancelAction */, false /* afterKeyguardGone */);
@@ -3169,6 +3170,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationPanel.onAffordanceLaunchEnded();
mNotificationPanel.animate().cancel();
mNotificationPanel.setAlpha(1f);
+ ViewGroupFadeHelper.reset(mNotificationPanel);
updateScrimController();
Trace.endSection();
return staying;
@@ -3433,7 +3435,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationPanel.resetViews(dozingAnimated);
updateQsExpansionEnabled();
- mKeyguardViewMediator.setAodShowing(mDozing);
+ mKeyguardViewMediator.setDozing(mDozing);
mEntryManager.updateNotifications();
updateDozingState();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 462b65f37ee0..d67818273ef2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone;
import static com.android.systemui.plugins.ActivityStarter.OnDismissAction;
+import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_UNLOCK_FADING;
import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
@@ -43,6 +44,7 @@ import com.android.systemui.Dependency;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.dock.DockManager;
import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.CommandQueue;
@@ -51,6 +53,7 @@ import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -82,6 +85,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
// make everything a bit slower to bridge a gap until the user is unlocked and home screen has
// dranw its first frame.
private static final long KEYGUARD_DISMISS_DURATION_LOCKED = 2000;
+ private static final long BYPASS_PANEL_FADE_DURATION = 67;
private static String TAG = "StatusBarKeyguardViewManager";
@@ -132,6 +136,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
private ViewGroup mContainer;
private ViewGroup mLockIconContainer;
+ private View mNotificationContainer;
protected KeyguardBouncer mBouncer;
protected boolean mShowing;
@@ -165,9 +170,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
(KeyguardMonitorImpl) Dependency.get(KeyguardMonitor.class);
private final NotificationMediaManager mMediaManager =
Dependency.get(NotificationMediaManager.class);
- private final StatusBarStateController mStatusBarStateController =
- Dependency.get(StatusBarStateController.class);
+ private final SysuiStatusBarStateController mStatusBarStateController =
+ (SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class);
private final DockManager mDockManager;
+ private KeyguardBypassController mBypassController;
private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
new KeyguardUpdateMonitorCallback() {
@@ -205,7 +211,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
NotificationPanelView notificationPanelView,
BiometricUnlockController biometricUnlockController,
DismissCallbackRegistry dismissCallbackRegistry,
- ViewGroup lockIconContainer) {
+ ViewGroup lockIconContainer, View notificationContainer,
+ KeyguardBypassController bypassController, FalsingManager falsingManager) {
mStatusBar = statusBar;
mContainer = container;
mLockIconContainer = lockIconContainer;
@@ -215,9 +222,11 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mBiometricUnlockController = biometricUnlockController;
mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext,
mViewMediatorCallback, mLockPatternUtils, container, dismissCallbackRegistry,
- mExpansionCallback);
+ mExpansionCallback, falsingManager);
mNotificationPanelView = notificationPanelView;
notificationPanelView.setExpansionListener(this);
+ mBypassController = bypassController;
+ mNotificationContainer = notificationContainer;
}
@Override
@@ -555,12 +564,32 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mBiometricUnlockController.startKeyguardFadingAway();
hideBouncer(true /* destroyView */);
if (wakeUnlockPulsing) {
- mStatusBar.fadeKeyguardWhilePulsing();
+ if (needsBypassFading()) {
+ ViewGroupFadeHelper.fadeOutAllChildrenExcept(mNotificationPanelView,
+ mNotificationContainer,
+ BYPASS_PANEL_FADE_DURATION,
+ () -> {
+ mStatusBar.hideKeyguard();
+ onKeyguardFadedAway();
+ });
+ } else {
+ mStatusBar.fadeKeyguardWhilePulsing();
+ }
wakeAndUnlockDejank();
} else {
- boolean staying = mStatusBar.hideKeyguard();
+ boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide();
if (!staying) {
mStatusBarWindowController.setKeyguardFadingAway(true);
+ if (needsBypassFading()) {
+ ViewGroupFadeHelper.fadeOutAllChildrenExcept(mNotificationPanelView,
+ mNotificationContainer,
+ BYPASS_PANEL_FADE_DURATION,
+ () -> {
+ mStatusBar.hideKeyguard();
+ });
+ } else {
+ mStatusBar.hideKeyguard();
+ }
// hide() will happen asynchronously and might arrive after the scrims
// were already hidden, this means that the transition callback won't
// be triggered anymore and StatusBarWindowController will be forever in
@@ -568,6 +597,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mStatusBar.updateScrimController();
wakeAndUnlockDejank();
} else {
+ mStatusBar.hideKeyguard();
mStatusBar.finishKeyguardFadingAway();
mBiometricUnlockController.finishKeyguardFadingAway();
}
@@ -580,6 +610,13 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
StatsLog.KEYGUARD_STATE_CHANGED__STATE__HIDDEN);
}
+ private boolean needsBypassFading() {
+ return (mBiometricUnlockController.getMode() == MODE_UNLOCK_FADING
+ || mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING
+ || mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK)
+ && mBypassController.getBypassEnabled();
+ }
+
@Override
public void onDensityOrFontScaleChanged() {
hideBouncer(true /* destroyView */);
@@ -602,6 +639,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
public void onKeyguardFadedAway() {
mContainer.postDelayed(() -> mStatusBarWindowController.setKeyguardFadingAway(false),
100);
+ ViewGroupFadeHelper.reset(mNotificationPanelView);
mStatusBar.finishKeyguardFadingAway();
mBiometricUnlockController.finishKeyguardFadingAway();
WindowManagerGlobal.getInstance().trimMemory(
@@ -677,6 +715,14 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
return mBouncer.isShowing();
}
+ /**
+ * When bouncer is fully visible or {@link KeyguardBouncer#show(boolean)} was called but
+ * animation didn't finish yet.
+ */
+ public boolean bouncerIsOrWillBeShowing() {
+ return mBouncer.isShowing() || mBouncer.willShowSoon();
+ }
+
public boolean isFullscreenBouncer() {
return mBouncer.isFullscreenBouncer();
}
@@ -726,6 +772,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) {
mStatusBarWindowController.setBouncerShowing(bouncerShowing);
mStatusBar.setBouncerShowing(bouncerShowing);
+ updateLockIcon();
}
KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
@@ -813,8 +860,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
* @return Whether subtle animation should be used for unlocking the device.
*/
public boolean shouldSubtleWindowAnimationsForUnlock() {
- return mStatusBar.mKeyguardBypassController.getBypassEnabled()
- && mStatusBar.mState == StatusBarState.KEYGUARD && !mBouncer.isAnimatingAway();
+ return needsBypassFading();
}
public boolean isGoingToNotificationShade() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 6691f7a759f3..13d4b8edb8d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -48,6 +48,7 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.RemoteInputView;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -93,9 +94,11 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks,
@Override
public void onStateChanged(int state) {
- if (state == StatusBarState.SHADE && mStatusBarStateController.leaveOpenOnKeyguardHide()) {
+ boolean hasPendingRemoteInput = mPendingRemoteInputView != null;
+ if (state == StatusBarState.SHADE
+ && (mStatusBarStateController.leaveOpenOnKeyguardHide() || hasPendingRemoteInput)) {
if (!mStatusBarStateController.isKeyguardRequested()) {
- if (mPendingRemoteInputView != null) {
+ if (hasPendingRemoteInput) {
mMainHandler.post(mPendingRemoteInputView::callOnClick);
}
mPendingRemoteInputView = null;
@@ -105,7 +108,9 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks,
@Override
public void onLockedRemoteInput(ExpandableNotificationRow row, View clicked) {
- mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
+ if (!row.isPinned()) {
+ mStatusBarStateController.setLeaveOpenOnKeyguardHide(true);
+ }
mShadeController.showBouncer(true /* scrimmed */);
mPendingRemoteInputView = clicked;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 94054188d769..f1049f005dea 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -62,7 +62,6 @@ import com.android.internal.widget.FloatingToolbar;
import com.android.systemui.Dependency;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
-import com.android.systemui.classifier.FalsingManagerFactory;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.DragDownHelper;
@@ -156,7 +155,7 @@ public class StatusBarWindowView extends FrameLayout {
setMotionEventSplittingEnabled(false);
mTransparentSrcPaint.setColor(0);
mTransparentSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
- mFalsingManager = FalsingManagerFactory.getInstance(context);
+ mFalsingManager = Dependency.get(FalsingManager.class); // TODO: inject into a controller.
mGestureDetector = new GestureDetector(context, mGestureListener);
mStatusBarStateController = Dependency.get(StatusBarStateController.class);
Dependency.get(TunerService.class).addTunable(mTunable,
@@ -290,7 +289,7 @@ public class StatusBarWindowView extends FrameLayout {
ExpandHelper.Callback expandHelperCallback = stackScrollLayout.getExpandHelperCallback();
DragDownHelper.DragDownCallback dragDownCallback = stackScrollLayout.getDragDownCallback();
setDragDownHelper(new DragDownHelper(getContext(), this, expandHelperCallback,
- dragDownCallback));
+ dragDownCallback, mFalsingManager));
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index 48a9fb67c17b..e61a67c77602 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -20,7 +20,6 @@ import android.app.AlertDialog;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.UserHandle;
@@ -34,10 +33,13 @@ import com.android.systemui.statusbar.policy.KeyguardMonitor;
/**
* Base class for dialogs that should appear over panels and keyguard.
+ * The SystemUIDialog registers a listener for the screen off / close system dialogs broadcast,
+ * and dismisses itself when it receives the broadcast.
*/
public class SystemUIDialog extends AlertDialog {
private final Context mContext;
+ private final DismissReceiver mDismissReceiver;
public SystemUIDialog(Context context) {
this(context, R.style.Theme_SystemUI_Dialog);
@@ -52,7 +54,19 @@ public class SystemUIDialog extends AlertDialog {
attrs.setTitle(getClass().getSimpleName());
getWindow().setAttributes(attrs);
- registerDismissListener(this);
+ mDismissReceiver = new DismissReceiver(this);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mDismissReceiver.register();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mDismissReceiver.unregister();
}
public void setShowForAllUsers(boolean show) {
@@ -100,12 +114,22 @@ public class SystemUIDialog extends AlertDialog {
return dialog;
}
+ /**
+ * Registers a listener that dismisses the given dialog when it receives
+ * the screen off / close system dialogs broadcast.
+ * <p>
+ * <strong>Note:</strong> Don't call dialog.setOnDismissListener() after
+ * calling this because it causes a leak of BroadcastReceiver.
+ *
+ * @param dialog The dialog to be associated with the listener.
+ */
public static void registerDismissListener(Dialog dialog) {
DismissReceiver dismissReceiver = new DismissReceiver(dialog);
+ dialog.setOnDismissListener(d -> dismissReceiver.unregister());
dismissReceiver.register();
}
- private static class DismissReceiver extends BroadcastReceiver implements OnDismissListener {
+ private static class DismissReceiver extends BroadcastReceiver {
private static final IntentFilter INTENT_FILTER = new IntentFilter();
static {
INTENT_FILTER.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
@@ -125,16 +149,16 @@ public class SystemUIDialog extends AlertDialog {
mRegistered = true;
}
- @Override
- public void onReceive(Context context, Intent intent) {
- mDialog.dismiss();
- }
-
- @Override
- public void onDismiss(DialogInterface dialog) {
+ void unregister() {
if (mRegistered) {
mDialog.getContext().unregisterReceiver(this);
mRegistered = false;
}
}
- }}
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mDialog.dismiss();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 78e845a68445..40c3d9d19c16 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -294,6 +294,18 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
}
@Override
+ public void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice,
+ int state, int bluetoothProfile) {
+ if (DEBUG) {
+ Log.d(TAG, "ProfileConnectionStateChanged=" + cachedDevice.getAddress() + " "
+ + stateToString(state) + " profileId=" + bluetoothProfile);
+ }
+ mCachedState.remove(cachedDevice);
+ updateConnected();
+ mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
+ }
+
+ @Override
public void onAclConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
if (DEBUG) {
Log.d(TAG, "ACLConnectionStateChanged=" + cachedDevice.getAddress() + " "
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index b21ba096c361..45627631efe1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -163,7 +163,8 @@ public class MobileSignalController extends SignalController<
| PhoneStateListener.LISTEN_CALL_STATE
| PhoneStateListener.LISTEN_DATA_CONNECTION_STATE
| PhoneStateListener.LISTEN_DATA_ACTIVITY
- | PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE);
+ | PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE
+ | PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
mContext.getContentResolver().registerContentObserver(Global.getUriFor(Global.MOBILE_DATA),
true, mObserver);
mContext.getContentResolver().registerContentObserver(Global.getUriFor(
@@ -636,6 +637,13 @@ public class MobileSignalController extends SignalController<
updateTelephony();
}
+
+ @Override
+ public void onActiveDataSubscriptionIdChanged(int subId) {
+ if (DEBUG) Log.d(mTag, "onActiveDataSubscriptionIdChanged: subId=" + subId);
+ updateDataSim();
+ updateTelephony();
+ }
};
static class MobileIconGroup extends SignalController.IconGroup {
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 640f0f0cc3f6..282d28c3b20c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -303,7 +303,7 @@ public class SmartReplyView extends ViewGroup {
};
OnClickListener onClickListener = view ->
- smartReplyView.mKeyguardDismissUtil.executeWhenUnlocked(action);
+ smartReplyView.mKeyguardDismissUtil.executeWhenUnlocked(action, !entry.isRowPinned());
if (useDelayedOnClickListener) {
onClickListener = new DelayedOnClickListener(onClickListener,
smartReplyView.mConstants.getOnClickInitDelay());
diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
index ede30046d6c3..9b264c4a326e 100644
--- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
@@ -26,7 +26,7 @@ import android.view.View;
import com.android.keyguard.KeyguardClockSwitch;
import com.android.keyguard.KeyguardMessageArea;
import com.android.keyguard.KeyguardSliceView;
-import com.android.systemui.SystemUIFactory;
+import com.android.systemui.SystemUIRootComponent;
import com.android.systemui.qs.QSCarrierGroup;
import com.android.systemui.qs.QSFooterImpl;
import com.android.systemui.qs.QSPanel;
@@ -62,7 +62,7 @@ public class InjectionInflationController {
private final LayoutInflater.Factory2 mFactory = new InjectionFactory();
@Inject
- public InjectionInflationController(SystemUIFactory.SystemUIRootComponent rootComponent) {
+ public InjectionInflationController(SystemUIRootComponent rootComponent) {
mViewCreator = rootComponent.createViewCreator();
initInjectionMap();
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 69d2e31135e8..3f3e1e32a951 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -243,8 +243,11 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
pw.print(" mState: "); pw.println(mState.toString(4));
pw.print(" mShowDndTile: "); pw.println(mShowDndTile);
pw.print(" mHasVibrator: "); pw.println(mHasVibrator);
- pw.print(" mRemoteStreams: "); pw.println(mMediaSessionsCallbacksW.mRemoteStreams
- .values());
+ synchronized (mMediaSessionsCallbacksW.mRemoteStreams) {
+ pw.print(" mRemoteStreams: ");
+ pw.println(mMediaSessionsCallbacksW.mRemoteStreams
+ .values());
+ }
pw.print(" mShowA11yStream: "); pw.println(mShowA11yStream);
pw.println();
mMediaSessions.dump(pw);
@@ -1075,7 +1078,10 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
@Override
public void onRemoteUpdate(Token token, String name, PlaybackInfo pi) {
addStream(token, "onRemoteUpdate");
- final int stream = mRemoteStreams.get(token);
+ int stream = 0;
+ synchronized (mRemoteStreams) {
+ stream = mRemoteStreams.get(token);
+ }
boolean changed = mState.states.indexOfKey(stream) < 0;
final StreamState ss = streamStateW(stream);
ss.dynamic = true;
@@ -1100,7 +1106,10 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
@Override
public void onRemoteVolumeChanged(Token token, int flags) {
addStream(token, "onRemoteVolumeChanged");
- final int stream = mRemoteStreams.get(token);
+ int stream = 0;
+ synchronized (mRemoteStreams) {
+ stream = mRemoteStreams.get(token);
+ }
final boolean showUI = shouldShowUI(flags);
boolean changed = updateActiveStreamW(stream);
if (showUI) {
@@ -1116,12 +1125,15 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
@Override
public void onRemoteRemoved(Token token) {
- if (!mRemoteStreams.containsKey(token)) {
- if (D.BUG) Log.d(TAG, "onRemoteRemoved: stream doesn't exist, "
- + "aborting remote removed for token:" + token.toString());
- return;
+ int stream = 0;
+ synchronized (mRemoteStreams) {
+ if (!mRemoteStreams.containsKey(token)) {
+ if (D.BUG) Log.d(TAG, "onRemoteRemoved: stream doesn't exist, "
+ + "aborting remote removed for token:" + token.toString());
+ return;
+ }
+ stream = mRemoteStreams.get(token);
}
- final int stream = mRemoteStreams.get(token);
mState.states.remove(stream);
if (mState.activeStream == stream) {
updateActiveStreamW(-1);
@@ -1139,20 +1151,24 @@ public class VolumeDialogControllerImpl implements VolumeDialogController, Dumpa
}
private Token findToken(int stream) {
- for (Map.Entry<Token, Integer> entry : mRemoteStreams.entrySet()) {
- if (entry.getValue().equals(stream)) {
- return entry.getKey();
+ synchronized (mRemoteStreams) {
+ for (Map.Entry<Token, Integer> entry : mRemoteStreams.entrySet()) {
+ if (entry.getValue().equals(stream)) {
+ return entry.getKey();
+ }
}
}
return null;
}
private void addStream(Token token, String triggeringMethod) {
- if (!mRemoteStreams.containsKey(token)) {
- mRemoteStreams.put(token, mNextStream);
- if (D.BUG) Log.d(TAG, triggeringMethod + ": added stream " + mNextStream
- + " from token + "+ token.toString());
- mNextStream++;
+ synchronized (mRemoteStreams) {
+ if (!mRemoteStreams.containsKey(token)) {
+ mRemoteStreams.put(token, mNextStream);
+ if (D.BUG) Log.d(TAG, triggeringMethod + ": added stream " + mNextStream
+ + " from token + " + token.toString());
+ mNextStream++;
+ }
}
}
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 2e02fd598e56..bdc6341bde91 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -317,13 +318,44 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
@Test
public void skipsAuthentication_whenEncryptedKeyguard() {
- reset(mUserManager);
- when(mUserManager.isUserUnlocked(anyInt())).thenReturn(false);
+ when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(
+ KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT);
+ mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController);
mKeyguardUpdateMonitor.dispatchStartedWakingUp();
mTestableLooper.processAllMessages();
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any());
+ verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
+ }
+
+ @Test
+ public void requiresAuthentication_whenEncryptedKeyguard_andBypass() {
+ testStrongAuthExceptOnBouncer(
+ KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT);
+ }
+
+ @Test
+ public void requiresAuthentication_whenTimeoutKeyguard_andBypass() {
+ testStrongAuthExceptOnBouncer(
+ KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT);
+ }
+
+ private void testStrongAuthExceptOnBouncer(int strongAuth) {
+ when(mKeyguardBypassController.canBypass()).thenReturn(true);
+ mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController);
+ when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(strongAuth);
+
+ mKeyguardUpdateMonitor.dispatchStartedWakingUp();
+ mTestableLooper.processAllMessages();
+ mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+ verify(mFaceManager).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
+
+ // Stop scanning when bouncer becomes visible
+ mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true /* showingBouncer */);
+ mTestableLooper.processAllMessages();
+ clearInvocations(mFaceManager);
+ mKeyguardUpdateMonitor.requestFaceAuth();
+ verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
}
@Test
@@ -357,6 +389,28 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
}
@Test
+ public void testIgnoresAuth_whenLockdown() {
+ mKeyguardUpdateMonitor.dispatchStartedWakingUp();
+ mTestableLooper.processAllMessages();
+ when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(
+ KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+
+ mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+ verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
+ }
+
+ @Test
+ public void testIgnoresAuth_whenLockout() {
+ mKeyguardUpdateMonitor.dispatchStartedWakingUp();
+ mTestableLooper.processAllMessages();
+ when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(
+ KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT);
+
+ mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
+ verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
+ }
+
+ @Test
public void testOnFaceAuthenticated_skipsFaceWhenAuthenticated() {
mKeyguardUpdateMonitor.onFaceAuthenticated(KeyguardUpdateMonitor.getCurrentUser());
mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
index b81e04821463..da25eed4a24e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationRemoteInputManagerTest.java
@@ -1,3 +1,4 @@
+
package com.android.systemui.statusbar;
import static junit.framework.Assert.assertEquals;
@@ -22,12 +23,14 @@ import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationRemoteInputManager.RemoteInputActiveExtender;
import com.android.systemui.statusbar.NotificationRemoteInputManager.RemoteInputHistoryExtender;
import com.android.systemui.statusbar.NotificationRemoteInputManager.SmartReplyHistoryExtender;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.ShadeController;
import com.google.android.collect.Sets;
@@ -54,6 +57,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
@Mock private SmartReplyController mSmartReplyController;
@Mock private NotificationListenerService.RankingMap mRanking;
@Mock private ExpandableNotificationRow mRow;
+ @Mock private StatusBarStateController mStateController;
// Dependency mocks:
@Mock private NotificationEntryManager mEntryManager;
@@ -73,6 +77,7 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
mRemoteInputManager = new TestableNotificationRemoteInputManager(mContext,
mLockscreenUserManager, mSmartReplyController, mEntryManager,
() -> mock(ShadeController.class),
+ mStateController,
Handler.createAsync(Looper.myLooper()));
mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID,
0, new Notification(), UserHandle.CURRENT, null, 0);
@@ -196,15 +201,15 @@ public class NotificationRemoteInputManagerTest extends SysuiTestCase {
private class TestableNotificationRemoteInputManager extends NotificationRemoteInputManager {
-
TestableNotificationRemoteInputManager(Context context,
NotificationLockscreenUserManager lockscreenUserManager,
SmartReplyController smartReplyController,
NotificationEntryManager notificationEntryManager,
Lazy<ShadeController> shadeController,
+ StatusBarStateController statusBarStateController,
Handler mainHandler) {
super(context, lockscreenUserManager, smartReplyController, notificationEntryManager,
- shadeController, mainHandler);
+ shadeController, statusBarStateController, mainHandler);
}
public void setUpWithPresenterForTest(Callback callback,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
index 81e373a8be27..185723ffa09b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SmartReplyControllerTest.java
@@ -38,6 +38,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -70,6 +71,7 @@ public class SmartReplyControllerTest extends SysuiTestCase {
@Mock private StatusBarNotification mSbn;
@Mock private NotificationEntryManager mNotificationEntryManager;
@Mock private IStatusBarService mIStatusBarService;
+ @Mock private StatusBarStateController mStatusBarStateController;
@Before
public void setUp() {
@@ -85,6 +87,7 @@ public class SmartReplyControllerTest extends SysuiTestCase {
mRemoteInputManager = new NotificationRemoteInputManager(mContext,
mock(NotificationLockscreenUserManager.class), mSmartReplyController,
mNotificationEntryManager, () -> mock(ShadeController.class),
+ mStatusBarStateController,
Handler.createAsync(Looper.myLooper()));
mRemoteInputManager.setUpWithCallback(mCallback, mDelegate);
mNotification = new Notification.Builder(mContext, "")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 92173ccbad2e..c1911eef6671 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -53,6 +53,7 @@ import com.android.systemui.ExpandHelper;
import com.android.systemui.InitController;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.EmptyShadeView;
@@ -79,7 +80,6 @@ import com.android.systemui.statusbar.phone.StatusBarTest.TestableNotificationEn
import com.android.systemui.statusbar.policy.ConfigurationController;
import org.junit.After;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -164,7 +164,8 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mock(ActivityStarterDelegate.class),
mock(StatusBarStateController.class),
mHeadsUpManager,
- mKeyguardBypassController);
+ mKeyguardBypassController,
+ new FalsingManagerFake());
mStackScroller = spy(mStackScrollerInternal);
mStackScroller.setShelf(notificationShelf);
mStackScroller.setStatusBar(mBar);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
index b24c3ddc1199..06a2eecd208c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java
@@ -40,6 +40,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.SwipeHelper;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -76,7 +77,8 @@ public class NotificationSwipeHelperTest extends SysuiTestCase {
public void setUp() throws Exception {
mCallback = mock(NotificationSwipeHelper.NotificationCallback.class);
mListener = mock(NotificationMenuRowPlugin.OnMenuEventListener.class);
- mSwipeHelper = spy(new NotificationSwipeHelper(SwipeHelper.X, mCallback, mContext, mListener));
+ mSwipeHelper = spy(new NotificationSwipeHelper(
+ SwipeHelper.X, mCallback, mContext, mListener, new FalsingManagerFake()));
mView = mock(View.class);
mEvent = mock(MotionEvent.class);
mMenuRow = mock(NotificationMenuRowPlugin.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
index 4e86f194c0cf..a99dc7fb6924 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java
@@ -82,6 +82,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
when(mUpdateMonitor.isDeviceInteractive()).thenReturn(true);
when(mUnlockMethodCache.isUnlockingWithFacePossible()).thenReturn(true);
when(mKeyguardBypassController.onBiometricAuthenticated(any())).thenReturn(true);
+ when(mKeyguardBypassController.canPlaySubtleWindowAnimations()).thenReturn(true);
mContext.addMockSystemService(PowerManager.class, mPowerManager);
mDependency.injectTestDependency(NotificationMediaManager.class, mMediaManager);
mDependency.injectTestDependency(StatusBarWindowController.class,
@@ -120,13 +121,13 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
BiometricSourceType.FINGERPRINT);
verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
- verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
+ verify(mStatusBarKeyguardViewManager).animateCollapsePanels(anyFloat());
}
@Test
public void onBiometricAuthenticated_whenFingerprintOnBouncer_dismissBouncer() {
when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
- when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
+ when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
BiometricSourceType.FINGERPRINT);
@@ -140,6 +141,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
BiometricSourceType.FACE);
verify(mStatusBarKeyguardViewManager, never()).animateCollapsePanels(anyFloat());
+ verify(mStatusBarKeyguardViewManager, never()).notifyKeyguardAuthenticated(anyBoolean());
}
@Test
@@ -151,13 +153,38 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase {
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
BiometricSourceType.FACE);
+ verify(mStatusBarKeyguardViewManager, never()).animateCollapsePanels(anyFloat());
verify(mStatusBarKeyguardViewManager).notifyKeyguardAuthenticated(eq(false));
}
@Test
+ public void onBiometricAuthenticated_whenFace_andBypass_encrypted_showBouncer() {
+ when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
+ mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
+
+ when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(false);
+ mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
+ BiometricSourceType.FACE);
+
+ verify(mStatusBarKeyguardViewManager).showBouncer(eq(false));
+ }
+
+ @Test
+ public void onBiometricAuthenticated_whenFace_noBypass_encrypted_doNothing() {
+ mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
+
+ when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(false);
+ mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
+ BiometricSourceType.FACE);
+
+ verify(mStatusBarKeyguardViewManager, never()).showBouncer(anyBoolean());
+ verify(mStatusBarKeyguardViewManager, never()).animateCollapsePanels(anyFloat());
+ }
+
+ @Test
public void onBiometricAuthenticated_whenFaceOnBouncer_dismissBouncer() {
when(mUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
- when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
+ when(mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()).thenReturn(true);
mBiometricUnlockController.onBiometricAuthenticated(UserHandle.USER_CURRENT,
BiometricSourceType.FACE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index d14b460d8c63..a96efd7d2fc2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -36,6 +36,7 @@ import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -98,6 +99,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
private PanelBar mPanelBar;
@Mock
private KeyguardAffordanceHelper mAffordanceHelper;
+ @Mock
+ private FalsingManager mFalsingManager;
private NotificationPanelView mNotificationPanelView;
@Before
@@ -191,7 +194,8 @@ public class NotificationPanelViewTest extends SysuiTestCase {
new InjectionInflationController(
SystemUIFactory.getInstance().getRootComponent()),
coordinator, expansionHandler, mock(DynamicPrivacyController.class),
- bypassController);
+ bypassController,
+ mFalsingManager);
mNotificationStackScroller = mNotificationStackScrollLayout;
mKeyguardStatusView = NotificationPanelViewTest.this.mKeyguardStatusView;
mKeyguardStatusBar = NotificationPanelViewTest.this.mKeyguardStatusBar;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index f50cf5a70cdc..63f653b0b303 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.phone;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -29,16 +30,21 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewPropertyAnimator;
import androidx.test.filters.SmallTest;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
+import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
import org.junit.Before;
import org.junit.Test;
@@ -70,7 +76,11 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
@Mock
private ViewGroup mLockIconContainer;
@Mock
- private StatusBarStateController mStatusBarStateController;
+ private SysuiStatusBarStateController mStatusBarStateController;
+ @Mock
+ private View mNotificationContainer;
+ @Mock
+ private KeyguardBypassController mBypassController;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Before
@@ -79,11 +89,14 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
mDependency.injectMockDependency(StatusBarWindowController.class);
mDependency.injectTestDependency(StatusBarStateController.class, mStatusBarStateController);
when(mLockIconContainer.getParent()).thenReturn(mock(ViewGroup.class));
+ when(mLockIconContainer.animate()).thenReturn(mock(ViewPropertyAnimator.class,
+ RETURNS_DEEP_STUBS));
mStatusBarKeyguardViewManager = new TestableStatusBarKeyguardViewManager(getContext(),
mViewMediatorCallback, mLockPatternUtils);
mStatusBarKeyguardViewManager.registerStatusBar(mStatusBar, mContainer,
mNotificationPanelView, mBiometrucUnlockController, mDismissCallbackRegistry,
- mLockIconContainer);
+ mLockIconContainer, mNotificationContainer, mBypassController,
+ new FalsingManagerFake());
mStatusBarKeyguardViewManager.show(null);
}
@@ -221,10 +234,12 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
NotificationPanelView notificationPanelView,
BiometricUnlockController fingerprintUnlockController,
DismissCallbackRegistry dismissCallbackRegistry,
- ViewGroup lockIconContainer) {
+ ViewGroup lockIconContainer, View notificationContainer,
+ KeyguardBypassController bypassController, FalsingManager falsingManager) {
super.registerStatusBar(statusBar, container, notificationPanelView,
- fingerprintUnlockController, dismissCallbackRegistry, lockIconContainer);
+ fingerprintUnlockController, dismissCallbackRegistry, lockIconContainer,
+ notificationContainer, bypassController, falsingManager);
mBouncer = StatusBarKeyguardViewManagerTest.this.mBouncer;
}
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
index ca648234a24e..a9a1392fb80b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
@@ -17,9 +17,11 @@ package com.android.systemui.statusbar.phone;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -52,13 +54,18 @@ public class SystemUIDialogTest extends SysuiTestCase {
@Test
public void testRegisterReceiver() {
+ final ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
final ArgumentCaptor<IntentFilter> intentFilterCaptor =
ArgumentCaptor.forClass(IntentFilter.class);
- verify(mContextSpy).registerReceiverAsUser(any(), any(),
+ mDialog.show();
+ verify(mContextSpy).registerReceiverAsUser(broadcastReceiverCaptor.capture(), any(),
intentFilterCaptor.capture(), any(), any());
assertTrue(intentFilterCaptor.getValue().hasAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
- }
+ mDialog.dismiss();
+ verify(mContextSpy).unregisterReceiver(eq(broadcastReceiverCaptor.getValue()));
+ }
}
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 8c5fac47885f..0cb575483466 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
@@ -109,7 +109,9 @@ public class SmartReplyViewTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
mReceiver = new BlockingQueueIntentReceiver();
mContext.registerReceiver(mReceiver, new IntentFilter(TEST_ACTION));
- mDependency.get(KeyguardDismissUtil.class).setDismissHandler(action -> action.onDismiss());
+ mDependency.get(KeyguardDismissUtil.class).setDismissHandler((action, unused) -> {
+ action.onDismiss();
+ });
mDependency.injectMockDependency(ShadeController.class);
mDependency.injectTestDependency(ActivityStarter.class, mActivityStarter);
mDependency.injectTestDependency(SmartReplyConstants.class, mConstants);
@@ -162,7 +164,7 @@ public class SmartReplyViewTest extends SysuiTestCase {
@Test
public void testSendSmartReply_keyguardCancelled() throws InterruptedException {
- mDependency.get(KeyguardDismissUtil.class).setDismissHandler(action -> {});
+ mDependency.get(KeyguardDismissUtil.class).setDismissHandler((action, unused) -> {});
setSmartReplies(TEST_CHOICES);
mView.getChildAt(2).performClick();
@@ -173,7 +175,9 @@ public class SmartReplyViewTest extends SysuiTestCase {
@Test
public void testSendSmartReply_waitsForKeyguard() throws InterruptedException {
AtomicReference<OnDismissAction> actionRef = new AtomicReference<>();
- mDependency.get(KeyguardDismissUtil.class).setDismissHandler(actionRef::set);
+ mDependency.get(KeyguardDismissUtil.class).setDismissHandler((action, unused) -> {
+ actionRef.set(action);
+ });
setSmartReplies(TEST_CHOICES);
mView.getChildAt(2).performClick();
diff --git a/packages/overlays/AccentColorBlackOverlay/Android.mk b/packages/overlays/AccentColorBlackOverlay/Android.mk
index a689defe5b6b..86d873dcab66 100644
--- a/packages/overlays/AccentColorBlackOverlay/Android.mk
+++ b/packages/overlays/AccentColorBlackOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := AccentColorBlack
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := AccentColorBlackOverlay
diff --git a/packages/overlays/AccentColorCinnamonOverlay/Android.mk b/packages/overlays/AccentColorCinnamonOverlay/Android.mk
index 3a6cbe3a182a..a8d3f10cfb9e 100644
--- a/packages/overlays/AccentColorCinnamonOverlay/Android.mk
+++ b/packages/overlays/AccentColorCinnamonOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := AccentColorCinnamon
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := AccentColorCinnamonOverlay
diff --git a/packages/overlays/AccentColorGreenOverlay/Android.mk b/packages/overlays/AccentColorGreenOverlay/Android.mk
index d96dbe17b103..c3aa6a87a2f1 100644
--- a/packages/overlays/AccentColorGreenOverlay/Android.mk
+++ b/packages/overlays/AccentColorGreenOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := AccentColorGreen
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := AccentColorGreenOverlay
diff --git a/packages/overlays/AccentColorOceanOverlay/Android.mk b/packages/overlays/AccentColorOceanOverlay/Android.mk
index cf0c6b310f02..96fbee4bbe74 100644
--- a/packages/overlays/AccentColorOceanOverlay/Android.mk
+++ b/packages/overlays/AccentColorOceanOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := AccentColorOcean
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := AccentColorOceanOverlay
diff --git a/packages/overlays/AccentColorOrchidOverlay/Android.mk b/packages/overlays/AccentColorOrchidOverlay/Android.mk
index fc55befef71e..352e36be8c82 100644
--- a/packages/overlays/AccentColorOrchidOverlay/Android.mk
+++ b/packages/overlays/AccentColorOrchidOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := AccentColorOrchid
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := AccentColorOrchidOverlay
diff --git a/packages/overlays/AccentColorPurpleOverlay/Android.mk b/packages/overlays/AccentColorPurpleOverlay/Android.mk
index 3a28efa2f820..29d5fc9c39b0 100644
--- a/packages/overlays/AccentColorPurpleOverlay/Android.mk
+++ b/packages/overlays/AccentColorPurpleOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := AccentColorPurple
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := AccentColorPurpleOverlay
diff --git a/packages/overlays/AccentColorSpaceOverlay/Android.mk b/packages/overlays/AccentColorSpaceOverlay/Android.mk
index 78cbf7325dee..cbddf6352aaa 100644
--- a/packages/overlays/AccentColorSpaceOverlay/Android.mk
+++ b/packages/overlays/AccentColorSpaceOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := AccentColorSpace
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := AccentColorSpaceOverlay
diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/Android.mk b/packages/overlays/DisplayCutoutEmulationCornerOverlay/Android.mk
index b73aea320d60..c3e8642084a0 100644
--- a/packages/overlays/DisplayCutoutEmulationCornerOverlay/Android.mk
+++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/Android.mk
@@ -6,8 +6,6 @@ LOCAL_RRO_THEME := DisplayCutoutEmulationCorner
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := DisplayCutoutEmulationCornerOverlay
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.mk b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.mk
index 8ca2dad25f3f..09d158d3e1f3 100644
--- a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.mk
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/Android.mk
@@ -6,8 +6,6 @@ LOCAL_RRO_THEME := DisplayCutoutEmulationDouble
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := DisplayCutoutEmulationDoubleOverlay
diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.mk b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.mk
index 7458cb5db9fb..6a1c09c87e33 100644
--- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.mk
+++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.mk
@@ -6,8 +6,6 @@ LOCAL_RRO_THEME := DisplayCutoutEmulationNarrow
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := DisplayCutoutEmulationNarrowOverlay
diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.mk b/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.mk
index 1a405e2275c6..cbceff08ae5e 100644
--- a/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.mk
+++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.mk
@@ -6,8 +6,6 @@ LOCAL_RRO_THEME := DisplayCutoutEmulationTall
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := DisplayCutoutEmulationTallOverlay
diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.mk b/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.mk
index 3ebc540852c8..82a076a88d9b 100644
--- a/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.mk
+++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.mk
@@ -6,8 +6,6 @@ LOCAL_RRO_THEME := DisplayCutoutEmulationWide
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := DisplayCutoutEmulationWideOverlay
diff --git a/packages/overlays/FontNotoSerifSourceOverlay/Android.mk b/packages/overlays/FontNotoSerifSourceOverlay/Android.mk
index f4eedaf377f9..16a0173a4635 100644
--- a/packages/overlays/FontNotoSerifSourceOverlay/Android.mk
+++ b/packages/overlays/FontNotoSerifSourceOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := FontNotoSerifSource
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := FontNotoSerifSourceOverlay
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/Android.mk b/packages/overlays/IconPackCircularAndroidOverlay/Android.mk
index 8f3baa5962dc..d96185fa34ea 100644
--- a/packages/overlays/IconPackCircularAndroidOverlay/Android.mk
+++ b/packages/overlays/IconPackCircularAndroidOverlay/Android.mk
@@ -20,8 +20,6 @@ LOCAL_RRO_THEME := IconPackCircularAndroid
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := IconPackCircularAndroidOverlay
diff --git a/packages/overlays/IconPackCircularLauncherOverlay/Android.mk b/packages/overlays/IconPackCircularLauncherOverlay/Android.mk
index 310bdef44b48..d736d7d666a5 100644
--- a/packages/overlays/IconPackCircularLauncherOverlay/Android.mk
+++ b/packages/overlays/IconPackCircularLauncherOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := IconPackCircularLauncher
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := IconPackCircularLauncherOverlay
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/Android.mk b/packages/overlays/IconPackCircularSettingsOverlay/Android.mk
index d06732228b82..ea2da30fba24 100644
--- a/packages/overlays/IconPackCircularSettingsOverlay/Android.mk
+++ b/packages/overlays/IconPackCircularSettingsOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := IconPackCircularSettings
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := IconPackCircularSettingsOverlay
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/Android.mk b/packages/overlays/IconPackCircularSystemUIOverlay/Android.mk
index 5e0dcbee8118..9045e8e58e6a 100644
--- a/packages/overlays/IconPackCircularSystemUIOverlay/Android.mk
+++ b/packages/overlays/IconPackCircularSystemUIOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := IconPackCircularSystemUI
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := IconPackCircularSystemUIOverlay
diff --git a/packages/overlays/IconPackCircularThemePickerOverlay/Android.mk b/packages/overlays/IconPackCircularThemePickerOverlay/Android.mk
index 412c26fc3da4..c2d472d541b8 100644
--- a/packages/overlays/IconPackCircularThemePickerOverlay/Android.mk
+++ b/packages/overlays/IconPackCircularThemePickerOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := IconPackCircularThemePicker
LOCAL_CERTIFICATE := platform
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := IconPackCircularThemePickerOverlay
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/Android.mk b/packages/overlays/IconPackFilledAndroidOverlay/Android.mk
index 3036f7df9f1e..78db7658aee1 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/Android.mk
+++ b/packages/overlays/IconPackFilledAndroidOverlay/Android.mk
@@ -20,8 +20,6 @@ LOCAL_RRO_THEME := IconPackFilledAndroid
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := IconPackFilledAndroidOverlay
diff --git a/packages/overlays/IconPackFilledLauncherOverlay/Android.mk b/packages/overlays/IconPackFilledLauncherOverlay/Android.mk
index 2460fa4675ff..16b8f526d2a2 100644
--- a/packages/overlays/IconPackFilledLauncherOverlay/Android.mk
+++ b/packages/overlays/IconPackFilledLauncherOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := IconPackFilledLauncher
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := IconPackFilledLauncherOverlay
diff --git a/packages/overlays/IconPackFilledSettingsOverlay/Android.mk b/packages/overlays/IconPackFilledSettingsOverlay/Android.mk
index 3cc071d732e1..d4e90007e956 100644
--- a/packages/overlays/IconPackFilledSettingsOverlay/Android.mk
+++ b/packages/overlays/IconPackFilledSettingsOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := IconPackFilledSettings
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := IconPackFilledSettingsOverlay
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/Android.mk b/packages/overlays/IconPackFilledSystemUIOverlay/Android.mk
index f0276927b8e2..35e157a268d5 100644
--- a/packages/overlays/IconPackFilledSystemUIOverlay/Android.mk
+++ b/packages/overlays/IconPackFilledSystemUIOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := IconPackFilledSystemUI
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := IconPackFilledSystemUIOverlay
diff --git a/packages/overlays/IconPackFilledThemePickerOverlay/Android.mk b/packages/overlays/IconPackFilledThemePickerOverlay/Android.mk
index 6d15603663b5..835d35e63efe 100644
--- a/packages/overlays/IconPackFilledThemePickerOverlay/Android.mk
+++ b/packages/overlays/IconPackFilledThemePickerOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := IconPackFilledThemePicker
LOCAL_CERTIFICATE := platform
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := IconPackFilledThemePickerOverlay
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/Android.mk b/packages/overlays/IconPackRoundedAndroidOverlay/Android.mk
index c6ad4ac04092..70d6fc44444c 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/Android.mk
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/Android.mk
@@ -20,8 +20,6 @@ LOCAL_RRO_THEME := IconPackRoundedAndroid
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := IconPackRoundedAndroidOverlay
diff --git a/packages/overlays/IconPackRoundedLauncherOverlay/Android.mk b/packages/overlays/IconPackRoundedLauncherOverlay/Android.mk
index 713e2819bb65..63de27fb18e0 100644
--- a/packages/overlays/IconPackRoundedLauncherOverlay/Android.mk
+++ b/packages/overlays/IconPackRoundedLauncherOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := IconPackRoundedLauncher
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := IconPackRoundedLauncherOverlay
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/Android.mk b/packages/overlays/IconPackRoundedSettingsOverlay/Android.mk
index 6c775190f548..c59bf7da10aa 100644
--- a/packages/overlays/IconPackRoundedSettingsOverlay/Android.mk
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := IconPackRoundedSettings
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := IconPackRoundedSettingsOverlay
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/Android.mk b/packages/overlays/IconPackRoundedSystemUIOverlay/Android.mk
index 4e21b41828c8..3b68c9209634 100644
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/Android.mk
+++ b/packages/overlays/IconPackRoundedSystemUIOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := IconPackRoundedSystemUI
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := IconPackRoundedSystemUIOverlay
diff --git a/packages/overlays/IconPackRoundedThemePickerOverlay/Android.mk b/packages/overlays/IconPackRoundedThemePickerOverlay/Android.mk
index ae48186e05ee..e31aa4a40baf 100644
--- a/packages/overlays/IconPackRoundedThemePickerOverlay/Android.mk
+++ b/packages/overlays/IconPackRoundedThemePickerOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := IconPackRoundedThemePicker
LOCAL_CERTIFICATE := platform
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := IconPackRoundedThemePickerOverlay
diff --git a/packages/overlays/IconShapeRoundedRectOverlay/Android.mk b/packages/overlays/IconShapeRoundedRectOverlay/Android.mk
index 21cd011ef83c..c6f00d1b5584 100644
--- a/packages/overlays/IconShapeRoundedRectOverlay/Android.mk
+++ b/packages/overlays/IconShapeRoundedRectOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := IconShapeRoundedRect
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := IconShapeRoundedRectOverlay
diff --git a/packages/overlays/IconShapeSquareOverlay/Android.mk b/packages/overlays/IconShapeSquareOverlay/Android.mk
index c8728838303c..602072126468 100644
--- a/packages/overlays/IconShapeSquareOverlay/Android.mk
+++ b/packages/overlays/IconShapeSquareOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := IconShapeSquare
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := IconShapeSquareOverlay
diff --git a/packages/overlays/IconShapeSquircleOverlay/Android.mk b/packages/overlays/IconShapeSquircleOverlay/Android.mk
index fa5fe6906dce..04409a544edf 100644
--- a/packages/overlays/IconShapeSquircleOverlay/Android.mk
+++ b/packages/overlays/IconShapeSquircleOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := IconShapeSquircle
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := IconShapeSquircleOverlay
diff --git a/packages/overlays/IconShapeTeardropOverlay/Android.mk b/packages/overlays/IconShapeTeardropOverlay/Android.mk
index d5f01f39965b..b127deabda4c 100644
--- a/packages/overlays/IconShapeTeardropOverlay/Android.mk
+++ b/packages/overlays/IconShapeTeardropOverlay/Android.mk
@@ -21,8 +21,6 @@ LOCAL_RRO_THEME := IconShapeTeardrop
LOCAL_PRODUCT_MODULE := true
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := IconShapeTeardropOverlay
diff --git a/packages/overlays/NavigationBarMode2ButtonOverlay/Android.mk b/packages/overlays/NavigationBarMode2ButtonOverlay/Android.mk
index be86ef2d3ff4..30477cceebcb 100644
--- a/packages/overlays/NavigationBarMode2ButtonOverlay/Android.mk
+++ b/packages/overlays/NavigationBarMode2ButtonOverlay/Android.mk
@@ -20,8 +20,6 @@ include $(CLEAR_VARS)
LOCAL_RRO_THEME := NavigationBarMode2Button
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := NavigationBarMode2ButtonOverlay
diff --git a/packages/overlays/NavigationBarMode3ButtonOverlay/Android.mk b/packages/overlays/NavigationBarMode3ButtonOverlay/Android.mk
index f44a362b266d..3d5a5a578c70 100644
--- a/packages/overlays/NavigationBarMode3ButtonOverlay/Android.mk
+++ b/packages/overlays/NavigationBarMode3ButtonOverlay/Android.mk
@@ -20,8 +20,6 @@ include $(CLEAR_VARS)
LOCAL_RRO_THEME := NavigationBarMode3Button
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := NavigationBarMode3ButtonOverlay
diff --git a/packages/overlays/NavigationBarModeGesturalOverlay/Android.mk b/packages/overlays/NavigationBarModeGesturalOverlay/Android.mk
index 02e2074accb7..3b7605a95a24 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlay/Android.mk
+++ b/packages/overlays/NavigationBarModeGesturalOverlay/Android.mk
@@ -20,8 +20,6 @@ include $(CLEAR_VARS)
LOCAL_RRO_THEME := NavigationBarModeGestural
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := NavigationBarModeGesturalOverlay
diff --git a/packages/overlays/NavigationBarModeGesturalOverlayExtraWideBack/Android.mk b/packages/overlays/NavigationBarModeGesturalOverlayExtraWideBack/Android.mk
index 9a38efa2f95d..1a1388eebd31 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlayExtraWideBack/Android.mk
+++ b/packages/overlays/NavigationBarModeGesturalOverlayExtraWideBack/Android.mk
@@ -20,8 +20,6 @@ include $(CLEAR_VARS)
LOCAL_RRO_THEME := NavigationBarModeGesturalExtraWideBack
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := NavigationBarModeGesturalOverlayExtraWideBack
diff --git a/packages/overlays/NavigationBarModeGesturalOverlayNarrowBack/Android.mk b/packages/overlays/NavigationBarModeGesturalOverlayNarrowBack/Android.mk
index 1d004c83faef..868998662aaa 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlayNarrowBack/Android.mk
+++ b/packages/overlays/NavigationBarModeGesturalOverlayNarrowBack/Android.mk
@@ -20,8 +20,6 @@ include $(CLEAR_VARS)
LOCAL_RRO_THEME := NavigationBarModeGesturalNarrowBack
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := NavigationBarModeGesturalOverlayNarrowBack
diff --git a/packages/overlays/NavigationBarModeGesturalOverlayWideBack/Android.mk b/packages/overlays/NavigationBarModeGesturalOverlayWideBack/Android.mk
index 0ab463f8e49f..2723add528be 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlayWideBack/Android.mk
+++ b/packages/overlays/NavigationBarModeGesturalOverlayWideBack/Android.mk
@@ -20,8 +20,6 @@ include $(CLEAR_VARS)
LOCAL_RRO_THEME := NavigationBarModeGesturalWideBack
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_PACKAGE_NAME := NavigationBarModeGesturalOverlayWideBack
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 303230b00c6f..b6cbbacde118 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -385,9 +385,10 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
for (int i = displaysList.size() - 1; i >= 0; i--) {
final int displayId = displaysList.get(i).getDisplayId();
+ final Context displayContext = mContext.createDisplayContext(displaysList.get(i));
if ((mEnabledFeatures & FLAG_FEATURE_TOUCH_EXPLORATION) != 0) {
- TouchExplorer explorer = new TouchExplorer(mContext, mAms);
+ TouchExplorer explorer = new TouchExplorer(displayContext, mAms);
addFirstEventHandler(displayId, explorer);
mTouchExplorer.put(displayId, explorer);
}
@@ -400,7 +401,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
final boolean triggerable = (mEnabledFeatures
& FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0;
MagnificationGestureHandler magnificationGestureHandler =
- new MagnificationGestureHandler(mContext,
+ new MagnificationGestureHandler(displayContext,
mAms.getMagnificationController(),
detectControlGestures, triggerable, displayId);
addFirstEventHandler(displayId, magnificationGestureHandler);
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 44f19ffe1904..5a9320f61b38 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -187,10 +187,9 @@ final class RemoteFillService extends ServiceConnector.Impl<IAutoFillService> {
if (err instanceof TimeoutException) {
dispatchCancellationSignal(cancellationSink.get());
mCallbacks.onFillRequestTimeout(request.getId());
+ } else if (err instanceof CancellationException) {
+ dispatchCancellationSignal(cancellationSink.get());
} else {
- if (err instanceof CancellationException) {
- dispatchCancellationSignal(cancellationSink.get());
- }
mCallbacks.onFillRequestFailure(request.getId(), err.getMessage());
}
}
diff --git a/services/backup/java/com/android/server/backup/encryption/chunking/DecryptedChunkFileOutput.java b/services/backup/java/com/android/server/backup/encryption/chunking/DecryptedChunkFileOutput.java
new file mode 100644
index 000000000000..ae2e150de4bc
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/encryption/chunking/DecryptedChunkFileOutput.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption.chunking;
+
+import static com.android.internal.util.Preconditions.checkState;
+
+import android.annotation.Nullable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.backup.encryption.tasks.DecryptedChunkOutput;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/** Writes plaintext chunks to a file, building a digest of the plaintext of the resulting file. */
+public class DecryptedChunkFileOutput implements DecryptedChunkOutput {
+ @VisibleForTesting static final String DIGEST_ALGORITHM = "SHA-256";
+
+ private final File mOutputFile;
+ private final MessageDigest mMessageDigest;
+ @Nullable private FileOutputStream mFileOutputStream;
+ private boolean mClosed;
+ @Nullable private byte[] mDigest;
+
+ /**
+ * Constructs a new instance which writes chunks to the given file and uses the default message
+ * digest algorithm.
+ */
+ public DecryptedChunkFileOutput(File outputFile) {
+ mOutputFile = outputFile;
+ try {
+ mMessageDigest = MessageDigest.getInstance(DIGEST_ALGORITHM);
+ } catch (NoSuchAlgorithmException e) {
+ throw new AssertionError(
+ "Impossible condition: JCE thinks it does not support AES.", e);
+ }
+ }
+
+ @Override
+ public DecryptedChunkOutput open() throws IOException {
+ checkState(mFileOutputStream == null, "Cannot open twice");
+ mFileOutputStream = new FileOutputStream(mOutputFile);
+ return this;
+ }
+
+ @Override
+ public void processChunk(byte[] plaintextBuffer, int length) throws IOException {
+ checkState(mFileOutputStream != null, "Must open before processing chunks");
+ mFileOutputStream.write(plaintextBuffer, /*off=*/ 0, length);
+ mMessageDigest.update(plaintextBuffer, /*offset=*/ 0, length);
+ }
+
+ @Override
+ public byte[] getDigest() {
+ checkState(mClosed, "Must close before getting mDigest");
+
+ // After the first call to mDigest() the MessageDigest is reset, thus we must store the
+ // result.
+ if (mDigest == null) {
+ mDigest = mMessageDigest.digest();
+ }
+ return mDigest;
+ }
+
+ @Override
+ public void close() throws IOException {
+ mFileOutputStream.close();
+ mClosed = true;
+ }
+}
diff --git a/services/backup/java/com/android/server/backup/encryption/keys/TertiaryKeyGenerator.java b/services/backup/java/com/android/server/backup/encryption/keys/TertiaryKeyGenerator.java
index ebf09dfd6ba6..a425c720b9b8 100644
--- a/services/backup/java/com/android/server/backup/encryption/keys/TertiaryKeyGenerator.java
+++ b/services/backup/java/com/android/server/backup/encryption/keys/TertiaryKeyGenerator.java
@@ -35,7 +35,7 @@ public class TertiaryKeyGenerator {
mKeyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
mKeyGenerator.init(KEY_SIZE_BITS, secureRandom);
} catch (NoSuchAlgorithmException e) {
- throw new RuntimeException(
+ throw new AssertionError(
"Impossible condition: JCE thinks it does not support AES.", e);
}
}
diff --git a/services/backup/java/com/android/server/backup/encryption/tasks/BackupEncrypter.java b/services/backup/java/com/android/server/backup/encryption/tasks/BackupEncrypter.java
new file mode 100644
index 000000000000..95d0d97b4073
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/encryption/tasks/BackupEncrypter.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption.tasks;
+
+import static java.util.Collections.unmodifiableList;
+
+import android.annotation.Nullable;
+
+import com.android.server.backup.encryption.chunk.ChunkHash;
+import com.android.server.backup.encryption.chunking.EncryptedChunk;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import javax.crypto.SecretKey;
+
+/** Task which reads data from some source, splits it into chunks and encrypts new chunks. */
+public interface BackupEncrypter {
+ /** The algorithm which we use to compute the digest of the backup file plaintext. */
+ String MESSAGE_DIGEST_ALGORITHM = "SHA-256";
+
+ /**
+ * Splits the backup input into encrypted chunks and encrypts new chunks.
+ *
+ * @param secretKey Key used to encrypt backup.
+ * @param fingerprintMixerSalt Fingerprint mixer salt used for content-defined chunking during a
+ * full backup. Should be {@code null} for a key-value backup.
+ * @param existingChunks Set of the SHA-256 Macs of chunks the server already has.
+ * @return a result containing an array of new encrypted chunks to upload, and an ordered
+ * listing of the chunks in the backup file.
+ * @throws IOException if a problem occurs reading from the backup data.
+ * @throws GeneralSecurityException if there is a problem encrypting the data.
+ */
+ Result backup(
+ SecretKey secretKey,
+ @Nullable byte[] fingerprintMixerSalt,
+ Set<ChunkHash> existingChunks)
+ throws IOException, GeneralSecurityException;
+
+ /**
+ * The result of an incremental backup. Contains new encrypted chunks to upload, and an ordered
+ * list of the chunks in the backup file.
+ */
+ class Result {
+ private final List<ChunkHash> mAllChunks;
+ private final List<EncryptedChunk> mNewChunks;
+ private final byte[] mDigest;
+
+ public Result(List<ChunkHash> allChunks, List<EncryptedChunk> newChunks, byte[] digest) {
+ mAllChunks = unmodifiableList(new ArrayList<>(allChunks));
+ mDigest = digest;
+ mNewChunks = unmodifiableList(new ArrayList<>(newChunks));
+ }
+
+ /**
+ * Returns an unmodifiable list of the hashes of all the chunks in the backup, in the order
+ * they appear in the plaintext.
+ */
+ public List<ChunkHash> getAllChunks() {
+ return mAllChunks;
+ }
+
+ /** Returns an unmodifiable list of the new chunks in the backup. */
+ public List<EncryptedChunk> getNewChunks() {
+ return mNewChunks;
+ }
+
+ /** Returns the message digest of the backup. */
+ public byte[] getDigest() {
+ return mDigest;
+ }
+ }
+}
diff --git a/services/backup/java/com/android/server/backup/encryption/tasks/BackupStreamEncrypter.java b/services/backup/java/com/android/server/backup/encryption/tasks/BackupStreamEncrypter.java
new file mode 100644
index 000000000000..45798d32885a
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/encryption/tasks/BackupStreamEncrypter.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption.tasks;
+
+import android.util.Slog;
+
+import com.android.server.backup.encryption.chunk.ChunkHash;
+import com.android.server.backup.encryption.chunking.ChunkEncryptor;
+import com.android.server.backup.encryption.chunking.ChunkHasher;
+import com.android.server.backup.encryption.chunking.EncryptedChunk;
+import com.android.server.backup.encryption.chunking.cdc.ContentDefinedChunker;
+import com.android.server.backup.encryption.chunking.cdc.FingerprintMixer;
+import com.android.server.backup.encryption.chunking.cdc.IsChunkBreakpoint;
+import com.android.server.backup.encryption.chunking.cdc.RabinFingerprint64;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.crypto.SecretKey;
+
+/**
+ * Splits backup data into variable-sized chunks using content-defined chunking, then encrypts the
+ * chunks. Given a hash of the SHA-256s of existing chunks, performs an incremental backup (i.e.,
+ * only encrypts new chunks).
+ */
+public class BackupStreamEncrypter implements BackupEncrypter {
+ private static final String TAG = "BackupStreamEncryptor";
+
+ private final InputStream mData;
+ private final int mMinChunkSizeBytes;
+ private final int mMaxChunkSizeBytes;
+ private final int mAverageChunkSizeBytes;
+
+ /**
+ * A new instance over the given distribution of chunk sizes.
+ *
+ * @param data The data to be backed up.
+ * @param minChunkSizeBytes The minimum chunk size. No chunk will be smaller than this.
+ * @param maxChunkSizeBytes The maximum chunk size. No chunk will be larger than this.
+ * @param averageChunkSizeBytes The average chunk size. The mean size of chunks will be roughly
+ * this (with a few tens of bytes of overhead for the initialization vector and message
+ * authentication code).
+ */
+ public BackupStreamEncrypter(
+ InputStream data,
+ int minChunkSizeBytes,
+ int maxChunkSizeBytes,
+ int averageChunkSizeBytes) {
+ this.mData = data;
+ this.mMinChunkSizeBytes = minChunkSizeBytes;
+ this.mMaxChunkSizeBytes = maxChunkSizeBytes;
+ this.mAverageChunkSizeBytes = averageChunkSizeBytes;
+ }
+
+ @Override
+ public Result backup(
+ SecretKey secretKey, byte[] fingerprintMixerSalt, Set<ChunkHash> existingChunks)
+ throws IOException, GeneralSecurityException {
+ MessageDigest messageDigest =
+ MessageDigest.getInstance(BackupEncrypter.MESSAGE_DIGEST_ALGORITHM);
+ RabinFingerprint64 rabinFingerprint64 = new RabinFingerprint64();
+ FingerprintMixer fingerprintMixer = new FingerprintMixer(secretKey, fingerprintMixerSalt);
+ IsChunkBreakpoint isChunkBreakpoint =
+ new IsChunkBreakpoint(mAverageChunkSizeBytes - mMinChunkSizeBytes);
+ ContentDefinedChunker chunker =
+ new ContentDefinedChunker(
+ mMinChunkSizeBytes,
+ mMaxChunkSizeBytes,
+ rabinFingerprint64,
+ fingerprintMixer,
+ isChunkBreakpoint);
+ ChunkHasher chunkHasher = new ChunkHasher(secretKey);
+ ChunkEncryptor encryptor = new ChunkEncryptor(secretKey, new SecureRandom());
+ Set<ChunkHash> includedChunks = new HashSet<>();
+ // New chunks will be added only once to this list, even if they occur multiple times.
+ List<EncryptedChunk> newChunks = new ArrayList<>();
+ // All chunks (including multiple occurrences) will be added to the chunkListing.
+ List<ChunkHash> chunkListing = new ArrayList<>();
+
+ includedChunks.addAll(existingChunks);
+
+ chunker.chunkify(
+ mData,
+ chunk -> {
+ messageDigest.update(chunk);
+ ChunkHash key = chunkHasher.computeHash(chunk);
+
+ if (!includedChunks.contains(key)) {
+ newChunks.add(encryptor.encrypt(key, chunk));
+ includedChunks.add(key);
+ }
+ chunkListing.add(key);
+ });
+
+ Slog.i(
+ TAG,
+ String.format(
+ "Chunks: %d total, %d unique, %d new",
+ chunkListing.size(), new HashSet<>(chunkListing).size(), newChunks.size()));
+ return new Result(
+ Collections.unmodifiableList(chunkListing),
+ Collections.unmodifiableList(newChunks),
+ messageDigest.digest());
+ }
+}
diff --git a/services/backup/java/com/android/server/backup/encryption/tasks/DecryptedChunkOutput.java b/services/backup/java/com/android/server/backup/encryption/tasks/DecryptedChunkOutput.java
new file mode 100644
index 000000000000..e3df3c1eb96f
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/encryption/tasks/DecryptedChunkOutput.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption.tasks;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+
+/**
+ * Accepts the plaintext bytes of decrypted chunks and writes them to some output. Also keeps track
+ * of the message digest of the chunks.
+ */
+public interface DecryptedChunkOutput extends Closeable {
+ /**
+ * Opens whatever output the implementation chooses, ready to process chunks.
+ *
+ * @return {@code this}, to allow use with try-with-resources
+ */
+ DecryptedChunkOutput open() throws IOException;
+
+ /**
+ * Writes the plaintext bytes of chunk to whatever output the implementation chooses. Also
+ * updates the digest with the chunk.
+ *
+ * <p>You must call {@link #open()} before this method, and you may not call it after calling
+ * {@link Closeable#close()}.
+ *
+ * @param plaintextBuffer An array containing the bytes of the plaintext of the chunk, starting
+ * at index 0.
+ * @param length The length in bytes of the plaintext contained in {@code plaintextBuffer}.
+ */
+ void processChunk(byte[] plaintextBuffer, int length) throws IOException, InvalidKeyException;
+
+ /**
+ * Returns the message digest of all the chunks processed by {@link #processChunk}.
+ *
+ * <p>You must call {@link Closeable#close()} before calling this method.
+ */
+ byte[] getDigest();
+}
diff --git a/services/backup/java/com/android/server/backup/encryption/tasks/EncryptedRestoreException.java b/services/backup/java/com/android/server/backup/encryption/tasks/EncryptedRestoreException.java
new file mode 100644
index 000000000000..487c0d92f6fd
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/encryption/tasks/EncryptedRestoreException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption.tasks;
+
+/** Wraps any exception related to encryption which occurs during restore. */
+public class EncryptedRestoreException extends Exception {
+ public EncryptedRestoreException(String message) {
+ super(message);
+ }
+
+ public EncryptedRestoreException(Throwable cause) {
+ super(cause);
+ }
+
+ public EncryptedRestoreException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
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 56eacc017079..eba9e4aa4c28 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -88,7 +88,6 @@ public class FullRestoreEngine extends RestoreEngine {
final PackageInfo mOnlyPackage;
final boolean mAllowApks;
- private final boolean mAllowObbs;
// Which package are we currently handling data for?
private String mAgentPackage;
@@ -113,9 +112,6 @@ public class FullRestoreEngine extends RestoreEngine {
// Packages we've already wiped data on when restoring their first file
private final HashSet<String> mClearedPackages = new HashSet<>();
- // How much data have we moved?
- private long mBytes;
-
// Working buffer
final byte[] mBuffer;
@@ -130,14 +126,14 @@ public class FullRestoreEngine extends RestoreEngine {
final int mEphemeralOpToken;
private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
- final boolean mIsAdbRestore;
+ private final boolean mIsAdbRestore;
@GuardedBy("mPipesLock")
private boolean mPipesClosed;
public FullRestoreEngine(UserBackupManagerService backupManagerService,
BackupRestoreTask monitorTask, IFullBackupRestoreObserver observer,
IBackupManagerMonitor monitor, PackageInfo onlyPackage, boolean allowApks,
- boolean allowObbs, int ephemeralOpToken, boolean isAdbRestore) {
+ int ephemeralOpToken, boolean isAdbRestore) {
mBackupManagerService = backupManagerService;
mEphemeralOpToken = ephemeralOpToken;
mMonitorTask = monitorTask;
@@ -145,9 +141,7 @@ public class FullRestoreEngine extends RestoreEngine {
mMonitor = monitor;
mOnlyPackage = onlyPackage;
mAllowApks = allowApks;
- mAllowObbs = allowObbs;
mBuffer = new byte[32 * 1024];
- mBytes = 0;
mAgentTimeoutParameters = Preconditions.checkNotNull(
backupManagerService.getAgentTimeoutParameters(),
"Timeout parameters cannot be null");
@@ -170,12 +164,7 @@ public class FullRestoreEngine extends RestoreEngine {
return false;
}
- BytesReadListener bytesReadListener = new BytesReadListener() {
- @Override
- public void onBytesRead(long bytesRead) {
- mBytes += bytesRead;
- }
- };
+ BytesReadListener bytesReadListener = bytesRead -> { };
TarBackupReader tarBackupReader = new TarBackupReader(instream,
bytesReadListener, monitor);
@@ -378,9 +367,7 @@ public class FullRestoreEngine extends RestoreEngine {
? ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL
: ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL);
mAgentPackage = pkg;
- } catch (IOException e) {
- // fall through to error handling
- } catch (NameNotFoundException e) {
+ } catch (IOException | NameNotFoundException e) {
// fall through to error handling
}
@@ -485,9 +472,6 @@ public class FullRestoreEngine extends RestoreEngine {
int toRead = (toCopy > buffer.length)
? buffer.length : (int) toCopy;
int nRead = instream.read(buffer, 0, toRead);
- if (nRead >= 0) {
- mBytes += nRead;
- }
if (nRead <= 0) {
break;
}
@@ -548,9 +532,6 @@ public class FullRestoreEngine extends RestoreEngine {
int toRead = (bytesToConsume > buffer.length)
? buffer.length : (int) bytesToConsume;
long nRead = instream.read(buffer, 0, toRead);
- if (nRead >= 0) {
- mBytes += nRead;
- }
if (nRead <= 0) {
break;
}
diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
index c9042566cf67..ec2d5454210b 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
@@ -23,21 +23,12 @@ import static com.android.server.backup.BackupPasswordManager.PBKDF_CURRENT;
import static com.android.server.backup.BackupPasswordManager.PBKDF_FALLBACK;
import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_HEADER_MAGIC;
import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_VERSION;
-import static com.android.server.backup.UserBackupManagerService.SETTINGS_PACKAGE;
-import static com.android.server.backup.UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
-import android.app.IBackupAgent;
-import android.app.backup.BackupAgent;
import android.app.backup.IFullBackupRestoreObserver;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.Signature;
-import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
-import com.android.server.backup.BackupAgentTimeoutParameters;
import com.android.server.backup.UserBackupManagerService;
import com.android.server.backup.fullbackup.FullBackupObbConnection;
import com.android.server.backup.utils.FullBackupRestoreObserverUtils;
@@ -50,8 +41,6 @@ import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.zip.InflaterInputStream;
@@ -71,34 +60,9 @@ public class PerformAdbRestoreTask implements Runnable {
private final String mCurrentPassword;
private final String mDecryptPassword;
private final AtomicBoolean mLatchObject;
- private final BackupAgent mPackageManagerBackupAgent;
- private final RestoreDeleteObserver mDeleteObserver = new RestoreDeleteObserver();
+ private final FullBackupObbConnection mObbConnection;
private IFullBackupRestoreObserver mObserver;
- private IBackupAgent mAgent;
- private String mAgentPackage;
- private ApplicationInfo mTargetApp;
- private FullBackupObbConnection mObbConnection = null;
- private ParcelFileDescriptor[] mPipes = null;
- private byte[] mWidgetData = null;
- private long mAppVersion;
-
- private long mBytes;
- private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
-
- // possible handling states for a given package in the restore dataset
- private final HashMap<String, RestorePolicy> mPackagePolicies
- = new HashMap<>();
-
- // installer package names for each encountered app, derived from the manifests
- private final HashMap<String, String> mPackageInstallers = new HashMap<>();
-
- // Signatures for a given package found in its manifest file
- private final HashMap<String, Signature[]> mManifestSignatures
- = new HashMap<>();
-
- // Packages we've already wiped data on when restoring their first file
- private final HashSet<String> mClearedPackages = new HashSet<>();
public PerformAdbRestoreTask(UserBackupManagerService backupManagerService,
ParcelFileDescriptor fd, String curPassword, String decryptPassword,
@@ -109,19 +73,7 @@ public class PerformAdbRestoreTask implements Runnable {
mDecryptPassword = decryptPassword;
mObserver = observer;
mLatchObject = latch;
- mAgent = null;
- mPackageManagerBackupAgent = backupManagerService.makeMetadataAgent();
- mAgentPackage = null;
- mTargetApp = null;
mObbConnection = new FullBackupObbConnection(backupManagerService);
- mAgentTimeoutParameters = Preconditions.checkNotNull(
- backupManagerService.getAgentTimeoutParameters(),
- "Timeout parameters cannot be null");
-
- // Which packages we've already wiped data on. We prepopulate this
- // with a whitelist of packages known to be unclearable.
- mClearedPackages.add("android");
- mClearedPackages.add(SETTINGS_PACKAGE);
}
@Override
@@ -130,11 +82,6 @@ public class PerformAdbRestoreTask implements Runnable {
mObbConnection.establish();
mObserver = FullBackupRestoreObserverUtils.sendStartRestore(mObserver);
- // Are we able to restore shared-storage data?
- if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
- mPackagePolicies.put(SHARED_BACKUP_AGENT_PACKAGE, RestorePolicy.ACCEPT);
- }
-
FileInputStream rawInStream = null;
try {
if (!mBackupManagerService.backupPasswordMatches(mCurrentPassword)) {
@@ -144,8 +91,6 @@ public class PerformAdbRestoreTask implements Runnable {
return;
}
- mBytes = 0;
-
rawInStream = new FileInputStream(mInputFile.getFileDescriptor());
InputStream tarInputStream = parseBackupFileHeaderAndReturnTarStream(rawInStream,
@@ -157,7 +102,7 @@ public class PerformAdbRestoreTask implements Runnable {
}
FullRestoreEngine mEngine = new FullRestoreEngine(mBackupManagerService, null,
- mObserver, null, null, true, true/*unused*/, 0 /*unused*/, true);
+ mObserver, null, null, true, 0 /*unused*/, true);
FullRestoreEngineThread mEngineThread = new FullRestoreEngineThread(mEngine,
tarInputStream);
mEngineThread.run();
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 6714b0aea261..a45f0c0ae186 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -86,7 +86,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
private final TransportClient mTransportClient;
// Where per-transport saved state goes
- File mStateDir;
+ private File mStateDir;
// Restore observer; may be null
private IRestoreObserver mObserver;
@@ -153,10 +153,9 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// Key/value: bookkeeping about staged data and files for agent access
private File mBackupDataName;
private File mStageName;
- private File mSavedStateName;
private File mNewStateName;
- ParcelFileDescriptor mBackupData;
- ParcelFileDescriptor mNewState;
+ private ParcelFileDescriptor mBackupData;
+ private ParcelFileDescriptor mNewState;
private final int mEphemeralOpToken;
private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
@@ -666,7 +665,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
}
// Guts of a key/value restore operation
- void initiateOneRestore(PackageInfo app, long appVersionCode) {
+ private void initiateOneRestore(PackageInfo app, long appVersionCode) {
final String packageName = app.packageName;
if (DEBUG) {
@@ -677,7 +676,6 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
mBackupDataName = new File(backupManagerService.getDataDir(), packageName + ".restore");
mStageName = new File(backupManagerService.getDataDir(), packageName + ".stage");
mNewStateName = new File(mStateDir, packageName + ".new");
- mSavedStateName = new File(mStateDir, packageName);
// don't stage the 'android' package where the wallpaper data lives. this is
// an optimization: we know there's no widget data hosted/published by that
@@ -870,7 +868,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
mCurrentPackage.packageName);
mEngine = new FullRestoreEngine(backupManagerService, this, null,
- mMonitor, mCurrentPackage, false, false, mEphemeralOpToken, false);
+ mMonitor, mCurrentPackage, false, mEphemeralOpToken, false);
mEngineThread = new FullRestoreEngineThread(mEngine, mEnginePipes[0]);
ParcelFileDescriptor eWriteEnd = mEnginePipes[1];
@@ -1160,7 +1158,6 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// the following from a discard of the newly-written state to the
// "correct" operation of renaming into the canonical state blob.
mNewStateName.delete(); // TODO: remove; see above comment
- //mNewStateName.renameTo(mSavedStateName); // TODO: replace with this
// If this wasn't the PM pseudopackage, tear down the agent side
if (mCurrentPackage.applicationInfo != null) {
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 3ebe70266c71..b36bbaa252c2 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -97,6 +97,7 @@ import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.location.AbstractLocationProvider;
import com.android.server.location.ActivityRecognitionProxy;
@@ -905,7 +906,8 @@ public class LocationManagerService extends ILocationManager.Stub {
Integer.parseInt(fragments[9]) /* accuracy */);
LocationProvider testProviderManager = new LocationProvider(name);
addProviderLocked(testProviderManager);
- new MockProvider(mContext, testProviderManager, properties);
+ testProviderManager.attachLocked(
+ new MockProvider(mContext, testProviderManager, properties));
}
}
@@ -1026,38 +1028,55 @@ public class LocationManagerService extends ILocationManager.Stub {
return mProperties;
}
- @GuardedBy("mLock")
- public void setRequestLocked(ProviderRequest request, WorkSource workSource) {
- if (mProvider != null) {
- long identity = Binder.clearCallingIdentity();
- try {
- mProvider.setRequest(request, workSource);
- } finally {
- Binder.restoreCallingIdentity(identity);
+ public void setRequest(ProviderRequest request, WorkSource workSource) {
+ // move calls going to providers onto a different thread to avoid deadlock
+ mHandler.post(() -> {
+ synchronized (mLock) {
+ if (mProvider != null) {
+ mProvider.onSetRequest(request, workSource);
+ }
}
- }
+ });
+ }
+
+ public void sendExtraCommand(String command, Bundle extras) {
+ int uid = Binder.getCallingUid();
+ int pid = Binder.getCallingPid();
+
+ // move calls going to providers onto a different thread to avoid deadlock
+ mHandler.post(() -> {
+ synchronized (mLock) {
+ if (mProvider != null) {
+ mProvider.onSendExtraCommand(uid, pid, command, extras);
+ }
+ }
+ });
}
@GuardedBy("mLock")
- public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.print(" " + mName + " provider");
+ public void dumpLocked(FileDescriptor fd, IndentingPrintWriter pw, String[] args) {
+ pw.print(mName + " provider");
if (isMock()) {
pw.print(" [mock]");
}
pw.println(":");
- pw.println(" useable=" + mUseable);
+ pw.increaseIndent();
+
+ pw.println("useable=" + mUseable);
if (!mUseable) {
- pw.println(" attached=" + (mProvider != null));
+ pw.println("attached=" + (mProvider != null));
if (mIsManagedBySettings) {
- pw.println(" allowed=" + mAllowed);
+ pw.println("allowed=" + mAllowed);
}
- pw.println(" enabled=" + mEnabled);
+ pw.println("enabled=" + mEnabled);
}
- pw.println(" properties=" + mProperties);
+ pw.println("properties=" + mProperties);
if (mProvider != null) {
+ // in order to be consistent with other provider APIs, this should be run on the
+ // location thread... but this likely isn't worth it just for dumping info.
long identity = Binder.clearCallingIdentity();
try {
mProvider.dump(fd, pw, args);
@@ -1065,6 +1084,8 @@ public class LocationManagerService extends ILocationManager.Stub {
Binder.restoreCallingIdentity(identity);
}
}
+
+ pw.decreaseIndent();
}
@GuardedBy("mLock")
@@ -1095,79 +1116,53 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- @GuardedBy("mLock")
- public void sendExtraCommandLocked(String command, Bundle extras) {
- if (mProvider != null) {
- // intentionally do not clear binder identity so that providers can evaluate who
- // is sending the extra command
- mProvider.sendExtraCommand(command, extras);
- }
- }
-
- // called from any thread
@Override
public void onReportLocation(Location location) {
- // no security check necessary because this is coming from an internal-only interface
- // move calls coming from below LMS onto a different thread to avoid deadlock
- mHandler.post(() -> {
- synchronized (mLock) {
- handleLocationChangedLocked(location, this);
- }
- });
+ synchronized (mLock) {
+ handleLocationChangedLocked(location, this);
+ }
}
- // called from any thread
@Override
public void onReportLocation(List<Location> locations) {
- // move calls coming from below LMS onto a different thread to avoid deadlock
- mHandler.post(() -> {
- synchronized (mLock) {
- LocationProvider gpsProvider = getLocationProviderLocked(GPS_PROVIDER);
- if (gpsProvider == null || !gpsProvider.isUseableLocked()) {
- Slog.w(TAG, "reportLocationBatch() called without user permission");
- return;
- }
+ synchronized (mLock) {
+ LocationProvider gpsProvider = getLocationProviderLocked(GPS_PROVIDER);
+ if (gpsProvider == null || !gpsProvider.isUseableLocked()) {
+ Slog.w(TAG, "reportLocationBatch() called without user permission");
+ return;
+ }
- if (mGnssBatchingCallback == null) {
- Slog.e(TAG, "reportLocationBatch() called without active Callback");
- return;
- }
+ if (mGnssBatchingCallback == null) {
+ Slog.e(TAG, "reportLocationBatch() called without active Callback");
+ return;
+ }
- try {
- mGnssBatchingCallback.onLocationBatch(locations);
- } catch (RemoteException e) {
- Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
- }
+ try {
+ mGnssBatchingCallback.onLocationBatch(locations);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "mGnssBatchingCallback.onLocationBatch failed", e);
}
- });
+ }
}
- // called from any thread
@Override
public void onSetEnabled(boolean enabled) {
- // move calls coming from below LMS onto a different thread to avoid deadlock
- mHandler.post(() -> {
- synchronized (mLock) {
- if (enabled == mEnabled) {
- return;
- }
-
- if (D) {
- Log.d(TAG, mName + " provider enabled is now " + mEnabled);
- }
+ synchronized (mLock) {
+ if (enabled == mEnabled) {
+ return;
+ }
- mEnabled = enabled;
- onUseableChangedLocked(false);
+ if (D) {
+ Log.d(TAG, mName + " provider enabled is now " + mEnabled);
}
- });
+
+ mEnabled = enabled;
+ onUseableChangedLocked(false);
+ }
}
@Override
public void onSetProperties(ProviderProperties properties) {
- // because this does not invoke any other methods which might result in calling back
- // into the location provider, it is safe to run this on the calling thread. it is also
- // currently necessary to run this on the calling thread to ensure that property changes
- // are publicly visibly immediately, ie for mock providers which are created.
synchronized (mLock) {
mProperties = properties;
}
@@ -1325,9 +1320,8 @@ public class LocationManagerService extends ILocationManager.Stub {
}
@Override
- @GuardedBy("mLock")
- public void setRequestLocked(ProviderRequest request, WorkSource workSource) {
- super.setRequestLocked(request, workSource);
+ public void setRequest(ProviderRequest request, WorkSource workSource) {
+ super.setRequest(request, workSource);
mCurrentRequest = request;
}
@@ -2232,7 +2226,7 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- provider.setRequestLocked(providerRequest, worksource);
+ provider.setRequest(providerRequest, worksource);
}
/**
@@ -2916,6 +2910,12 @@ public class LocationManagerService extends ILocationManager.Stub {
mCallerIdentity = callerIdentity;
mListenerName = listenerName;
}
+
+ @Override
+ public String toString() {
+ return mListenerName + "[" + mCallerIdentity.mPackageName + "(" + mCallerIdentity.mPid
+ + ")]";
+ }
}
private static class LinkedListener<TListener> extends LinkedListenerBase {
@@ -3116,7 +3116,7 @@ public class LocationManagerService extends ILocationManager.Stub {
LocationProvider provider = getLocationProviderLocked(providerName);
if (provider != null) {
- provider.sendExtraCommandLocked(command, extras);
+ provider.sendExtraCommand(command, extras);
}
mLocationUsageLogger.logLocationApiUsage(
@@ -3671,6 +3671,8 @@ public class LocationManagerService extends ILocationManager.Stub {
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+
synchronized (mLock) {
if (args.length > 0 && args[0].equals("--gnssmetrics")) {
if (mGnssMetricsProvider != null) {
@@ -3678,115 +3680,133 @@ public class LocationManagerService extends ILocationManager.Stub {
}
return;
}
- pw.println("Current Location Manager state:");
- pw.print(" Current System Time: "
+
+ ipw.println("Location Manager State:");
+ ipw.increaseIndent();
+ ipw.print("Current System Time: "
+ TimeUtils.logTimeOfDay(System.currentTimeMillis()));
- pw.println(", Current Elapsed Time: "
+ ipw.println(", Current Elapsed Time: "
+ TimeUtils.formatDuration(SystemClock.elapsedRealtime()));
- pw.println(" Current user: " + mCurrentUserId + " " + Arrays.toString(
+ ipw.println("Current user: " + mCurrentUserId + " " + Arrays.toString(
mCurrentUserProfiles));
- pw.println(" Location mode: " + isLocationEnabled());
- pw.println(" Battery Saver Location Mode: "
+ ipw.println("Location Mode: " + isLocationEnabled());
+ ipw.println("Battery Saver Location Mode: "
+ locationPowerSaveModeToString(mBatterySaverMode));
- pw.println(" Location Listeners:");
+
+ ipw.println("Location Listeners:");
+ ipw.increaseIndent();
for (Receiver receiver : mReceivers.values()) {
- pw.println(" " + receiver);
+ ipw.println(receiver);
}
- pw.println(" Active Records by Provider:");
+ ipw.decreaseIndent();
+
+ ipw.println("Active Records by Provider:");
+ ipw.increaseIndent();
for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
- pw.println(" " + entry.getKey() + ":");
+ ipw.println(entry.getKey() + ":");
+ ipw.increaseIndent();
for (UpdateRecord record : entry.getValue()) {
- pw.println(" " + record);
+ ipw.println(record);
}
+ ipw.decreaseIndent();
}
+ ipw.decreaseIndent();
- pw.println(" Active GnssMeasurement Listeners:");
- dumpGnssDataListenersLocked(pw, mGnssMeasurementsListeners);
- pw.println(" Active GnssNavigationMessage Listeners:");
- dumpGnssDataListenersLocked(pw, mGnssNavigationMessageListeners);
- pw.println(" Active GnssStatus Listeners:");
- dumpGnssDataListenersLocked(pw, mGnssStatusListeners);
+ ipw.println("GnssMeasurement Listeners:");
+ ipw.increaseIndent();
+ for (LinkedListenerBase listener : mGnssMeasurementsListeners.values()) {
+ ipw.println(listener + ": " + isThrottlingExemptLocked(listener.mCallerIdentity));
+ }
+ ipw.decreaseIndent();
- pw.println(" Historical Records by Provider:");
+ ipw.println("GnssNavigationMessage Listeners:");
+ ipw.increaseIndent();
+ for (LinkedListenerBase listener : mGnssNavigationMessageListeners.values()) {
+ ipw.println(listener + ": " + isThrottlingExemptLocked(listener.mCallerIdentity));
+ }
+ ipw.decreaseIndent();
+
+ ipw.println("GnssStatus Listeners:");
+ ipw.increaseIndent();
+ for (LinkedListenerBase listener : mGnssStatusListeners.values()) {
+ ipw.println(listener + ": " + isThrottlingExemptLocked(listener.mCallerIdentity));
+ }
+ ipw.decreaseIndent();
+
+ ipw.println("Historical Records by Provider:");
+ ipw.increaseIndent();
for (Map.Entry<PackageProviderKey, PackageStatistics> entry
: mRequestStatistics.statistics.entrySet()) {
PackageProviderKey key = entry.getKey();
- PackageStatistics stats = entry.getValue();
- pw.println(" " + key.packageName + ": " + key.providerName + ": " + stats);
+ ipw.println(key.packageName + ": " + key.providerName + ": " + entry.getValue());
}
- pw.println(" Last Known Locations:");
+ ipw.decreaseIndent();
+
+ ipw.println("Last Known Locations:");
+ ipw.increaseIndent();
for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
- String provider = entry.getKey();
- Location location = entry.getValue();
- pw.println(" " + provider + ": " + location);
+ ipw.println(entry.getKey() + ": " + entry.getValue());
}
+ ipw.decreaseIndent();
- pw.println(" Last Known Locations Coarse Intervals:");
+ ipw.println("Last Known Coarse Locations:");
+ ipw.increaseIndent();
for (Map.Entry<String, Location> entry : mLastLocationCoarseInterval.entrySet()) {
- String provider = entry.getKey();
- Location location = entry.getValue();
- pw.println(" " + provider + ": " + location);
+ ipw.println(entry.getKey() + ": " + entry.getValue());
}
+ ipw.decreaseIndent();
if (mGeofenceManager != null) {
- mGeofenceManager.dump(pw);
- } else {
- pw.println(" Geofences: null");
+ ipw.println("Geofences:");
+ ipw.increaseIndent();
+ mGeofenceManager.dump(ipw);
+ ipw.decreaseIndent();
}
if (mBlacklist != null) {
- pw.append(" ");
- mBlacklist.dump(pw);
- } else {
- pw.println(" mBlacklist=null");
+ mBlacklist.dump(ipw);
}
if (mExtraLocationControllerPackage != null) {
- pw.println(" Location controller extra package: " + mExtraLocationControllerPackage
- + " enabled: " + mExtraLocationControllerPackageEnabled);
+ ipw.println("Location Controller Extra Package: " + mExtraLocationControllerPackage
+ + (mExtraLocationControllerPackageEnabled ? " [enabled]" : "[disabled]"));
}
if (!mBackgroundThrottlePackageWhitelist.isEmpty()) {
- pw.println(" Throttling Whitelisted Packages:");
+ ipw.println("Throttling Whitelisted Packages:");
+ ipw.increaseIndent();
for (String packageName : mBackgroundThrottlePackageWhitelist) {
- pw.println(" " + packageName);
+ ipw.println(packageName);
}
+ ipw.decreaseIndent();
}
if (!mIgnoreSettingsPackageWhitelist.isEmpty()) {
- pw.println(" Bypass Whitelisted Packages:");
+ ipw.println("Bypass Whitelisted Packages:");
+ ipw.increaseIndent();
for (String packageName : mIgnoreSettingsPackageWhitelist) {
- pw.println(" " + packageName);
+ ipw.println(packageName);
}
+ ipw.decreaseIndent();
}
if (mLocationFudger != null) {
- pw.append(" fudger: ");
- mLocationFudger.dump(fd, pw, args);
- } else {
- pw.println(" fudger: null");
+ ipw.println("Location Fudger:");
+ ipw.increaseIndent();
+ mLocationFudger.dump(fd, ipw, args);
+ ipw.decreaseIndent();
}
- if (args.length > 0 && "short".equals(args[0])) {
- return;
- }
+ ipw.println("Location Providers:");
+ ipw.increaseIndent();
for (LocationProvider provider : mProviders) {
- provider.dumpLocked(fd, pw, args);
+ provider.dumpLocked(fd, ipw, args);
}
+ ipw.decreaseIndent();
+
if (mGnssBatchingInProgress) {
- pw.println(" GNSS batching in progress");
+ ipw.println("GNSS batching in progress");
}
}
}
-
- @GuardedBy("mLock")
- private void dumpGnssDataListenersLocked(PrintWriter pw,
- ArrayMap<IBinder, ? extends LinkedListenerBase> gnssDataListeners) {
- for (LinkedListenerBase listener : gnssDataListeners.values()) {
- CallerIdentity callerIdentity = listener.mCallerIdentity;
- pw.println(" " + callerIdentity.mPid + " " + callerIdentity.mUid + " "
- + callerIdentity.mPackageName + ": "
- + isThrottlingExemptLocked(callerIdentity));
- }
- }
}
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java
index b6fa1570cdb0..c0f10a3c86e1 100644
--- a/services/core/java/com/android/server/MmsServiceBroker.java
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -37,6 +37,7 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.service.carrier.CarrierMessagingService;
import android.telephony.SmsManager;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Slog;
@@ -331,7 +332,7 @@ public class MmsServiceBroker extends SystemService {
@Override
public void sendMessage(int subId, String callingPkg, Uri contentUri,
String locationUrl, Bundle configOverrides, PendingIntent sentIntent)
- throws RemoteException {
+ throws RemoteException {
Slog.d(TAG, "sendMessage() by " + callingPkg);
mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, "Send MMS message");
if (getAppOpsManager().noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
@@ -341,7 +342,8 @@ public class MmsServiceBroker extends SystemService {
}
contentUri = adjustUriForUserAndGrantPermission(contentUri,
CarrierMessagingService.SERVICE_INTERFACE,
- Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ Intent.FLAG_GRANT_READ_URI_PERMISSION,
+ subId);
getServiceGuarded().sendMessage(subId, callingPkg, contentUri, locationUrl,
configOverrides, sentIntent);
}
@@ -360,7 +362,8 @@ public class MmsServiceBroker extends SystemService {
}
contentUri = adjustUriForUserAndGrantPermission(contentUri,
CarrierMessagingService.SERVICE_INTERFACE,
- Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+ subId);
getServiceGuarded().downloadMessage(subId, callingPkg, locationUrl, contentUri,
configOverrides, downloadedIntent);
@@ -388,7 +391,7 @@ public class MmsServiceBroker extends SystemService {
@Override
public Uri importMultimediaMessage(String callingPkg, Uri contentUri,
String messageId, long timestampSecs, boolean seen, boolean read)
- throws RemoteException {
+ throws RemoteException {
if (getAppOpsManager().noteOp(AppOpsManager.OP_WRITE_SMS, Binder.getCallingUid(),
callingPkg) != AppOpsManager.MODE_ALLOWED) {
// Silently fail AppOps failure due to not being the default SMS app
@@ -496,12 +499,12 @@ public class MmsServiceBroker extends SystemService {
* even if the caller is not in the primary user.
*
* @param contentUri The Uri to adjust
- * @param action The intent action used to find the associated carrier app
+ * @param action The intent action used to find the associated carrier app
* @param permission The permission to add
* @return The adjusted Uri containing the calling userId.
*/
private Uri adjustUriForUserAndGrantPermission(Uri contentUri, String action,
- int permission) {
+ int permission, int subId) {
final Intent grantIntent = new Intent();
grantIntent.setData(contentUri);
grantIntent.setFlags(permission);
@@ -521,9 +524,10 @@ public class MmsServiceBroker extends SystemService {
// Grant permission for the carrier app.
Intent intent = new Intent(action);
TelephonyManager telephonyManager =
- (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
- List<String> carrierPackages = telephonyManager.getCarrierPackageNamesForIntent(
- intent);
+ (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ List<String> carrierPackages =
+ telephonyManager.getCarrierPackageNamesForIntentAndPhone(
+ intent, SubscriptionManager.getPhoneId(subId));
if (carrierPackages != null && carrierPackages.size() == 1) {
LocalServices.getService(UriGrantsManagerInternal.class)
.grantUriPermissionFromIntent(callingUid, carrierPackages.get(0),
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index e66e596d5038..f7e825eecc12 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1027,7 +1027,12 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
log(str);
}
mLocalLog.log(str);
- if (validatePhoneId(phoneId)) {
+ // for service state updates, don't notify clients when subId is invalid. This prevents
+ // us from sending incorrect notifications like b/133140128
+ // In the future, we can remove this logic for every notification here and add a
+ // callback so listeners know when their PhoneStateListener's subId becomes invalid, but
+ // for now we use the simplest fix.
+ if (validatePhoneId(phoneId) && SubscriptionManager.isValidSubscriptionId(subId)) {
mServiceState[phoneId] = state;
for (Record r : mRecords) {
@@ -1059,7 +1064,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
} else {
- log("notifyServiceStateForSubscriber: INVALID phoneId=" + phoneId);
+ log("notifyServiceStateForSubscriber: INVALID phoneId=" + phoneId
+ + " or subId=" + subId);
}
handleRemoveListLocked();
}
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index bc7da3fe2edc..30a356325ada 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -413,15 +413,15 @@ final class UiModeManagerService extends SystemService {
try {
synchronized (mLock) {
if (mNightMode != mode) {
- if (UserManager.get(getContext()).isPrimaryUser()) {
- SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME,
- Integer.toString(mode));
- }
-
// Only persist setting if not in car mode
if (!mCarModeEnabled) {
Secure.putIntForUser(getContext().getContentResolver(),
Secure.UI_NIGHT_MODE, mode, user);
+
+ if (UserManager.get(getContext()).isPrimaryUser()) {
+ SystemProperties.set(SYSTEM_PROPERTY_DEVICE_THEME,
+ Integer.toString(mode));
+ }
}
mNightMode = mode;
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 5b9c78f6e8ea..a502ff24e5b8 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -103,6 +103,7 @@ public class Watchdog extends Thread {
public static final List<String> HAL_INTERFACES_OF_INTEREST = Arrays.asList(
"android.hardware.audio@2.0::IDevicesFactory",
"android.hardware.audio@4.0::IDevicesFactory",
+ "android.hardware.audio@5.0::IDevicesFactory",
"android.hardware.biometrics.face@1.0::IBiometricsFace",
"android.hardware.bluetooth@1.0::IBluetoothHci",
"android.hardware.camera.provider@2.4::ICameraProvider",
@@ -114,7 +115,8 @@ public class Watchdog extends Thread {
"android.hardware.media.omx@1.0::IOmxStore",
"android.hardware.power.stats@1.0::IPowerStats",
"android.hardware.sensors@1.0::ISensors",
- "android.hardware.vr@1.0::IVr"
+ "android.hardware.vr@1.0::IVr",
+ "android.system.suspend@1.0::ISystemSuspend"
);
static Watchdog sWatchdog;
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 746c250308de..56208a9565e1 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -30,7 +30,6 @@ import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.ActivityInfo;
-import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
@@ -44,6 +43,7 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
+import android.permission.IPermissionManager;
import android.util.EventLog;
import android.util.Slog;
import android.util.SparseIntArray;
@@ -921,7 +921,7 @@ public final class BroadcastQueue {
if (perms == null) {
return false;
}
- IPackageManager pm = AppGlobals.getPackageManager();
+ IPermissionManager pm = AppGlobals.getPermissionManager();
for (int i = perms.length-1; i >= 0; i--) {
try {
PermissionInfo pi = pm.getPermissionInfo(perms[i], "android", 0);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 8ef5b07531ce..6c57be8bbadf 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -54,8 +54,6 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.content.res.XmlResourceParser;
import android.database.ContentObserver;
import android.hardware.hdmi.HdmiAudioSystemClient;
import android.hardware.hdmi.HdmiControlManager;
@@ -82,11 +80,7 @@ import android.media.IRingtonePlayer;
import android.media.IVolumeController;
import android.media.MediaExtractor;
import android.media.MediaFormat;
-import android.media.MediaPlayer;
-import android.media.MediaPlayer.OnCompletionListener;
-import android.media.MediaPlayer.OnErrorListener;
import android.media.PlayerBase;
-import android.media.SoundPool;
import android.media.VolumePolicy;
import android.media.audiofx.AudioEffect;
import android.media.audiopolicy.AudioMix;
@@ -102,7 +96,6 @@ import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
-import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -137,7 +130,6 @@ import android.widget.Toast;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
-import com.android.internal.util.XmlUtils;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -146,15 +138,11 @@ import com.android.server.audio.AudioServiceEvents.VolumeEvent;
import com.android.server.pm.UserManagerService;
import com.android.server.wm.ActivityTaskManagerInternal;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -294,19 +282,6 @@ public class AudioService extends IAudioService.Stub
// protects mRingerMode
private final Object mSettingsLock = new Object();
- private SoundPool mSoundPool;
- private final Object mSoundEffectsLock = new Object();
- private static final int NUM_SOUNDPOOL_CHANNELS = 4;
-
- /* Sound effect file names */
- private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
- private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
-
- /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
- * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
- * uses soundpool (second column) */
- private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
-
/** Maximum volume index values for audio streams */
protected static int[] MAX_STREAM_VOLUME = new int[] {
5, // STREAM_VOICE_CALL
@@ -366,7 +341,7 @@ public class AudioService extends IAudioService.Stub
AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
AudioSystem.STREAM_MUSIC, // STREAM_ALARM
AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION
- AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO
+ AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
AudioSystem.STREAM_MUSIC, // STREAM_DTMF
AudioSystem.STREAM_MUSIC, // STREAM_TTS
@@ -453,6 +428,9 @@ public class AudioService extends IAudioService.Stub
* @see System#MUTE_STREAMS_AFFECTED */
private int mMuteAffectedStreams;
+ @NonNull
+ private SoundEffectsHelper mSfxHelper;
+
/**
* NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
* mVibrateSetting is just maintained during deprecation period but vibration policy is
@@ -493,14 +471,6 @@ public class AudioService extends IAudioService.Stub
private boolean mSystemReady;
// true if Intent.ACTION_USER_SWITCHED has ever been received
private boolean mUserSwitchedReceived;
- // listener for SoundPool sample load completion indication
- private SoundPoolCallback mSoundPoolCallBack;
- // thread for SoundPool listener
- private SoundPoolListenerThread mSoundPoolListenerThread;
- // message looper for SoundPool listener
- private Looper mSoundPoolLooper = null;
- // volume applied to sound played with playSoundEffect()
- private static int sSoundEffectVolumeDb;
// previous volume adjustment direction received by checkForRingerModeChange()
private int mPrevVolDirection = AudioManager.ADJUST_SAME;
// mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
@@ -642,6 +612,8 @@ public class AudioService extends IAudioService.Stub
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
+ mSfxHelper = new SoundEffectsHelper(mContext);
+
mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
mHasVibrator = mVibrator == null ? false : mVibrator.hasVibrator();
@@ -732,9 +704,6 @@ public class AudioService extends IAudioService.Stub
MAX_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM];
}
- sSoundEffectVolumeDb = context.getResources().getInteger(
- com.android.internal.R.integer.config_soundEffectVolumeDb);
-
createAudioSystemThread();
AudioSystem.setErrorCallback(mAudioSystemCallback);
@@ -2543,15 +2512,11 @@ public class AudioService extends IAudioService.Stub
mVolumeController.postVolumeChanged(streamType, flags);
}
- // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
- // receives volume notification from Audio Receiver.
+ // If Hdmi-CEC system audio mode is on and we are a TV panel, never show volume bar.
private int updateFlagsForTvPlatform(int flags) {
synchronized (mHdmiClientLock) {
- if (mHdmiTvClient != null) {
- if (mHdmiSystemAudioSupported &&
- ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
- flags &= ~AudioManager.FLAG_SHOW_UI;
- }
+ if (mHdmiTvClient != null && mHdmiSystemAudioSupported) {
+ flags &= ~AudioManager.FLAG_SHOW_UI;
}
}
return flags;
@@ -3373,104 +3338,30 @@ public class AudioService extends IAudioService.Stub
//==========================================================================================
// Sound Effects
//==========================================================================================
+ private static final class LoadSoundEffectReply
+ implements SoundEffectsHelper.OnEffectsLoadCompleteHandler {
+ private static final int SOUND_EFFECTS_LOADING = 1;
+ private static final int SOUND_EFFECTS_LOADED = 0;
+ private static final int SOUND_EFFECTS_ERROR = -1;
+ private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
- private static final String TAG_AUDIO_ASSETS = "audio_assets";
- private static final String ATTR_VERSION = "version";
- private static final String TAG_GROUP = "group";
- private static final String ATTR_GROUP_NAME = "name";
- private static final String TAG_ASSET = "asset";
- private static final String ATTR_ASSET_ID = "id";
- private static final String ATTR_ASSET_FILE = "file";
+ private int mStatus = SOUND_EFFECTS_LOADING;
- private static final String ASSET_FILE_VERSION = "1.0";
- private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
-
- private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
-
- class LoadSoundEffectReply {
- public int mStatus = 1;
- };
-
- private void loadTouchSoundAssetDefaults() {
- SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
- for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
- SOUND_EFFECT_FILES_MAP[i][0] = 0;
- SOUND_EFFECT_FILES_MAP[i][1] = -1;
- }
- }
-
- private void loadTouchSoundAssets() {
- XmlResourceParser parser = null;
-
- // only load assets once.
- if (!SOUND_EFFECT_FILES.isEmpty()) {
- return;
+ @Override
+ public synchronized void run(boolean success) {
+ mStatus = success ? SOUND_EFFECTS_LOADED : SOUND_EFFECTS_ERROR;
+ notify();
}
- loadTouchSoundAssetDefaults();
-
- try {
- parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
-
- XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
- String version = parser.getAttributeValue(null, ATTR_VERSION);
- boolean inTouchSoundsGroup = false;
-
- if (ASSET_FILE_VERSION.equals(version)) {
- while (true) {
- XmlUtils.nextElement(parser);
- String element = parser.getName();
- if (element == null) {
- break;
- }
- if (element.equals(TAG_GROUP)) {
- String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
- if (GROUP_TOUCH_SOUNDS.equals(name)) {
- inTouchSoundsGroup = true;
- break;
- }
- }
- }
- while (inTouchSoundsGroup) {
- XmlUtils.nextElement(parser);
- String element = parser.getName();
- if (element == null) {
- break;
- }
- if (element.equals(TAG_ASSET)) {
- String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
- String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
- int fx;
-
- try {
- Field field = AudioManager.class.getField(id);
- fx = field.getInt(null);
- } catch (Exception e) {
- Log.w(TAG, "Invalid touch sound ID: "+id);
- continue;
- }
-
- int i = SOUND_EFFECT_FILES.indexOf(file);
- if (i == -1) {
- i = SOUND_EFFECT_FILES.size();
- SOUND_EFFECT_FILES.add(file);
- }
- SOUND_EFFECT_FILES_MAP[fx][0] = i;
- } else {
- break;
- }
+ public synchronized boolean waitForLoaded(int attempts) {
+ while ((mStatus == SOUND_EFFECTS_LOADING) && (attempts-- > 0)) {
+ try {
+ wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
+ } catch (InterruptedException e) {
+ Log.w(TAG, "Interrupted while waiting sound pool loaded.");
}
}
- } catch (Resources.NotFoundException e) {
- Log.w(TAG, "audio assets file not found", e);
- } catch (XmlPullParserException e) {
- Log.w(TAG, "XML parser exception reading touch sound assets", e);
- } catch (IOException e) {
- Log.w(TAG, "I/O exception reading touch sound assets", e);
- } finally {
- if (parser != null) {
- parser.close();
- }
+ return mStatus == SOUND_EFFECTS_LOADED;
}
}
@@ -3500,20 +3391,9 @@ public class AudioService extends IAudioService.Stub
* This method must be called at first when sound effects are enabled
*/
public boolean loadSoundEffects() {
- int attempts = 3;
LoadSoundEffectReply reply = new LoadSoundEffectReply();
-
- synchronized (reply) {
- sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
- while ((reply.mStatus == 1) && (attempts-- > 0)) {
- try {
- reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
- } catch (InterruptedException e) {
- Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
- }
- }
- }
- return (reply.mStatus == 0);
+ sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
+ return reply.waitForLoaded(3 /*attempts*/);
}
/**
@@ -3533,61 +3413,6 @@ public class AudioService extends IAudioService.Stub
sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
}
- class SoundPoolListenerThread extends Thread {
- public SoundPoolListenerThread() {
- super("SoundPoolListenerThread");
- }
-
- @Override
- public void run() {
-
- Looper.prepare();
- mSoundPoolLooper = Looper.myLooper();
-
- synchronized (mSoundEffectsLock) {
- if (mSoundPool != null) {
- mSoundPoolCallBack = new SoundPoolCallback();
- mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
- }
- mSoundEffectsLock.notify();
- }
- Looper.loop();
- }
- }
-
- private final class SoundPoolCallback implements
- android.media.SoundPool.OnLoadCompleteListener {
-
- int mStatus = 1; // 1 means neither error nor last sample loaded yet
- List<Integer> mSamples = new ArrayList<Integer>();
-
- public int status() {
- return mStatus;
- }
-
- public void setSamples(int[] samples) {
- for (int i = 0; i < samples.length; i++) {
- // do not wait ack for samples rejected upfront by SoundPool
- if (samples[i] > 0) {
- mSamples.add(samples[i]);
- }
- }
- }
-
- public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
- synchronized (mSoundEffectsLock) {
- int i = mSamples.indexOf(sampleId);
- if (i >= 0) {
- mSamples.remove(i);
- }
- if ((status != 0) || mSamples. isEmpty()) {
- mStatus = status;
- mSoundEffectsLock.notify();
- }
- }
- }
- }
-
/** @see AudioManager#reloadAudioSettings() */
public void reloadAudioSettings() {
readAudioSettings(false /*userSwitch*/);
@@ -5108,230 +4933,6 @@ public class AudioService extends IAudioService.Stub
Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
}
- private String getSoundEffectFilePath(int effectType) {
- String filePath = Environment.getProductDirectory() + SOUND_EFFECTS_PATH
- + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
- if (!new File(filePath).isFile()) {
- filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH
- + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
- }
- return filePath;
- }
-
- private boolean onLoadSoundEffects() {
- int status;
-
- synchronized (mSoundEffectsLock) {
- if (!mSystemReady) {
- Log.w(TAG, "onLoadSoundEffects() called before boot complete");
- return false;
- }
-
- if (mSoundPool != null) {
- return true;
- }
-
- loadTouchSoundAssets();
-
- mSoundPool = new SoundPool.Builder()
- .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
- .setAudioAttributes(new AudioAttributes.Builder()
- .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
- .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
- .build())
- .build();
- mSoundPoolCallBack = null;
- mSoundPoolListenerThread = new SoundPoolListenerThread();
- mSoundPoolListenerThread.start();
- int attempts = 3;
- while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
- try {
- // Wait for mSoundPoolCallBack to be set by the other thread
- mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
- } catch (InterruptedException e) {
- Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
- }
- }
-
- if (mSoundPoolCallBack == null) {
- Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
- if (mSoundPoolLooper != null) {
- mSoundPoolLooper.quit();
- mSoundPoolLooper = null;
- }
- mSoundPoolListenerThread = null;
- mSoundPool.release();
- mSoundPool = null;
- return false;
- }
- /*
- * poolId table: The value -1 in this table indicates that corresponding
- * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
- * Once loaded, the value in poolId is the sample ID and the same
- * sample can be reused for another effect using the same file.
- */
- int[] poolId = new int[SOUND_EFFECT_FILES.size()];
- for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
- poolId[fileIdx] = -1;
- }
- /*
- * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
- * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
- * this indicates we have a valid sample loaded for this effect.
- */
-
- int numSamples = 0;
- for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
- // Do not load sample if this effect uses the MediaPlayer
- if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
- continue;
- }
- if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
- String filePath = getSoundEffectFilePath(effect);
- int sampleId = mSoundPool.load(filePath, 0);
- if (sampleId <= 0) {
- Log.w(TAG, "Soundpool could not load file: "+filePath);
- } else {
- SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
- poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
- numSamples++;
- }
- } else {
- SOUND_EFFECT_FILES_MAP[effect][1] =
- poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
- }
- }
- // wait for all samples to be loaded
- if (numSamples > 0) {
- mSoundPoolCallBack.setSamples(poolId);
-
- attempts = 3;
- status = 1;
- while ((status == 1) && (attempts-- > 0)) {
- try {
- mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
- status = mSoundPoolCallBack.status();
- } catch (InterruptedException e) {
- Log.w(TAG, "Interrupted while waiting sound pool callback.");
- }
- }
- } else {
- status = -1;
- }
-
- if (mSoundPoolLooper != null) {
- mSoundPoolLooper.quit();
- mSoundPoolLooper = null;
- }
- mSoundPoolListenerThread = null;
- if (status != 0) {
- Log.w(TAG,
- "onLoadSoundEffects(), Error "+status+ " while loading samples");
- for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
- if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
- SOUND_EFFECT_FILES_MAP[effect][1] = -1;
- }
- }
-
- mSoundPool.release();
- mSoundPool = null;
- }
- }
- return (status == 0);
- }
-
- /**
- * Unloads samples from the sound pool.
- * This method can be called to free some memory when
- * sound effects are disabled.
- */
- private void onUnloadSoundEffects() {
- synchronized (mSoundEffectsLock) {
- if (mSoundPool == null) {
- return;
- }
-
- int[] poolId = new int[SOUND_EFFECT_FILES.size()];
- for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
- poolId[fileIdx] = 0;
- }
-
- for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
- if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
- continue;
- }
- if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
- mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
- SOUND_EFFECT_FILES_MAP[effect][1] = -1;
- poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
- }
- }
- mSoundPool.release();
- mSoundPool = null;
- }
- }
-
- private void onPlaySoundEffect(int effectType, int volume) {
- synchronized (mSoundEffectsLock) {
-
- onLoadSoundEffects();
-
- if (mSoundPool == null) {
- return;
- }
- float volFloat;
- // use default if volume is not specified by caller
- if (volume < 0) {
- volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
- } else {
- volFloat = volume / 1000.0f;
- }
-
- if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
- mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
- volFloat, volFloat, 0, 0, 1.0f);
- } else {
- MediaPlayer mediaPlayer = new MediaPlayer();
- try {
- String filePath = getSoundEffectFilePath(effectType);
- mediaPlayer.setDataSource(filePath);
- mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
- mediaPlayer.prepare();
- mediaPlayer.setVolume(volFloat);
- mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
- public void onCompletion(MediaPlayer mp) {
- cleanupPlayer(mp);
- }
- });
- mediaPlayer.setOnErrorListener(new OnErrorListener() {
- public boolean onError(MediaPlayer mp, int what, int extra) {
- cleanupPlayer(mp);
- return true;
- }
- });
- mediaPlayer.start();
- } catch (IOException ex) {
- Log.w(TAG, "MediaPlayer IOException: "+ex);
- } catch (IllegalArgumentException ex) {
- Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
- } catch (IllegalStateException ex) {
- Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
- }
- }
- }
- }
-
- private void cleanupPlayer(MediaPlayer mp) {
- if (mp != null) {
- try {
- mp.stop();
- mp.release();
- } catch (IllegalStateException ex) {
- Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
- }
- }
- }
-
private void onPersistSafeVolumeState(int state) {
Settings.Global.putInt(mContentResolver,
Settings.Global.AUDIO_SAFE_VOLUME_STATE,
@@ -5378,24 +4979,25 @@ public class AudioService extends IAudioService.Stub
break;
case MSG_UNLOAD_SOUND_EFFECTS:
- onUnloadSoundEffects();
+ mSfxHelper.unloadSoundEffects();
break;
case MSG_LOAD_SOUND_EFFECTS:
- //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
- // can take several dozens of milliseconds to complete
- boolean loaded = onLoadSoundEffects();
- if (msg.obj != null) {
- LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
- synchronized (reply) {
- reply.mStatus = loaded ? 0 : -1;
- reply.notify();
+ {
+ LoadSoundEffectReply reply = (LoadSoundEffectReply) msg.obj;
+ if (mSystemReady) {
+ mSfxHelper.loadSoundEffects(reply);
+ } else {
+ Log.w(TAG, "[schedule]loadSoundEffects() called before boot complete");
+ if (reply != null) {
+ reply.run(false);
}
}
+ }
break;
case MSG_PLAY_SOUND_EFFECT:
- onPlaySoundEffect(msg.arg1, msg.arg2);
+ mSfxHelper.playSoundEffect(msg.arg1, msg.arg2);
break;
case MSG_SET_FORCE_USE:
@@ -6426,6 +6028,8 @@ public class AudioService extends IAudioService.Stub
pw.println("\nAudioDeviceBroker:");
mDeviceBroker.dump(pw, " ");
+ pw.println("\nSoundEffects:");
+ mSfxHelper.dump(pw, " ");
pw.println("\n");
pw.println("\nEvent logs:");
diff --git a/services/core/java/com/android/server/audio/SoundEffectsHelper.java b/services/core/java/com/android/server/audio/SoundEffectsHelper.java
new file mode 100644
index 000000000000..cf5bc8d88c73
--- /dev/null
+++ b/services/core/java/com/android/server/audio/SoundEffectsHelper.java
@@ -0,0 +1,521 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.audio;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.media.AudioSystem;
+import android.media.MediaPlayer;
+import android.media.MediaPlayer.OnCompletionListener;
+import android.media.MediaPlayer.OnErrorListener;
+import android.media.SoundPool;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+import android.util.PrintWriterPrinter;
+
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A helper class for managing sound effects loading / unloading
+ * used by AudioService. As its methods are called on the message handler thread
+ * of AudioService, the actual work is offloaded to a dedicated thread.
+ * This helps keeping AudioService responsive.
+ * @hide
+ */
+class SoundEffectsHelper {
+ private static final String TAG = "AS.SfxHelper";
+
+ private static final int NUM_SOUNDPOOL_CHANNELS = 4;
+
+ /* Sound effect file names */
+ private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
+
+ private static final int EFFECT_NOT_IN_SOUND_POOL = 0; // SoundPool sample IDs > 0
+
+ private static final int MSG_LOAD_EFFECTS = 0;
+ private static final int MSG_UNLOAD_EFFECTS = 1;
+ private static final int MSG_PLAY_EFFECT = 2;
+ private static final int MSG_LOAD_EFFECTS_TIMEOUT = 3;
+
+ interface OnEffectsLoadCompleteHandler {
+ void run(boolean success);
+ }
+
+ private final AudioEventLogger mSfxLogger = new AudioEventLogger(
+ AudioManager.NUM_SOUND_EFFECTS + 10, "Sound Effects Loading");
+
+ private final Context mContext;
+ // default attenuation applied to sound played with playSoundEffect()
+ private final int mSfxAttenuationDb;
+
+ // thread for doing all work
+ private SfxWorker mSfxWorker;
+ // thread's message handler
+ private SfxHandler mSfxHandler;
+
+ private static final class Resource {
+ final String mFileName;
+ int mSampleId;
+ boolean mLoaded; // for effects in SoundPool
+ Resource(String fileName) {
+ mFileName = fileName;
+ mSampleId = EFFECT_NOT_IN_SOUND_POOL;
+ }
+ }
+ // All the fields below are accessed by the worker thread exclusively
+ private final List<Resource> mResources = new ArrayList<Resource>();
+ private final int[] mEffects = new int[AudioManager.NUM_SOUND_EFFECTS]; // indexes in mResources
+ private SoundPool mSoundPool;
+ private SoundPoolLoader mSoundPoolLoader;
+
+ SoundEffectsHelper(Context context) {
+ mContext = context;
+ mSfxAttenuationDb = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_soundEffectVolumeDb);
+ startWorker();
+ }
+
+ /*package*/ void loadSoundEffects(OnEffectsLoadCompleteHandler onComplete) {
+ sendMsg(MSG_LOAD_EFFECTS, 0, 0, onComplete, 0);
+ }
+
+ /**
+ * Unloads samples from the sound pool.
+ * This method can be called to free some memory when
+ * sound effects are disabled.
+ */
+ /*package*/ void unloadSoundEffects() {
+ sendMsg(MSG_UNLOAD_EFFECTS, 0, 0, null, 0);
+ }
+
+ /*package*/ void playSoundEffect(int effect, int volume) {
+ sendMsg(MSG_PLAY_EFFECT, effect, volume, null, 0);
+ }
+
+ /*package*/ void dump(PrintWriter pw, String prefix) {
+ if (mSfxHandler != null) {
+ pw.println(prefix + "Message handler (watch for unhandled messages):");
+ mSfxHandler.dump(new PrintWriterPrinter(pw), " ");
+ } else {
+ pw.println(prefix + "Message handler is null");
+ }
+ pw.println(prefix + "Default attenuation (dB): " + mSfxAttenuationDb);
+ mSfxLogger.dump(pw);
+ }
+
+ private void startWorker() {
+ mSfxWorker = new SfxWorker();
+ mSfxWorker.start();
+ synchronized (this) {
+ while (mSfxHandler == null) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ Log.w(TAG, "Interrupted while waiting " + mSfxWorker.getName() + " to start");
+ }
+ }
+ }
+ }
+
+ private void sendMsg(int msg, int arg1, int arg2, Object obj, int delayMs) {
+ mSfxHandler.sendMessageDelayed(mSfxHandler.obtainMessage(msg, arg1, arg2, obj), delayMs);
+ }
+
+ private void logEvent(String msg) {
+ mSfxLogger.log(new AudioEventLogger.StringEvent(msg));
+ }
+
+ // All the methods below run on the worker thread
+ private void onLoadSoundEffects(OnEffectsLoadCompleteHandler onComplete) {
+ if (mSoundPoolLoader != null) {
+ // Loading is ongoing.
+ mSoundPoolLoader.addHandler(onComplete);
+ return;
+ }
+ if (mSoundPool != null) {
+ if (onComplete != null) {
+ onComplete.run(true /*success*/);
+ }
+ return;
+ }
+
+ logEvent("effects loading started");
+ mSoundPool = new SoundPool.Builder()
+ .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
+ .setAudioAttributes(new AudioAttributes.Builder()
+ .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .build())
+ .build();
+ loadTouchSoundAssets();
+
+ mSoundPoolLoader = new SoundPoolLoader();
+ mSoundPoolLoader.addHandler(new OnEffectsLoadCompleteHandler() {
+ @Override
+ public void run(boolean success) {
+ mSoundPoolLoader = null;
+ if (!success) {
+ Log.w(TAG, "onLoadSoundEffects(), Error while loading samples");
+ onUnloadSoundEffects();
+ }
+ }
+ });
+ mSoundPoolLoader.addHandler(onComplete);
+
+ int resourcesToLoad = 0;
+ for (Resource res : mResources) {
+ String filePath = getResourceFilePath(res);
+ int sampleId = mSoundPool.load(filePath, 0);
+ if (sampleId > 0) {
+ res.mSampleId = sampleId;
+ res.mLoaded = false;
+ resourcesToLoad++;
+ } else {
+ logEvent("effect " + filePath + " rejected by SoundPool");
+ Log.w(TAG, "SoundPool could not load file: " + filePath);
+ }
+ }
+
+ if (resourcesToLoad > 0) {
+ sendMsg(MSG_LOAD_EFFECTS_TIMEOUT, 0, 0, null, SOUND_EFFECTS_LOAD_TIMEOUT_MS);
+ } else {
+ logEvent("effects loading completed, no effects to load");
+ mSoundPoolLoader.onComplete(true /*success*/);
+ }
+ }
+
+ void onUnloadSoundEffects() {
+ if (mSoundPool == null) {
+ return;
+ }
+ if (mSoundPoolLoader != null) {
+ mSoundPoolLoader.addHandler(new OnEffectsLoadCompleteHandler() {
+ @Override
+ public void run(boolean success) {
+ onUnloadSoundEffects();
+ }
+ });
+ }
+
+ logEvent("effects unloading started");
+ for (Resource res : mResources) {
+ if (res.mSampleId != EFFECT_NOT_IN_SOUND_POOL) {
+ mSoundPool.unload(res.mSampleId);
+ }
+ }
+ mSoundPool.release();
+ mSoundPool = null;
+ logEvent("effects unloading completed");
+ }
+
+ void onPlaySoundEffect(int effect, int volume) {
+ float volFloat;
+ // use default if volume is not specified by caller
+ if (volume < 0) {
+ volFloat = (float) Math.pow(10, (float) mSfxAttenuationDb / 20);
+ } else {
+ volFloat = volume / 1000.0f;
+ }
+
+ Resource res = mResources.get(mEffects[effect]);
+ if (res.mSampleId != EFFECT_NOT_IN_SOUND_POOL && res.mLoaded) {
+ mSoundPool.play(res.mSampleId, volFloat, volFloat, 0, 0, 1.0f);
+ } else {
+ MediaPlayer mediaPlayer = new MediaPlayer();
+ try {
+ String filePath = getResourceFilePath(res);
+ mediaPlayer.setDataSource(filePath);
+ mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
+ mediaPlayer.prepare();
+ mediaPlayer.setVolume(volFloat);
+ mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
+ public void onCompletion(MediaPlayer mp) {
+ cleanupPlayer(mp);
+ }
+ });
+ mediaPlayer.setOnErrorListener(new OnErrorListener() {
+ public boolean onError(MediaPlayer mp, int what, int extra) {
+ cleanupPlayer(mp);
+ return true;
+ }
+ });
+ mediaPlayer.start();
+ } catch (IOException ex) {
+ Log.w(TAG, "MediaPlayer IOException: " + ex);
+ } catch (IllegalArgumentException ex) {
+ Log.w(TAG, "MediaPlayer IllegalArgumentException: " + ex);
+ } catch (IllegalStateException ex) {
+ Log.w(TAG, "MediaPlayer IllegalStateException: " + ex);
+ }
+ }
+ }
+
+ private static void cleanupPlayer(MediaPlayer mp) {
+ if (mp != null) {
+ try {
+ mp.stop();
+ mp.release();
+ } catch (IllegalStateException ex) {
+ Log.w(TAG, "MediaPlayer IllegalStateException: " + ex);
+ }
+ }
+ }
+
+ private static final String TAG_AUDIO_ASSETS = "audio_assets";
+ private static final String ATTR_VERSION = "version";
+ private static final String TAG_GROUP = "group";
+ private static final String ATTR_GROUP_NAME = "name";
+ private static final String TAG_ASSET = "asset";
+ private static final String ATTR_ASSET_ID = "id";
+ private static final String ATTR_ASSET_FILE = "file";
+
+ private static final String ASSET_FILE_VERSION = "1.0";
+ private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
+
+ private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 15000;
+
+ private String getResourceFilePath(Resource res) {
+ String filePath = Environment.getProductDirectory() + SOUND_EFFECTS_PATH + res.mFileName;
+ if (!new File(filePath).isFile()) {
+ filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + res.mFileName;
+ }
+ return filePath;
+ }
+
+ private void loadTouchSoundAssetDefaults() {
+ int defaultResourceIdx = mResources.size();
+ mResources.add(new Resource("Effect_Tick.ogg"));
+ for (int i = 0; i < mEffects.length; i++) {
+ mEffects[i] = defaultResourceIdx;
+ }
+ }
+
+ private void loadTouchSoundAssets() {
+ XmlResourceParser parser = null;
+
+ // only load assets once.
+ if (!mResources.isEmpty()) {
+ return;
+ }
+
+ loadTouchSoundAssetDefaults();
+
+ try {
+ parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
+
+ XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
+ String version = parser.getAttributeValue(null, ATTR_VERSION);
+ boolean inTouchSoundsGroup = false;
+
+ if (ASSET_FILE_VERSION.equals(version)) {
+ while (true) {
+ XmlUtils.nextElement(parser);
+ String element = parser.getName();
+ if (element == null) {
+ break;
+ }
+ if (element.equals(TAG_GROUP)) {
+ String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
+ if (GROUP_TOUCH_SOUNDS.equals(name)) {
+ inTouchSoundsGroup = true;
+ break;
+ }
+ }
+ }
+ while (inTouchSoundsGroup) {
+ XmlUtils.nextElement(parser);
+ String element = parser.getName();
+ if (element == null) {
+ break;
+ }
+ if (element.equals(TAG_ASSET)) {
+ String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
+ String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
+ int fx;
+
+ try {
+ Field field = AudioManager.class.getField(id);
+ fx = field.getInt(null);
+ } catch (Exception e) {
+ Log.w(TAG, "Invalid touch sound ID: " + id);
+ continue;
+ }
+
+ mEffects[fx] = findOrAddResourceByFileName(file);
+ } else {
+ break;
+ }
+ }
+ }
+ } catch (Resources.NotFoundException e) {
+ Log.w(TAG, "audio assets file not found", e);
+ } catch (XmlPullParserException e) {
+ Log.w(TAG, "XML parser exception reading touch sound assets", e);
+ } catch (IOException e) {
+ Log.w(TAG, "I/O exception reading touch sound assets", e);
+ } finally {
+ if (parser != null) {
+ parser.close();
+ }
+ }
+ }
+
+ private int findOrAddResourceByFileName(String fileName) {
+ for (int i = 0; i < mResources.size(); i++) {
+ if (mResources.get(i).mFileName.equals(fileName)) {
+ return i;
+ }
+ }
+ int result = mResources.size();
+ mResources.add(new Resource(fileName));
+ return result;
+ }
+
+ private Resource findResourceBySampleId(int sampleId) {
+ for (Resource res : mResources) {
+ if (res.mSampleId == sampleId) {
+ return res;
+ }
+ }
+ return null;
+ }
+
+ private class SfxWorker extends Thread {
+ SfxWorker() {
+ super("AS.SfxWorker");
+ }
+
+ @Override
+ public void run() {
+ Looper.prepare();
+ synchronized (SoundEffectsHelper.this) {
+ mSfxHandler = new SfxHandler();
+ SoundEffectsHelper.this.notify();
+ }
+ Looper.loop();
+ }
+ }
+
+ private class SfxHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_LOAD_EFFECTS:
+ onLoadSoundEffects((OnEffectsLoadCompleteHandler) msg.obj);
+ break;
+ case MSG_UNLOAD_EFFECTS:
+ onUnloadSoundEffects();
+ break;
+ case MSG_PLAY_EFFECT:
+ onLoadSoundEffects(new OnEffectsLoadCompleteHandler() {
+ @Override
+ public void run(boolean success) {
+ if (success) {
+ onPlaySoundEffect(msg.arg1 /*effect*/, msg.arg2 /*volume*/);
+ }
+ }
+ });
+ break;
+ case MSG_LOAD_EFFECTS_TIMEOUT:
+ if (mSoundPoolLoader != null) {
+ mSoundPoolLoader.onTimeout();
+ }
+ break;
+ }
+ }
+ }
+
+ private class SoundPoolLoader implements
+ android.media.SoundPool.OnLoadCompleteListener {
+
+ private List<OnEffectsLoadCompleteHandler> mLoadCompleteHandlers =
+ new ArrayList<OnEffectsLoadCompleteHandler>();
+
+ SoundPoolLoader() {
+ // SoundPool use the current Looper when creating its message handler.
+ // Since SoundPoolLoader is created on the SfxWorker thread, SoundPool's
+ // message handler ends up running on it (it's OK to have multiple
+ // handlers on the same Looper). Thus, onLoadComplete gets executed
+ // on the worker thread.
+ mSoundPool.setOnLoadCompleteListener(this);
+ }
+
+ void addHandler(OnEffectsLoadCompleteHandler handler) {
+ if (handler != null) {
+ mLoadCompleteHandlers.add(handler);
+ }
+ }
+
+ @Override
+ public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
+ if (status == 0) {
+ int remainingToLoad = 0;
+ for (Resource res : mResources) {
+ if (res.mSampleId == sampleId && !res.mLoaded) {
+ logEvent("effect " + res.mFileName + " loaded");
+ res.mLoaded = true;
+ }
+ if (res.mSampleId != EFFECT_NOT_IN_SOUND_POOL && !res.mLoaded) {
+ remainingToLoad++;
+ }
+ }
+ if (remainingToLoad == 0) {
+ onComplete(true);
+ }
+ } else {
+ Resource res = findResourceBySampleId(sampleId);
+ String filePath;
+ if (res != null) {
+ filePath = getResourceFilePath(res);
+ } else {
+ filePath = "with unknown sample ID " + sampleId;
+ }
+ logEvent("effect " + filePath + " loading failed, status " + status);
+ Log.w(TAG, "onLoadSoundEffects(), Error " + status + " while loading sample "
+ + filePath);
+ onComplete(false);
+ }
+ }
+
+ void onTimeout() {
+ onComplete(false);
+ }
+
+ void onComplete(boolean success) {
+ mSoundPool.setOnLoadCompleteListener(null);
+ for (OnEffectsLoadCompleteHandler handler : mLoadCompleteHandlers) {
+ handler.run(success);
+ }
+ logEvent("effects loading " + (success ? "completed" : "failed"));
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index def7f75ac3b6..a38abdc1bed0 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -63,6 +63,7 @@ import com.android.server.SystemServerInitThreadPool;
import com.android.server.biometrics.AuthenticationClient;
import com.android.server.biometrics.BiometricServiceBase;
import com.android.server.biometrics.BiometricUtils;
+import com.android.server.biometrics.ClientMonitor;
import com.android.server.biometrics.Constants;
import com.android.server.biometrics.EnumerateClient;
import com.android.server.biometrics.RemovalClient;
@@ -342,14 +343,24 @@ public class FaceService extends BiometricServiceBase {
@Override // Binder call
public int revokeChallenge(IBinder token) {
checkPermission(MANAGE_BIOMETRIC);
- return startRevokeChallenge(token);
+ // TODO(b/137106905): Schedule binder calls in FaceService to avoid deadlocks.
+ if (getCurrentClient() == null) {
+ // if we aren't handling any other HIDL calls (mCurrentClient == null), revoke the
+ // challenge right away.
+ return startRevokeChallenge(token);
+ } else {
+ // postpone revoking the challenge until we finish processing the current HIDL call.
+ mRevokeChallengePending = true;
+ return Status.OK;
+ }
}
@Override // Binder call
- public void enroll(final IBinder token, final byte[] cryptoToken,
+ public void enroll(int userId, final IBinder token, final byte[] cryptoToken,
final IFaceServiceReceiver receiver, final String opPackageName,
final int[] disabledFeatures) {
checkPermission(MANAGE_BIOMETRIC);
+ updateActiveGroup(userId, opPackageName);
mNotificationManager.cancelAsUser(NOTIFICATION_TAG, NOTIFICATION_ID,
UserHandle.CURRENT);
@@ -448,8 +459,9 @@ public class FaceService extends BiometricServiceBase {
@Override // Binder call
public void remove(final IBinder token, final int faceId, final int userId,
- final IFaceServiceReceiver receiver) {
+ final IFaceServiceReceiver receiver, final String opPackageName) {
checkPermission(MANAGE_BIOMETRIC);
+ updateActiveGroup(userId, opPackageName);
if (token == null) {
Slog.w(TAG, "remove(): token is null");
@@ -612,9 +624,10 @@ public class FaceService extends BiometricServiceBase {
}
@Override
- public void setFeature(int feature, boolean enabled, final byte[] token,
- IFaceServiceReceiver receiver) {
+ public void setFeature(int userId, int feature, boolean enabled, final byte[] token,
+ IFaceServiceReceiver receiver, final String opPackageName) {
checkPermission(MANAGE_BIOMETRIC);
+ updateActiveGroup(userId, opPackageName);
mHandler.post(() -> {
if (!FaceService.this.hasEnrolledBiometrics(mCurrentUserId)) {
@@ -644,8 +657,10 @@ public class FaceService extends BiometricServiceBase {
}
@Override
- public void getFeature(int feature, IFaceServiceReceiver receiver) {
+ public void getFeature(int userId, int feature, IFaceServiceReceiver receiver,
+ final String opPackageName) {
checkPermission(MANAGE_BIOMETRIC);
+ updateActiveGroup(userId, opPackageName);
mHandler.post(() -> {
// This should ideally return tri-state, but the user isn't shown settings unless
@@ -807,6 +822,7 @@ public class FaceService extends BiometricServiceBase {
@GuardedBy("this")
private IBiometricsFace mDaemon;
private UsageStats mUsageStats;
+ private boolean mRevokeChallengePending = false;
// One of the AuthenticationClient constants
private int mCurrentUserLockoutMode;
@@ -1036,6 +1052,15 @@ public class FaceService extends BiometricServiceBase {
}
@Override
+ protected void removeClient(ClientMonitor client) {
+ super.removeClient(client);
+ if (mRevokeChallengePending) {
+ startRevokeChallenge(null);
+ mRevokeChallengePending = false;
+ }
+ }
+
+ @Override
public void onStart() {
super.onStart();
publishBinderService(Context.FACE_SERVICE, new FaceServiceWrapper());
@@ -1246,7 +1271,11 @@ public class FaceService extends BiometricServiceBase {
return 0;
}
try {
- return daemon.revokeChallenge();
+ final int res = daemon.revokeChallenge();
+ if (res != Status.OK) {
+ Slog.e(TAG, "revokeChallenge returned " + res);
+ }
+ return res;
} catch (RemoteException e) {
Slog.e(TAG, "startRevokeChallenge failed", e);
}
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
new file mode 100644
index 000000000000..bb3b9be2bd2f
--- /dev/null
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.compat;
+
+import android.annotation.Nullable;
+import android.compat.annotation.EnabledAfter;
+import android.content.pm.ApplicationInfo;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Represents the state of a single compatibility change.
+ *
+ * <p>A compatibility change has a default setting, determined by the {@code enableAfterTargetSdk}
+ * and {@code disabled} constructor parameters. If a change is {@code disabled}, this overrides any
+ * target SDK criteria set. These settings can be overridden for a specific package using
+ * {@link #addPackageOverride(String, boolean)}.
+ *
+ * <p>Note, this class is not thread safe so callers must ensure thread safety.
+ */
+public final class CompatChange {
+
+ private final long mChangeId;
+ @Nullable private final String mName;
+ private final int mEnableAfterTargetSdk;
+ private final boolean mDisabled;
+ private Map<String, Boolean> mPackageOverrides;
+
+ public CompatChange(long changeId) {
+ this(changeId, null, -1, false);
+ }
+
+ /**
+ * @param changeId Unique ID for the change. See {@link android.compat.Compatibility}.
+ * @param name Short descriptive name.
+ * @param enableAfterTargetSdk {@code targetSdkVersion} restriction. See {@link EnabledAfter};
+ * -1 if the change is always enabled.
+ * @param disabled If {@code true}, overrides any {@code enableAfterTargetSdk} set.
+ */
+ public CompatChange(long changeId, @Nullable String name, int enableAfterTargetSdk,
+ boolean disabled) {
+ mChangeId = changeId;
+ mName = name;
+ mEnableAfterTargetSdk = enableAfterTargetSdk;
+ mDisabled = disabled;
+ }
+
+ long getId() {
+ return mChangeId;
+ }
+
+ @Nullable
+ String getName() {
+ return mName;
+ }
+
+ /**
+ * Force the enabled state of this change for a given package name. The change will only take
+ * effect after that packages process is killed and restarted.
+ *
+ * <p>Note, this method is not thread safe so callers must ensure thread safety.
+ *
+ * @param pname Package name to enable the change for.
+ * @param enabled Whether or not to enable the change.
+ */
+ void addPackageOverride(String pname, boolean enabled) {
+ if (mPackageOverrides == null) {
+ mPackageOverrides = new HashMap<>();
+ }
+ mPackageOverrides.put(pname, enabled);
+ }
+
+ /**
+ * Remove any package override for the given package name, restoring the default behaviour.
+ *
+ * <p>Note, this method is not thread safe so callers must ensure thread safety.
+ *
+ * @param pname Package name to reset to defaults for.
+ */
+ void removePackageOverride(String pname) {
+ if (mPackageOverrides != null) {
+ mPackageOverrides.remove(pname);
+ }
+ }
+
+ /**
+ * Find if this change is enabled for the given package, taking into account any overrides that
+ * exist.
+ *
+ * @param app Info about the app in question
+ * @return {@code true} if the change should be enabled for the package.
+ */
+ boolean isEnabled(ApplicationInfo app) {
+ if (mPackageOverrides != null && mPackageOverrides.containsKey(app.packageName)) {
+ return mPackageOverrides.get(app.packageName);
+ }
+ if (mDisabled) {
+ return false;
+ }
+ if (mEnableAfterTargetSdk != -1) {
+ return app.targetSdkVersion > mEnableAfterTargetSdk;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("ChangeId(")
+ .append(mChangeId);
+ if (mName != null) {
+ sb.append("; name=").append(mName);
+ }
+ if (mEnableAfterTargetSdk != -1) {
+ sb.append("; enableAfterTargetSdk=").append(mEnableAfterTargetSdk);
+ }
+ if (mDisabled) {
+ sb.append("; disabled");
+ }
+ if (mPackageOverrides != null && mPackageOverrides.size() > 0) {
+ sb.append("; packageOverrides=").append(mPackageOverrides);
+ }
+ return sb.append(")").toString();
+ }
+}
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
new file mode 100644
index 000000000000..fea5d836ac25
--- /dev/null
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.compat;
+
+import android.content.pm.ApplicationInfo;
+import android.text.TextUtils;
+import android.util.LongArray;
+import android.util.LongSparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * This class maintains state relating to platform compatibility changes.
+ *
+ * <p>It stores the default configuration for each change, and any per-package overrides that have
+ * been configured.
+ */
+public final class CompatConfig {
+
+ private static final CompatConfig sInstance = new CompatConfig();
+
+ @GuardedBy("mChanges")
+ private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>();
+
+ @VisibleForTesting
+ public CompatConfig() {
+ }
+
+ /**
+ * @return The static instance of this class to be used within the system server.
+ */
+ public static CompatConfig get() {
+ return sInstance;
+ }
+
+ /**
+ * Add a change. This is intended to be used by code that reads change config from the
+ * filesystem. This should be done at system startup time.
+ *
+ * @param change The change to add. Any change with the same ID will be overwritten.
+ */
+ public void addChange(CompatChange change) {
+ synchronized (mChanges) {
+ mChanges.put(change.getId(), change);
+ }
+ }
+
+ /**
+ * Retrieves the set of disabled changes for a given app. Any change ID not in the returned
+ * array is by default enabled for the app.
+ *
+ * @param app The app in question
+ * @return A sorted long array of change IDs. We use a primitive array to minimize memory
+ * footprint: Every app process will store this array statically so we aim to reduce
+ * overhead as much as possible.
+ */
+ public long[] getDisabledChanges(ApplicationInfo app) {
+ LongArray disabled = new LongArray();
+ synchronized (mChanges) {
+ for (int i = 0; i < mChanges.size(); ++i) {
+ CompatChange c = mChanges.valueAt(i);
+ if (!c.isEnabled(app)) {
+ disabled.add(c.getId());
+ }
+ }
+ }
+ // Note: we don't need to explicitly sort the array, as the behaviour of LongSparseArray
+ // (mChanges) ensures it's already sorted.
+ return disabled.toArray();
+ }
+
+ /**
+ * Look up a change ID by name.
+ *
+ * @param name Name of the change to look up
+ * @return The change ID, or {@code -1} if no change with that name exists.
+ */
+ public long lookupChangeId(String name) {
+ synchronized (mChanges) {
+ for (int i = 0; i < mChanges.size(); ++i) {
+ if (TextUtils.equals(mChanges.valueAt(i).getName(), name)) {
+ return mChanges.keyAt(i);
+ }
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Find if a given change is enabled for a given application.
+ *
+ * @param changeId The ID of the change in question
+ * @param app App to check for
+ * @return {@code true} if the change is enabled for this app. Also returns {@code true} if the
+ * change ID is not known, as unknown changes are enabled by default.
+ */
+ public boolean isChangeEnabled(long changeId, ApplicationInfo app) {
+ synchronized (mChanges) {
+ CompatChange c = mChanges.get(changeId);
+ if (c == null) {
+ // we know nothing about this change: default behaviour is enabled.
+ return true;
+ }
+ return c.isEnabled(app);
+ }
+ }
+
+ /**
+ * Overrides the enabled state for a given change and app. This method is intended to be used
+ * *only* for debugging purposes, ultimately invoked either by an adb command, or from some
+ * developer settings UI.
+ *
+ * <p>Note, package overrides are not persistent and will be lost on system or runtime restart.
+ *
+ * @param changeId The ID of the change to be overridden. Note, this call will succeed even if
+ * this change is not known; it will only have any affect if any code in the
+ * platform is gated on the ID given.
+ * @param packageName The app package name to override the change for.
+ * @param enabled If the change should be enabled or disabled.
+ */
+ public void addOverride(long changeId, String packageName, boolean enabled) {
+ synchronized (mChanges) {
+ CompatChange c = mChanges.get(changeId);
+ if (c == null) {
+ c = new CompatChange(changeId);
+ addChange(c);
+ }
+ c.addPackageOverride(packageName, enabled);
+ }
+ }
+
+ /**
+ * Removes an override previously added via {@link #addOverride(long, String, boolean)}. This
+ * restores the default behaviour for the given change and app, once any app processes have been
+ * restarted.
+ *
+ * @param changeId The ID of the change that was overridden.
+ * @param packageName The app package name that was overridden.
+ */
+ public void removeOverride(long changeId, String packageName) {
+ synchronized (mChanges) {
+ CompatChange c = mChanges.get(changeId);
+ if (c != null) {
+ c.removePackageOverride(packageName);
+ }
+ }
+ }
+
+}
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
new file mode 100644
index 000000000000..456d15e4fba8
--- /dev/null
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.compat;
+
+import android.content.pm.ApplicationInfo;
+import android.util.Slog;
+
+/**
+ * System server internal API for gating and reporting compatibility changes.
+ */
+public class PlatformCompat {
+
+ private static final String TAG = "Compatibility";
+
+ /**
+ * Reports that a compatibility change is affecting an app process now.
+ *
+ * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, ApplicationInfo)},
+ * you do not need to call this API directly. The change will be reported for you in the case
+ * that {@link #isChangeEnabled(long, ApplicationInfo)} returns {@code true}.
+ *
+ * @param changeId The ID of the compatibility change taking effect.
+ * @param appInfo Representing the affected app.
+ */
+ public static void reportChange(long changeId, ApplicationInfo appInfo) {
+ Slog.d(TAG, "Compat change reported: " + changeId + "; UID " + appInfo.uid);
+ // TODO log via StatsLog
+ }
+
+ /**
+ * Query if a given compatibility change is enabled for an app process. This method should
+ * be called when implementing functionality on behalf of the affected app.
+ *
+ * <p>If this method returns {@code true}, the calling code should implement the compatibility
+ * change, resulting in differing behaviour compared to earlier releases. If this method returns
+ * {@code false}, the calling code should behave as it did in earlier releases.
+ *
+ * <p>When this method returns {@code true}, it will also report the change as
+ * {@link #reportChange(long, ApplicationInfo)} would, so there is no need to call that method
+ * directly.
+ *
+ * @param changeId The ID of the compatibility change in question.
+ * @param appInfo Representing the app in question.
+ * @return {@code true} if the change is enabled for the current app.
+ */
+ public static boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
+ if (CompatConfig.get().isChangeEnabled(changeId, appInfo)) {
+ reportChange(changeId, appInfo);
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 33c84d161a90..4957eed21c70 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -44,6 +44,7 @@ import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
import static android.net.wifi.WifiManager.IFACE_IP_MODE_UNSPECIFIED;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static com.android.server.ConnectivityService.SHORT_ARG;
@@ -89,6 +90,8 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.os.UserManagerInternal.UserRestrictionsListener;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
@@ -97,7 +100,6 @@ import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
-import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.MessageUtils;
@@ -182,12 +184,13 @@ public class Tethering extends BaseNetworkObserver {
// into a single coherent structure.
private final HashSet<IpServer> mForwardedDownstreams;
private final VersionedBroadcastListener mCarrierConfigChange;
- private final VersionedBroadcastListener mDefaultSubscriptionChange;
private final TetheringDependencies mDeps;
private final EntitlementManager mEntitlementMgr;
private final Handler mHandler;
private final RemoteCallbackList<ITetheringEventCallback> mTetheringEventCallbacks =
new RemoteCallbackList<>();
+ private final PhoneStateListener mPhoneStateListener;
+ private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID;
private volatile TetheringConfiguration mConfig;
private InterfaceSet mCurrentUpstreamIfaceSet;
@@ -238,7 +241,6 @@ public class Tethering extends BaseNetworkObserver {
stopTethering(downstream);
});
mEntitlementMgr.setTetheringConfigurationFetcher(() -> {
- maybeDefaultDataSubChanged();
return mConfig;
});
@@ -250,22 +252,26 @@ public class Tethering extends BaseNetworkObserver {
mEntitlementMgr.reevaluateSimCardProvisioning(mConfig);
});
- filter = new IntentFilter();
- filter.addAction(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
- mDefaultSubscriptionChange = new VersionedBroadcastListener(
- "DefaultSubscriptionChangeListener", mContext, mHandler, filter,
- (Intent ignored) -> {
- mLog.log("OBSERVED default data subscription change");
- maybeDefaultDataSubChanged();
- // To avoid launch unexpected provisioning checks, ignore re-provisioning when
- // no CarrierConfig loaded yet. Assume reevaluateSimCardProvisioning() will be
- // triggered again when CarrierConfig is loaded.
- if (mEntitlementMgr.getCarrierConfig(mConfig) != null) {
- mEntitlementMgr.reevaluateSimCardProvisioning(mConfig);
- } else {
- mLog.log("IGNORED reevaluate provisioning due to no carrier config loaded");
- }
- });
+ mPhoneStateListener = new PhoneStateListener(mLooper) {
+ @Override
+ public void onActiveDataSubscriptionIdChanged(int subId) {
+ mLog.log("OBSERVED active data subscription change, from " + mActiveDataSubId
+ + " to " + subId);
+ if (subId == mActiveDataSubId) return;
+
+ mActiveDataSubId = subId;
+ updateConfiguration();
+ // To avoid launching unexpected provisioning checks, ignore re-provisioning when
+ // no CarrierConfig loaded yet. Assume reevaluateSimCardProvisioning() will be
+ // triggered again when CarrierConfig is loaded.
+ if (mEntitlementMgr.getCarrierConfig(mConfig) != null) {
+ mEntitlementMgr.reevaluateSimCardProvisioning(mConfig);
+ } else {
+ mLog.log("IGNORED reevaluate provisioning due to no carrier config loaded");
+ }
+ }
+ };
+
mStateReceiver = new StateReceiver();
// Load tethering configuration.
@@ -276,7 +282,8 @@ public class Tethering extends BaseNetworkObserver {
private void startStateMachineUpdaters(Handler handler) {
mCarrierConfigChange.startListening();
- mDefaultSubscriptionChange.startListening();
+ TelephonyManager.from(mContext).listen(mPhoneStateListener,
+ PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_STATE);
@@ -304,27 +311,17 @@ public class Tethering extends BaseNetworkObserver {
// NOTE: This is always invoked on the mLooper thread.
private void updateConfiguration() {
- final int subId = mDeps.getDefaultDataSubscriptionId();
- updateConfiguration(subId);
- }
-
- private void updateConfiguration(final int subId) {
- mConfig = new TetheringConfiguration(mContext, mLog, subId);
+ mConfig = mDeps.generateTetheringConfiguration(mContext, mLog, mActiveDataSubId);
mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired);
}
private void maybeDunSettingChanged() {
- final boolean isDunRequired = TetheringConfiguration.checkDunRequired(mContext);
+ final boolean isDunRequired = TetheringConfiguration.checkDunRequired(
+ mContext, mActiveDataSubId);
if (isDunRequired == mConfig.isDunRequired) return;
updateConfiguration();
}
- private void maybeDefaultDataSubChanged() {
- final int subId = mDeps.getDefaultDataSubscriptionId();
- if (subId == mConfig.subId) return;
- updateConfiguration(subId);
- }
-
@Override
public void interfaceStatusChanged(String iface, boolean up) {
// Never called directly: only called from interfaceLinkStateChanged.
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
index 8427b6eceab9..1907892c4d87 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -112,7 +112,7 @@ public class TetheringConfiguration {
tetherableWifiRegexs = getResourceStringArray(res, config_tether_wifi_regexs);
tetherableBluetoothRegexs = getResourceStringArray(res, config_tether_bluetooth_regexs);
- isDunRequired = checkDunRequired(ctx);
+ isDunRequired = checkDunRequired(ctx, subId);
chooseUpstreamAutomatically = getResourceBoolean(res, config_tether_upstream_automatic);
preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, isDunRequired);
@@ -228,9 +228,9 @@ public class TetheringConfiguration {
}
/** Check whether dun is required. */
- public static boolean checkDunRequired(Context ctx) {
+ public static boolean checkDunRequired(Context ctx, int id) {
final TelephonyManager tm = (TelephonyManager) ctx.getSystemService(TELEPHONY_SERVICE);
- return (tm != null) ? tm.getTetherApnRequired() : false;
+ return (tm != null) ? tm.getTetherApnRequired(id) : false;
}
private static Collection<Integer> getUpstreamIfaceTypes(Resources res, boolean dunRequired) {
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
index a0aad7c50481..4ad7ac4bead0 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -21,7 +21,6 @@ import android.net.NetworkRequest;
import android.net.ip.IpServer;
import android.net.util.SharedLog;
import android.os.Handler;
-import android.telephony.SubscriptionManager;
import com.android.internal.util.StateMachine;
import com.android.server.connectivity.MockableSystemProperties;
@@ -88,9 +87,10 @@ public class TetheringDependencies {
}
/**
- * Get default data subscription id to build TetheringConfiguration.
+ * Generate a new TetheringConfiguration according to input sub Id.
*/
- public int getDefaultDataSubscriptionId() {
- return SubscriptionManager.getDefaultDataSubscriptionId();
+ public TetheringConfiguration generateTetheringConfiguration(Context ctx, SharedLog log,
+ int subId) {
+ return new TetheringConfiguration(ctx, log, subId);
}
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index b6f3e7db90e8..4f4baab204e6 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -446,6 +446,14 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
assertRunOnServiceThread();
int logicalAddress = message.getSource();
int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
+ if (HdmiUtils.getLocalPortFromPhysicalAddress(
+ physicalAddress, mService.getPhysicalAddress())
+ == HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE) {
+ return super.handleActiveSource(message);
+ }
+ // If the new Active Source is under the current device, check if the device info and the TV
+ // input is ready to switch to the new Active Source. If not ready, buffer the cec command
+ // to handle later when the device is ready.
HdmiDeviceInfo info = getCecDeviceInfo(logicalAddress);
if (info == null) {
HdmiLogger.debug("Device info %X not found; buffering the command", logicalAddress);
@@ -455,7 +463,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
mDelayedMessageBuffer.add(message);
} else {
mDelayedMessageBuffer.removeActiveSource();
- super.handleActiveSource(message);
+ return super.handleActiveSource(message);
}
return true;
}
@@ -846,10 +854,20 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
if (sourcePhysicalAddress != getActiveSource().physicalAddress) {
// If the Active Source recorded by the current device is not synced up with TV,
// update the Active Source internally.
- for (HdmiDeviceInfo info : HdmiUtils.sparseArrayToList(mDeviceInfos)) {
- if (info.getPhysicalAddress() == sourcePhysicalAddress) {
- setActiveSource(info.getLogicalAddress(), info.getPhysicalAddress());
- break;
+ if (sourcePhysicalAddress == mService.getPhysicalAddress()) {
+ // If the active path is the current device itself, update with local info
+ if (mService.playback() != null) {
+ setActiveSource(mService.playback().mAddress, sourcePhysicalAddress);
+ } else {
+ setActiveSource(mAddress, sourcePhysicalAddress);
+ }
+ } else {
+ // If it's not the current device, look for the device info from the list
+ for (HdmiDeviceInfo info : HdmiUtils.sparseArrayToList(mDeviceInfos)) {
+ if (info.getPhysicalAddress() == sourcePhysicalAddress) {
+ setActiveSource(info.getLogicalAddress(), info.getPhysicalAddress());
+ break;
+ }
}
}
// If the Active path from TV's System Audio Mode request does not belong to any
@@ -1014,7 +1032,7 @@ public class HdmiCecLocalDeviceAudioSystem extends HdmiCecLocalDeviceSource {
// Init arc whenever System Audio Mode is on
// Since some TVs don't request ARC on with System Audio Mode on request
if (SystemProperties.getBoolean(Constants.PROPERTY_ARC_SUPPORT, true)
- && isDirectConnectToTv()) {
+ && isDirectConnectToTv() && mService.isSystemAudioActivated()) {
if (!hasAction(ArcInitiationActionFromAvr.class)) {
addAndStartAction(new ArcInitiationActionFromAvr(this));
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index b1516ec490a1..4d5dc6aba937 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -56,6 +56,7 @@ import android.media.tv.TvInputManager;
import android.media.tv.TvInputManager.TvInputCallback;
import android.net.Uri;
import android.os.Build;
+import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -1662,6 +1663,8 @@ public class HdmiControlService extends SystemService {
@Override
public void oneTouchPlay(final IHdmiControlCallback callback) {
enforceAccessPermission();
+ int pid = Binder.getCallingPid();
+ Slog.d(TAG, "Proccess pid: " + pid + " is calling oneTouchPlay.");
runOnServiceThread(new Runnable() {
@Override
public void run() {
diff --git a/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
index c52921ef344b..16cf7eef6a1e 100644
--- a/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractPerUserSystemService.java
@@ -75,6 +75,14 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst
mMaster = master;
mLock = lock;
mUserId = userId;
+ updateIsSetupComplete(userId);
+ }
+
+ /** Updates whether setup is complete for current user */
+ private void updateIsSetupComplete(@UserIdInt int userId) {
+ final String setupComplete = Settings.Secure.getStringForUser(
+ getContext().getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, userId);
+ mSetupComplete = "1".equals(setupComplete);
}
/**
@@ -143,9 +151,7 @@ public abstract class AbstractPerUserSystemService<S extends AbstractPerUserSyst
+ ", disabled=" + disabled + ", mDisabled=" + mDisabled);
}
- final String setupComplete = Settings.Secure.getStringForUser(
- getContext().getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, mUserId);
- mSetupComplete = "1".equals(setupComplete);
+ updateIsSetupComplete(mUserId);
mDisabled = disabled;
updateServiceInfoLocked();
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 49b42df34fa5..09e93759196f 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -17,7 +17,6 @@ package com.android.server.inputmethod;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
-import static android.view.inputmethod.InputMethodSystemProperty.PER_PROFILE_IME_ENABLED;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -1036,9 +1035,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// sender userId can be a real user ID or USER_ALL.
final int senderUserId = pendingResult.getSendingUserId();
if (senderUserId != UserHandle.USER_ALL) {
- final int resolvedUserId = PER_PROFILE_IME_ENABLED
- ? senderUserId : mUserManagerInternal.getProfileParentId(senderUserId);
- if (resolvedUserId != mSettings.getCurrentUserId()) {
+ if (senderUserId != mSettings.getCurrentUserId()) {
// A background user is trying to hide the dialog. Ignore.
return;
}
@@ -1662,9 +1659,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (userId == mSettings.getCurrentUserId()) {
return true;
}
- if (!PER_PROFILE_IME_ENABLED && mSettings.isCurrentProfile(userId)) {
- return true;
- }
// Caveat: A process which has INTERACT_ACROSS_USERS_FULL gets results for the
// foreground user, not for the user of that process. Accordingly InputMethodManagerService
@@ -3005,7 +2999,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return InputBindResult.INVALID_USER;
}
- if (PER_PROFILE_IME_ENABLED && userId != mSettings.getCurrentUserId()) {
+ if (userId != mSettings.getCurrentUserId()) {
switchUserLocked(userId);
}
// Master feature flag that overrides other conditions and forces IME preRendering.
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index b5e19aeed0c5..77e2fbd25670 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -35,13 +35,11 @@ import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.IntArray;
import android.util.Pair;
import android.util.Printer;
import android.util.Slog;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
-import android.view.inputmethod.InputMethodSystemProperty;
import android.view.textservice.SpellCheckerInfo;
import com.android.internal.annotations.GuardedBy;
@@ -1303,9 +1301,6 @@ final class InputMethodUtils {
* Converts a user ID, which can be a pseudo user ID such as {@link UserHandle#USER_ALL} to a
* list of real user IDs.
*
- * <p>This method also converts profile user ID to profile parent user ID unless
- * {@link InputMethodSystemProperty#PER_PROFILE_IME_ENABLED} is {@code true}.</p>
- *
* @param userIdToBeResolved A user ID. Two pseudo user ID {@link UserHandle#USER_CURRENT} and
* {@link UserHandle#USER_ALL} are also supported
* @param currentUserId A real user ID, which will be used when {@link UserHandle#USER_CURRENT}
@@ -1320,17 +1315,7 @@ final class InputMethodUtils {
LocalServices.getService(UserManagerInternal.class);
if (userIdToBeResolved == UserHandle.USER_ALL) {
- if (InputMethodSystemProperty.PER_PROFILE_IME_ENABLED) {
- return userManagerInternal.getUserIds();
- }
- final IntArray result = new IntArray();
- for (int userId : userManagerInternal.getUserIds()) {
- final int parentUserId = userManagerInternal.getProfileParentId(userId);
- if (result.indexOf(parentUserId) < 0) {
- result.add(parentUserId);
- }
- }
- return result.toArray();
+ return userManagerInternal.getUserIds();
}
final int sourceUserId;
@@ -1353,8 +1338,6 @@ final class InputMethodUtils {
}
return new int[]{};
}
- final int resolvedUserId = InputMethodSystemProperty.PER_PROFILE_IME_ENABLED
- ? sourceUserId : userManagerInternal.getProfileParentId(sourceUserId);
- return new int[]{resolvedUserId};
+ return new int[]{sourceUserId};
}
}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index bf6708b77096..e44e9022bf5d 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -446,6 +446,10 @@ public class JobSchedulerService extends com.android.server.SystemService
private static final String KEY_MIN_CONNECTIVITY_COUNT = "min_connectivity_count";
private static final String KEY_MIN_CONTENT_COUNT = "min_content_count";
private static final String KEY_MIN_READY_JOBS_COUNT = "min_ready_jobs_count";
+ private static final String KEY_MIN_READY_NON_ACTIVE_JOBS_COUNT =
+ "min_ready_non_active_jobs_count";
+ private static final String KEY_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS =
+ "max_non_active_job_batch_delay_ms";
private static final String KEY_HEAVY_USE_FACTOR = "heavy_use_factor";
private static final String KEY_MODERATE_USE_FACTOR = "moderate_use_factor";
@@ -476,6 +480,8 @@ public class JobSchedulerService extends com.android.server.SystemService
private static final int DEFAULT_MIN_CONNECTIVITY_COUNT = 1;
private static final int DEFAULT_MIN_CONTENT_COUNT = 1;
private static final int DEFAULT_MIN_READY_JOBS_COUNT = 1;
+ private static final int DEFAULT_MIN_READY_NON_ACTIVE_JOBS_COUNT = 5;
+ private static final long DEFAULT_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS = 31 * MINUTE_IN_MILLIS;
private static final float DEFAULT_HEAVY_USE_FACTOR = .9f;
private static final float DEFAULT_MODERATE_USE_FACTOR = .5f;
private static final int DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT = Integer.MAX_VALUE;
@@ -527,6 +533,18 @@ public class JobSchedulerService extends com.android.server.SystemService
* a much better mechanism.
*/
int MIN_READY_JOBS_COUNT = DEFAULT_MIN_READY_JOBS_COUNT;
+
+ /**
+ * Minimum # of non-ACTIVE jobs for which the JMS will be happy running some work early.
+ */
+ int MIN_READY_NON_ACTIVE_JOBS_COUNT = DEFAULT_MIN_READY_NON_ACTIVE_JOBS_COUNT;
+
+ /**
+ * Don't batch a non-ACTIVE job if it's been delayed due to force batching attempts for
+ * at least this amount of time.
+ */
+ long MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS = DEFAULT_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS;
+
/**
* This is the job execution factor that is considered to be heavy use of the system.
*/
@@ -660,6 +678,12 @@ public class JobSchedulerService extends com.android.server.SystemService
DEFAULT_MIN_CONTENT_COUNT);
MIN_READY_JOBS_COUNT = mParser.getInt(KEY_MIN_READY_JOBS_COUNT,
DEFAULT_MIN_READY_JOBS_COUNT);
+ MIN_READY_NON_ACTIVE_JOBS_COUNT = mParser.getInt(
+ KEY_MIN_READY_NON_ACTIVE_JOBS_COUNT,
+ DEFAULT_MIN_READY_NON_ACTIVE_JOBS_COUNT);
+ MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS = mParser.getLong(
+ KEY_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS,
+ DEFAULT_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS);
HEAVY_USE_FACTOR = mParser.getFloat(KEY_HEAVY_USE_FACTOR,
DEFAULT_HEAVY_USE_FACTOR);
MODERATE_USE_FACTOR = mParser.getFloat(KEY_MODERATE_USE_FACTOR,
@@ -710,6 +734,10 @@ public class JobSchedulerService extends com.android.server.SystemService
pw.printPair(KEY_MIN_CONNECTIVITY_COUNT, MIN_CONNECTIVITY_COUNT).println();
pw.printPair(KEY_MIN_CONTENT_COUNT, MIN_CONTENT_COUNT).println();
pw.printPair(KEY_MIN_READY_JOBS_COUNT, MIN_READY_JOBS_COUNT).println();
+ pw.printPair(KEY_MIN_READY_NON_ACTIVE_JOBS_COUNT,
+ MIN_READY_NON_ACTIVE_JOBS_COUNT).println();
+ pw.printPair(KEY_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS,
+ MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS).println();
pw.printPair(KEY_HEAVY_USE_FACTOR, HEAVY_USE_FACTOR).println();
pw.printPair(KEY_MODERATE_USE_FACTOR, MODERATE_USE_FACTOR).println();
@@ -752,6 +780,10 @@ public class JobSchedulerService extends com.android.server.SystemService
proto.write(ConstantsProto.MIN_CONNECTIVITY_COUNT, MIN_CONNECTIVITY_COUNT);
proto.write(ConstantsProto.MIN_CONTENT_COUNT, MIN_CONTENT_COUNT);
proto.write(ConstantsProto.MIN_READY_JOBS_COUNT, MIN_READY_JOBS_COUNT);
+ proto.write(ConstantsProto.MIN_READY_NON_ACTIVE_JOBS_COUNT,
+ MIN_READY_NON_ACTIVE_JOBS_COUNT);
+ proto.write(ConstantsProto.MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS,
+ MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS);
proto.write(ConstantsProto.HEAVY_USE_FACTOR, HEAVY_USE_FACTOR);
proto.write(ConstantsProto.MODERATE_USE_FACTOR, MODERATE_USE_FACTOR);
@@ -1989,7 +2021,7 @@ public class JobSchedulerService extends com.android.server.SystemService
}
final class ReadyJobQueueFunctor implements Consumer<JobStatus> {
- ArrayList<JobStatus> newReadyJobs;
+ final ArrayList<JobStatus> newReadyJobs = new ArrayList<>();
@Override
public void accept(JobStatus job) {
@@ -1997,9 +2029,6 @@ public class JobSchedulerService extends com.android.server.SystemService
if (DEBUG) {
Slog.d(TAG, " queued " + job.toShortString());
}
- if (newReadyJobs == null) {
- newReadyJobs = new ArrayList<JobStatus>();
- }
newReadyJobs.add(job);
} else {
evaluateControllerStatesLocked(job);
@@ -2007,14 +2036,13 @@ public class JobSchedulerService extends com.android.server.SystemService
}
public void postProcess() {
- if (newReadyJobs != null) {
- noteJobsPending(newReadyJobs);
- mPendingJobs.addAll(newReadyJobs);
- if (mPendingJobs.size() > 1) {
- mPendingJobs.sort(mEnqueueTimeComparator);
- }
+ noteJobsPending(newReadyJobs);
+ mPendingJobs.addAll(newReadyJobs);
+ if (mPendingJobs.size() > 1) {
+ mPendingJobs.sort(mEnqueueTimeComparator);
}
- newReadyJobs = null;
+
+ newReadyJobs.clear();
}
}
private final ReadyJobQueueFunctor mReadyQueueFunctor = new ReadyJobQueueFunctor();
@@ -2031,7 +2059,9 @@ public class JobSchedulerService extends com.android.server.SystemService
int backoffCount;
int connectivityCount;
int contentCount;
- List<JobStatus> runnableJobs;
+ int forceBatchedCount;
+ int unbatchedCount;
+ final List<JobStatus> runnableJobs = new ArrayList<>();
public MaybeReadyJobQueueFunctor() {
reset();
@@ -2051,29 +2081,39 @@ public class JobSchedulerService extends com.android.server.SystemService
}
} catch (RemoteException e) {
}
- if (job.getNumFailures() > 0) {
- backoffCount++;
- }
- if (job.hasIdleConstraint()) {
- idleCount++;
- }
- if (job.hasConnectivityConstraint()) {
- connectivityCount++;
- }
- if (job.hasChargingConstraint()) {
- chargingCount++;
- }
- if (job.hasBatteryNotLowConstraint()) {
- batteryNotLowCount++;
- }
- if (job.hasStorageNotLowConstraint()) {
- storageNotLowCount++;
- }
- if (job.hasContentTriggerConstraint()) {
- contentCount++;
- }
- if (runnableJobs == null) {
- runnableJobs = new ArrayList<>();
+ if (mConstants.MIN_READY_NON_ACTIVE_JOBS_COUNT > 1
+ && job.getStandbyBucket() != ACTIVE_INDEX
+ && (job.getFirstForceBatchedTimeElapsed() == 0
+ || sElapsedRealtimeClock.millis() - job.getFirstForceBatchedTimeElapsed()
+ < mConstants.MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS)) {
+ // Force batching non-ACTIVE jobs. Don't include them in the other counts.
+ forceBatchedCount++;
+ if (job.getFirstForceBatchedTimeElapsed() == 0) {
+ job.setFirstForceBatchedTimeElapsed(sElapsedRealtimeClock.millis());
+ }
+ } else {
+ unbatchedCount++;
+ if (job.getNumFailures() > 0) {
+ backoffCount++;
+ }
+ if (job.hasIdleConstraint()) {
+ idleCount++;
+ }
+ if (job.hasConnectivityConstraint()) {
+ connectivityCount++;
+ }
+ if (job.hasChargingConstraint()) {
+ chargingCount++;
+ }
+ if (job.hasBatteryNotLowConstraint()) {
+ batteryNotLowCount++;
+ }
+ if (job.hasStorageNotLowConstraint()) {
+ storageNotLowCount++;
+ }
+ if (job.hasContentTriggerConstraint()) {
+ contentCount++;
+ }
}
runnableJobs.add(job);
} else {
@@ -2089,8 +2129,9 @@ public class JobSchedulerService extends com.android.server.SystemService
batteryNotLowCount >= mConstants.MIN_BATTERY_NOT_LOW_COUNT ||
storageNotLowCount >= mConstants.MIN_STORAGE_NOT_LOW_COUNT ||
contentCount >= mConstants.MIN_CONTENT_COUNT ||
- (runnableJobs != null
- && runnableJobs.size() >= mConstants.MIN_READY_JOBS_COUNT)) {
+ forceBatchedCount >= mConstants.MIN_READY_NON_ACTIVE_JOBS_COUNT ||
+ (unbatchedCount > 0 && (unbatchedCount + forceBatchedCount)
+ >= mConstants.MIN_READY_JOBS_COUNT)) {
if (DEBUG) {
Slog.d(TAG, "maybeQueueReadyJobsForExecutionLocked: Running jobs.");
}
@@ -2109,7 +2150,8 @@ public class JobSchedulerService extends com.android.server.SystemService
reset();
}
- private void reset() {
+ @VisibleForTesting
+ void reset() {
chargingCount = 0;
idleCount = 0;
backoffCount = 0;
@@ -2117,7 +2159,9 @@ public class JobSchedulerService extends com.android.server.SystemService
batteryNotLowCount = 0;
storageNotLowCount = 0;
contentCount = 0;
- runnableJobs = null;
+ forceBatchedCount = 0;
+ unbatchedCount = 0;
+ runnableJobs.clear();
}
}
private final MaybeReadyJobQueueFunctor mMaybeQueueFunctor = new MaybeReadyJobQueueFunctor();
@@ -2226,7 +2270,8 @@ public class JobSchedulerService extends com.android.server.SystemService
* - The job's standby bucket has come due to be runnable.
* - The component is enabled and runnable.
*/
- private boolean isReadyToBeExecutedLocked(JobStatus job) {
+ @VisibleForTesting
+ boolean isReadyToBeExecutedLocked(JobStatus job) {
final boolean jobReady = job.isReady();
if (DEBUG) {
@@ -2358,7 +2403,8 @@ public class JobSchedulerService extends com.android.server.SystemService
return !appIsBad;
}
- private void evaluateControllerStatesLocked(final JobStatus job) {
+ @VisibleForTesting
+ void evaluateControllerStatesLocked(final JobStatus job) {
for (int c = mControllers.size() - 1; c >= 0; --c) {
final StateController sc = mControllers.get(c);
sc.evaluateStateLocked(job);
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 9df77cb2ea7a..d73c25336808 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -186,6 +186,9 @@ public final class JobStatus {
*/
private long whenStandbyDeferred;
+ /** The first time this job was force batched. */
+ private long mFirstForceBatchedTimeElapsed;
+
// Constraints.
final int requiredConstraints;
private final int mRequiredConstraintsOfInterest;
@@ -729,6 +732,18 @@ public final class JobStatus {
whenStandbyDeferred = now;
}
+ /**
+ * Returns the first time this job was force batched, in the elapsed realtime timebase. Will be
+ * 0 if this job was never force batched.
+ */
+ public long getFirstForceBatchedTimeElapsed() {
+ return mFirstForceBatchedTimeElapsed;
+ }
+
+ public void setFirstForceBatchedTimeElapsed(long now) {
+ mFirstForceBatchedTimeElapsed = now;
+ }
+
public String getSourceTag() {
return sourceTag;
}
@@ -1625,6 +1640,12 @@ public final class JobStatus {
TimeUtils.formatDuration(whenStandbyDeferred, elapsedRealtimeMillis, pw);
pw.println();
}
+ if (mFirstForceBatchedTimeElapsed != 0) {
+ pw.print(prefix);
+ pw.print(" Time since first force batch attempt: ");
+ TimeUtils.formatDuration(mFirstForceBatchedTimeElapsed, elapsedRealtimeMillis, pw);
+ pw.println();
+ }
pw.print(prefix); pw.print("Enqueue time: ");
TimeUtils.formatDuration(enqueueTime, elapsedRealtimeMillis, pw);
pw.println();
@@ -1817,6 +1838,11 @@ public final class JobStatus {
proto.write(JobStatusDumpProto.STANDBY_BUCKET, standbyBucket);
proto.write(JobStatusDumpProto.ENQUEUE_DURATION_MS, elapsedRealtimeMillis - enqueueTime);
+ proto.write(JobStatusDumpProto.TIME_SINCE_FIRST_DEFERRAL_MS,
+ whenStandbyDeferred == 0 ? 0 : elapsedRealtimeMillis - whenStandbyDeferred);
+ proto.write(JobStatusDumpProto.TIME_SINCE_FIRST_FORCE_BATCH_ATTEMPT_MS,
+ mFirstForceBatchedTimeElapsed == 0
+ ? 0 : elapsedRealtimeMillis - mFirstForceBatchedTimeElapsed);
if (earliestRunTimeElapsedMillis == NO_EARLIEST_RUNTIME) {
proto.write(JobStatusDumpProto.TIME_UNTIL_EARLIEST_RUNTIME_MS, 0);
} else {
diff --git a/services/core/java/com/android/server/location/AbstractLocationProvider.java b/services/core/java/com/android/server/location/AbstractLocationProvider.java
index 8107e9fe3e67..c1a63940c080 100644
--- a/services/core/java/com/android/server/location/AbstractLocationProvider.java
+++ b/services/core/java/com/android/server/location/AbstractLocationProvider.java
@@ -77,6 +77,22 @@ public abstract class AbstractLocationProvider {
}
/**
+ * Call this method to report a change in provider enabled/disabled status. May be called from
+ * any thread.
+ */
+ protected void setEnabled(boolean enabled) {
+ mLocationProviderManager.onSetEnabled(enabled);
+ }
+
+ /**
+ * Call this method to report a change in provider properties. May be called from
+ * any thread.
+ */
+ protected void setProperties(ProviderProperties properties) {
+ mLocationProviderManager.onSetProperties(properties);
+ }
+
+ /**
* Call this method to report a new location. May be called from any thread.
*/
protected void reportLocation(Location location) {
@@ -91,39 +107,35 @@ public abstract class AbstractLocationProvider {
}
/**
- * Call this method to report a change in provider enabled/disabled status. May be called from
- * any thread.
+ * Invoked by the location service to return a list of packages currently associated with this
+ * provider. May be called from any thread.
*/
- protected void setEnabled(boolean enabled) {
- mLocationProviderManager.onSetEnabled(enabled);
+ public List<String> getProviderPackages() {
+ return Collections.singletonList(mContext.getPackageName());
}
/**
- * Call this method to report a change in provider properties. May be called from
- * any thread.
+ * Invoked by the location service to deliver a new request for fulfillment to the provider.
+ * Replaces any previous requests completely. Will always be invoked from the location service
+ * thread with a cleared binder identity.
*/
- protected void setProperties(ProviderProperties properties) {
- mLocationProviderManager.onSetProperties(properties);
- }
-
- /** Returns list of packages currently associated with this provider. */
- public List<String> getProviderPackages() {
- return Collections.singletonList(mContext.getPackageName());
- }
+ public abstract void onSetRequest(ProviderRequest request, WorkSource source);
/**
- * Called when the location service delivers a new request for fulfillment to the provider.
- * Replaces any previous requests completely.
+ * Invoked by the location service to deliver a custom command to this provider. Will always be
+ * invoked from the location service thread with a cleared binder identity.
*/
- public abstract void setRequest(ProviderRequest request, WorkSource source);
+ public void onSendExtraCommand(int uid, int pid, String command, Bundle extras) {}
/**
- * Called to dump debug or log information.
+ * Invoked by the location service to dump debug or log information. May be invoked from any
+ * thread.
*/
public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args);
/**
- * Retrieves the current status of the provider.
+ * Invoked by the location service to retrieve the current status of the provider. May be
+ * invoked from any thread.
*
* @deprecated Will be removed in a future release.
*/
@@ -133,7 +145,8 @@ public abstract class AbstractLocationProvider {
}
/**
- * Retrieves the last update time of the status of the provider.
+ * Invoked by the location service to retrieve the last update time of the status of the
+ * provider. May be invoked from any thread.
*
* @deprecated Will be removed in a future release.
*/
@@ -141,10 +154,4 @@ public abstract class AbstractLocationProvider {
public long getStatusUpdateTime() {
return 0;
}
-
- /**
- * Sends a custom command to this provider. Called with the original binder identity of the
- * caller.
- */
- public abstract void sendExtraCommand(String command, Bundle extras);
}
diff --git a/services/core/java/com/android/server/location/GeofenceManager.java b/services/core/java/com/android/server/location/GeofenceManager.java
index fafe99c9fe18..a1922067e7cf 100644
--- a/services/core/java/com/android/server/location/GeofenceManager.java
+++ b/services/core/java/com/android/server/location/GeofenceManager.java
@@ -16,11 +16,6 @@
package com.android.server.location;
-import java.io.PrintWriter;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.content.ContentResolver;
@@ -44,6 +39,11 @@ import android.util.Slog;
import com.android.server.LocationManagerService;
import com.android.server.PendingIntentUtils;
+import java.io.PrintWriter;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
public class GeofenceManager implements LocationListener, PendingIntent.OnFinished {
private static final String TAG = "GeofenceManager";
private static final boolean D = LocationManagerService.D;
@@ -79,13 +79,13 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish
private final GeofenceHandler mHandler;
private final LocationBlacklist mBlacklist;
- private Object mLock = new Object();
+ private final Object mLock = new Object();
// access to members below is synchronized on mLock
/**
* A list containing all registered geofences.
*/
- private List<GeofenceState> mFences = new LinkedList<GeofenceState>();
+ private List<GeofenceState> mFences = new LinkedList<>();
/**
* This is set true when we have an active request for {@link Location} updates via
@@ -272,8 +272,8 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish
*/
// Runs on the handler.
private void updateFences() {
- List<PendingIntent> enterIntents = new LinkedList<PendingIntent>();
- List<PendingIntent> exitIntents = new LinkedList<PendingIntent>();
+ List<PendingIntent> enterIntents = new LinkedList<>();
+ List<PendingIntent> exitIntents = new LinkedList<>();
synchronized (mLock) {
mPendingUpdate = false;
@@ -446,14 +446,8 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish
}
public void dump(PrintWriter pw) {
- pw.println(" Geofences:");
-
for (GeofenceState state : mFences) {
- pw.append(" ");
- pw.append(state.mPackageName);
- pw.append(" ");
- pw.append(state.mFence.toString());
- pw.append("\n");
+ pw.println(state.mPackageName + " " + state.mFence);
}
}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index c312b76cc463..6911b7c8f565 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -182,7 +182,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
private static final int INJECT_NTP_TIME = 5;
// PSDS stands for Predicted Satellite Data Service
private static final int DOWNLOAD_PSDS_DATA = 6;
- private static final int UPDATE_LOCATION = 7; // Handle external location from network listener
private static final int DOWNLOAD_PSDS_DATA_FINISHED = 11;
private static final int INITIALIZE_HANDLER = 13;
private static final int REQUEST_LOCATION = 16;
@@ -877,7 +876,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
});
}
- private void handleUpdateLocation(Location location) {
+ private void injectLocation(Location location) {
if (location.hasAccuracy()) {
if (DEBUG) {
Log.d(TAG, "injectLocation: " + location);
@@ -1029,7 +1028,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
@Override
- public void setRequest(ProviderRequest request, WorkSource source) {
+ public void onSetRequest(ProviderRequest request, WorkSource source) {
sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
}
@@ -1166,7 +1165,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
@Override
- public void sendExtraCommand(String command, Bundle extras) {
+ public void onSendExtraCommand(int uid, int pid, String command, Bundle extras) {
long identity = Binder.clearCallingIdentity();
try {
@@ -2034,9 +2033,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
case DOWNLOAD_PSDS_DATA_FINISHED:
mDownloadPsdsDataPending = STATE_IDLE;
break;
- case UPDATE_LOCATION:
- handleUpdateLocation((Location) msg.obj);
- break;
case INITIALIZE_HANDLER:
handleInitialize();
break;
@@ -2132,7 +2128,7 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
public void onLocationChanged(Location location) {
// this callback happens on mHandler looper
if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
- handleUpdateLocation(location);
+ injectLocation(location);
}
}
}
@@ -2161,8 +2157,6 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
return "DOWNLOAD_PSDS_DATA";
case DOWNLOAD_PSDS_DATA_FINISHED:
return "DOWNLOAD_PSDS_DATA_FINISHED";
- case UPDATE_LOCATION:
- return "UPDATE_LOCATION";
case INITIALIZE_HANDLER:
return "INITIALIZE_HANDLER";
case REPORT_LOCATION:
@@ -2177,18 +2171,18 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
StringBuilder s = new StringBuilder();
- s.append(" mStarted=").append(mStarted).append(" (changed ");
+ s.append("mStarted=").append(mStarted).append(" (changed ");
TimeUtils.formatDuration(SystemClock.elapsedRealtime()
- mStartedChangedElapsedRealtime, s);
s.append(" ago)").append('\n');
- s.append(" mFixInterval=").append(mFixInterval).append('\n');
- s.append(" mLowPowerMode=").append(mLowPowerMode).append('\n');
- s.append(" mGnssMeasurementsProvider.isRegistered()=")
+ s.append("mFixInterval=").append(mFixInterval).append('\n');
+ s.append("mLowPowerMode=").append(mLowPowerMode).append('\n');
+ s.append("mGnssMeasurementsProvider.isRegistered()=")
.append(mGnssMeasurementsProvider.isRegistered()).append('\n');
- s.append(" mGnssNavigationMessageProvider.isRegistered()=")
+ s.append("mGnssNavigationMessageProvider.isRegistered()=")
.append(mGnssNavigationMessageProvider.isRegistered()).append('\n');
- s.append(" mDisableGpsForPowerManager=").append(mDisableGpsForPowerManager).append('\n');
- s.append(" mTopHalCapabilities=0x").append(Integer.toHexString(mTopHalCapabilities));
+ s.append("mDisableGpsForPowerManager=").append(mDisableGpsForPowerManager).append('\n');
+ s.append("mTopHalCapabilities=0x").append(Integer.toHexString(mTopHalCapabilities));
s.append(" ( ");
if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHEDULING ");
if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
@@ -2205,12 +2199,13 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
}
s.append(")\n");
if (hasCapability(GPS_CAPABILITY_MEASUREMENT_CORRECTIONS)) {
- s.append(" SubHal=MEASUREMENT_CORRECTIONS[");
+ s.append("SubHal=MEASUREMENT_CORRECTIONS[");
s.append(mGnssMeasurementCorrectionsProvider.toStringCapabilities());
s.append("]\n");
}
s.append(mGnssMetrics.dumpGnssMetricsAsText());
- s.append(" native internal state: ").append(native_get_internal_state());
+ s.append("native internal state: \n");
+ s.append(" ").append(native_get_internal_state());
s.append("\n");
pw.append(s);
}
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index ddbc20358a9d..09911ff1a74e 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -168,7 +168,7 @@ public class LocationProviderProxy extends AbstractLocationProvider {
}
@Override
- public void setRequest(ProviderRequest request, WorkSource source) {
+ public void onSetRequest(ProviderRequest request, WorkSource source) {
synchronized (mRequestLock) {
mRequest = request;
mWorkSource = source;
@@ -181,10 +181,10 @@ public class LocationProviderProxy extends AbstractLocationProvider {
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println(" service=" + mServiceWatcher);
+ pw.println("service=" + mServiceWatcher);
synchronized (mProviderPackagesLock) {
if (mProviderPackages.size() > 1) {
- pw.println(" additional packages=" + mProviderPackages);
+ pw.println("additional packages=" + mProviderPackages);
}
}
}
@@ -206,7 +206,7 @@ public class LocationProviderProxy extends AbstractLocationProvider {
}
@Override
- public void sendExtraCommand(String command, Bundle extras) {
+ public void onSendExtraCommand(int uid, int pid, String command, Bundle extras) {
mServiceWatcher.runOnBinder(binder -> {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
service.sendExtraCommand(command, extras);
diff --git a/services/core/java/com/android/server/location/MockProvider.java b/services/core/java/com/android/server/location/MockProvider.java
index 6accad8a93a0..b0c4c2e65fd8 100644
--- a/services/core/java/com/android/server/location/MockProvider.java
+++ b/services/core/java/com/android/server/location/MockProvider.java
@@ -81,11 +81,11 @@ public class MockProvider extends AbstractLocationProvider {
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println(" last location=" + mLocation);
+ pw.println("last location=" + mLocation);
}
@Override
- public void setRequest(ProviderRequest request, WorkSource source) {}
+ public void onSetRequest(ProviderRequest request, WorkSource source) {}
@Override
public int getStatus(Bundle extras) {
@@ -101,7 +101,4 @@ public class MockProvider extends AbstractLocationProvider {
public long getStatusUpdateTime() {
return mStatusUpdateTime;
}
-
- @Override
- public void sendExtraCommand(String command, Bundle extras) {}
}
diff --git a/services/core/java/com/android/server/location/PassiveProvider.java b/services/core/java/com/android/server/location/PassiveProvider.java
index 3a841c91399e..639b1eb1ed5e 100644
--- a/services/core/java/com/android/server/location/PassiveProvider.java
+++ b/services/core/java/com/android/server/location/PassiveProvider.java
@@ -19,7 +19,6 @@ package com.android.server.location;
import android.content.Context;
import android.location.Criteria;
import android.location.Location;
-import android.os.Bundle;
import android.os.WorkSource;
import com.android.internal.location.ProviderProperties;
@@ -53,7 +52,7 @@ public class PassiveProvider extends AbstractLocationProvider {
}
@Override
- public void setRequest(ProviderRequest request, WorkSource source) {
+ public void onSetRequest(ProviderRequest request, WorkSource source) {
mReportLocation = request.reportLocation;
}
@@ -64,10 +63,7 @@ public class PassiveProvider extends AbstractLocationProvider {
}
@Override
- public void sendExtraCommand(String command, Bundle extras) {}
-
- @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println(" report location=" + mReportLocation);
+ pw.println("report location=" + mReportLocation);
}
}
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
index c13fcd61eeab..9e3401882f45 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java
@@ -85,9 +85,16 @@ final class MediaRoute2ProviderProxy implements ServiceConnection {
mCallback = callback;
}
- public void setSelectedRoute(int uid, String routeId) {
+ public void selectRoute(String packageName, String routeId) {
if (mConnectionReady) {
- mActiveConnection.selectRoute(uid, routeId);
+ mActiveConnection.selectRoute(packageName, routeId);
+ updateBinding();
+ }
+ }
+
+ public void unselectRoute(String packageName, String routeId) {
+ if (mConnectionReady) {
+ mActiveConnection.unselectRotue(packageName, routeId);
updateBinding();
}
}
@@ -235,17 +242,6 @@ final class MediaRoute2ProviderProxy implements ServiceConnection {
}
}
- private void onRouteSelected(Connection connection, int uid, String routeId) {
- if (mActiveConnection != connection) {
- return;
- }
-
- if (DEBUG) {
- Slog.d(TAG, this + ": State changed ");
- }
- mHandler.post(mStateChanged);
- }
-
private void onProviderInfoUpdated(Connection connection, MediaRoute2ProviderInfo info) {
if (mActiveConnection != connection) {
return;
@@ -298,8 +294,8 @@ final class MediaRoute2ProviderProxy implements ServiceConnection {
public boolean register() {
try {
mProvider.asBinder().linkToDeath(this, 0);
- mProvider.registerClient(mClient);
- mHandler.post((Runnable) () -> onConnectionReady(Connection.this));
+ mProvider.setClient(mClient);
+ mHandler.post(() -> onConnectionReady(Connection.this));
return true;
} catch (RemoteException ex) {
binderDied();
@@ -312,23 +308,25 @@ final class MediaRoute2ProviderProxy implements ServiceConnection {
mClient.dispose();
}
- public void selectRoute(int uid, String id) {
- if (mClient == null) {
- return;
- }
+ public void selectRoute(String packageName, String routeId) {
try {
- mProvider.selectRoute(mClient, uid, id);
+ mProvider.selectRoute(packageName, routeId);
} catch (RemoteException ex) {
Slog.e(TAG, "Failed to deliver request to set discovery mode.", ex);
}
}
- public void sendControlRequest(String id, Intent request) {
- if (mClient == null) {
- return;
+ public void unselectRotue(String packageName, String routeId) {
+ try {
+ mProvider.unselectRoute(packageName, routeId);
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Failed to deliver request to set discovery mode.", ex);
}
+ }
+
+ public void sendControlRequest(String routeId, Intent request) {
try {
- mProvider.notifyControlRequestSent(mClient, id, request);
+ mProvider.notifyControlRequestSent(routeId, request);
} catch (RemoteException ex) {
Slog.e(TAG, "Failed to deliver request to send control request.", ex);
}
@@ -339,10 +337,6 @@ final class MediaRoute2ProviderProxy implements ServiceConnection {
mHandler.post(() -> onConnectionDied(Connection.this));
}
- void postRouteSelected(int uid, String routeId) {
- mHandler.post(() -> onRouteSelected(Connection.this, uid, routeId));
- }
-
void postProviderUpdated(MediaRoute2ProviderInfo info) {
mHandler.post(() -> onProviderInfoUpdated(Connection.this, info));
}
@@ -360,14 +354,6 @@ final class MediaRoute2ProviderProxy implements ServiceConnection {
}
@Override
- public void notifyRouteSelected(int uid, String routeId) throws RemoteException {
- Connection connection = mConnectionRef.get();
- if (connection != null) {
- connection.postRouteSelected(uid, routeId);
- }
- }
-
- @Override
public void notifyProviderInfoUpdated(MediaRoute2ProviderInfo info) {
Connection connection = mConnectionRef.get();
if (connection != null) {
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 0398658f18cd..01936c9159dd 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -183,11 +183,11 @@ class MediaRouter2ServiceImpl {
}
public void selectClientRoute2(@NonNull IMediaRouter2Manager manager,
- int clientUid, @Nullable MediaRoute2Info route) {
+ String packageName, @Nullable MediaRoute2Info route) {
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- selectClientRoute2Locked(manager, clientUid, route);
+ selectClientRoute2Locked(manager, packageName, route);
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -267,8 +267,7 @@ class MediaRouter2ServiceImpl {
}
}
- private void selectRoute2Locked(IMediaRouter2Client client,
- MediaRoute2Info route) {
+ private void selectRoute2Locked(IMediaRouter2Client client, MediaRoute2Info route) {
ClientRecord clientRecord = mAllClientRecords.get(client.asBinder());
if (clientRecord != null) {
MediaRoute2Info oldRoute = clientRecord.mSelectedRoute;
@@ -364,10 +363,10 @@ class MediaRouter2ServiceImpl {
}
private void selectClientRoute2Locked(IMediaRouter2Manager manager,
- int clientUid, MediaRoute2Info route) {
+ String packageName, MediaRoute2Info route) {
ManagerRecord managerRecord = mAllManagerRecords.get(manager.asBinder());
if (managerRecord != null) {
- ClientRecord clientRecord = managerRecord.mUserRecord.findClientRecordByUid(clientUid);
+ ClientRecord clientRecord = managerRecord.mUserRecord.findClientRecord(packageName);
if (clientRecord == null) {
Slog.w(TAG, "Ignoring route selection for unknown client.");
}
@@ -413,9 +412,11 @@ class MediaRouter2ServiceImpl {
mHandler = new UserHandler(MediaRouter2ServiceImpl.this, this);
}
- ClientRecord findClientRecordByUid(int uid) {
+ ClientRecord findClientRecord(String packageName) {
for (ClientRecord clientRecord : mClientRecords) {
- if (clientRecord.mUid == uid) return clientRecord;
+ if (TextUtils.equals(clientRecord.mPackageName, packageName)) {
+ return clientRecord;
+ }
}
return null;
}
@@ -501,8 +502,7 @@ class MediaRouter2ServiceImpl {
static final int MSG_STOP = 2;
static final int MSG_UPDATE_CLIENT_USAGE = 11;
- static final int MSG_UPDATE_MANAGER_STATE = 12;
- static final int MSG_SEND_CONTROL_REQUEST = 13;
+ static final int MSG_SEND_CONTROL_REQUEST = 12;
private final WeakReference<MediaRouter2ServiceImpl> mServiceRef;
private final UserRecord mUserRecord;
@@ -539,10 +539,6 @@ class MediaRouter2ServiceImpl {
updateClientUsage((ClientRecord) msg.obj);
break;
}
- case MSG_UPDATE_MANAGER_STATE: {
- updateManagerState();
- break;
- }
case MSG_SEND_CONTROL_REQUEST: {
Pair<MediaRoute2Info, Intent> obj = (Pair<MediaRoute2Info, Intent>) msg.obj;
sendControlRequest(obj.first, obj.second);
@@ -585,20 +581,24 @@ class MediaRouter2ServiceImpl {
scheduleUpdateManagerState();
}
- private void unselectRoute(ClientRecord clientRecord, MediaRoute2Info route) {
+ private void selectRoute(ClientRecord clientRecord, MediaRoute2Info route) {
if (route != null) {
MediaRoute2ProviderProxy provider = findProvider(route.getProviderId());
- if (provider != null) {
- provider.setSelectedRoute(clientRecord.mUid, null);
+ if (provider == null) {
+ Log.w(TAG, "Ignoring to select route of unknown provider " + route);
+ } else {
+ provider.selectRoute(clientRecord.mPackageName, route.getId());
}
}
}
- private void selectRoute(ClientRecord clientRecord, MediaRoute2Info route) {
+ private void unselectRoute(ClientRecord clientRecord, MediaRoute2Info route) {
if (route != null) {
MediaRoute2ProviderProxy provider = findProvider(route.getProviderId());
- if (provider != null) {
- provider.setSelectedRoute(clientRecord.mUid, route.getId());
+ if (provider == null) {
+ Log.w(TAG, "Ignoring to unselect route of unknown provider " + route);
+ } else {
+ provider.unselectRoute(clientRecord.mPackageName, route.getId());
}
}
}
@@ -613,7 +613,7 @@ class MediaRouter2ServiceImpl {
private void scheduleUpdateManagerState() {
if (!mManagerStateUpdateScheduled) {
mManagerStateUpdateScheduled = true;
- sendEmptyMessage(MSG_UPDATE_MANAGER_STATE);
+ post(this::updateManagerState);
}
}
@@ -670,8 +670,9 @@ class MediaRouter2ServiceImpl {
}
for (IMediaRouter2Manager manager : managers) {
try {
- manager.notifyRouteSelected(clientRecord.mUid, clientRecord.mSelectedRoute);
- manager.notifyControlCategoriesChanged(clientRecord.mUid,
+ manager.notifyRouteSelected(clientRecord.mPackageName,
+ clientRecord.mSelectedRoute);
+ manager.notifyControlCategoriesChanged(clientRecord.mPackageName,
clientRecord.mControlCategories);
} catch (RemoteException ex) {
Slog.w(TAG, "Failed to update client usage. Manager probably died.", ex);
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 4577365b6c3a..a43068b87c06 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -482,8 +482,8 @@ public final class MediaRouterService extends IMediaRouterService.Stub
// Binder call
@Override
public void selectClientRoute2(IMediaRouter2Manager manager,
- int clientUid, MediaRoute2Info route) {
- mService2.selectClientRoute2(manager, clientUid, route);
+ String packageName, MediaRoute2Info route) {
+ mService2.selectClientRoute2(manager, packageName, route);
}
// Binder call
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 5bd4b2029e7b..c05655a6a5de 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -92,6 +92,7 @@ import com.android.server.Watchdog.Monitor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
/**
@@ -748,6 +749,8 @@ public class MediaSessionService extends SystemService implements Monitor {
private final int mFullUserId;
private final MediaSessionStack mPriorityStack;
+ private final HashMap<IBinder, CallbackRecord> mCallbacks = new HashMap<>();
+
private PendingIntent mLastMediaButtonReceiver;
private ComponentName mRestoredMediaButtonReceiver;
private int mRestoredMediaButtonReceiverComponentType;
@@ -761,7 +764,6 @@ public class MediaSessionService extends SystemService implements Monitor {
private IOnMediaKeyListener mOnMediaKeyListener;
private int mOnMediaKeyListenerUid;
- private ICallback mCallback;
FullUserRecord(int fullUserId) {
mFullUserId = fullUserId;
@@ -793,6 +795,24 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
+ public void registerCallbackLocked(ICallback callback, int uid) {
+ IBinder cbBinder = callback.asBinder();
+ CallbackRecord cr = new CallbackRecord(callback, uid);
+ mCallbacks.put(cbBinder, cr);
+ try {
+ cbBinder.linkToDeath(cr, 0);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to register callback", e);
+ mCallbacks.remove(cbBinder);
+ }
+ }
+
+ public void unregisterCallbackLocked(ICallback callback) {
+ IBinder cbBinder = callback.asBinder();
+ CallbackRecord cr = mCallbacks.remove(cbBinder);
+ cbBinder.unlinkToDeath(cr, 0);
+ }
+
public void dumpLocked(PrintWriter pw, String prefix) {
pw.print(prefix + "Record for full_user=" + mFullUserId);
// Dump managed profile user ids associated with this user.
@@ -811,7 +831,10 @@ public class MediaSessionService extends SystemService implements Monitor {
pw.println(indent + "Media key listener: " + mOnMediaKeyListener);
pw.println(indent + "Media key listener package: "
+ getCallingPackageName(mOnMediaKeyListenerUid));
- pw.println(indent + "Callback: " + mCallback);
+ pw.println(indent + "Callbacks: registered " + mCallbacks.size() + " callback(s)");
+ for (CallbackRecord cr : mCallbacks.values()) {
+ pw.println(indent + " from " + getCallingPackageName(cr.uid));
+ }
pw.println(indent + "Last MediaButtonReceiver: " + mLastMediaButtonReceiver);
pw.println(indent + "Restored MediaButtonReceiver: " + mRestoredMediaButtonReceiver);
pw.println(indent + "Restored MediaButtonReceiverComponentType: "
@@ -871,21 +894,18 @@ public class MediaSessionService extends SystemService implements Monitor {
mFullUserId);
}
- private void pushAddressedPlayerChangedLocked() {
- if (mCallback == null) {
- return;
- }
+ private void pushAddressedPlayerChangedLocked(ICallback callback) {
try {
MediaSessionRecord mediaButtonSession = getMediaButtonSessionLocked();
if (mediaButtonSession != null) {
- mCallback.onAddressedPlayerChangedToMediaSession(
+ callback.onAddressedPlayerChangedToMediaSession(
mediaButtonSession.getSessionToken());
} else if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null) {
- mCallback.onAddressedPlayerChangedToMediaButtonReceiver(
+ callback.onAddressedPlayerChangedToMediaButtonReceiver(
mCurrentFullUserRecord.mLastMediaButtonReceiver
.getIntent().getComponent());
} else if (mCurrentFullUserRecord.mRestoredMediaButtonReceiver != null) {
- mCallback.onAddressedPlayerChangedToMediaButtonReceiver(
+ callback.onAddressedPlayerChangedToMediaButtonReceiver(
mCurrentFullUserRecord.mRestoredMediaButtonReceiver);
}
} catch (RemoteException e) {
@@ -893,6 +913,12 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
+ private void pushAddressedPlayerChangedLocked() {
+ for (CallbackRecord cr : mCallbacks.values()) {
+ pushAddressedPlayerChangedLocked(cr.callback);
+ }
+ }
+
private MediaSessionRecord getMediaButtonSessionLocked() {
return isGlobalPriorityActiveLocked()
? mGlobalPrioritySession : mPriorityStack.getMediaButtonSession();
@@ -926,6 +952,23 @@ public class MediaSessionService extends SystemService implements Monitor {
// Pick legacy behavior for BroadcastReceiver or unknown.
return COMPONENT_TYPE_BROADCAST;
}
+
+ final class CallbackRecord implements IBinder.DeathRecipient {
+ public final ICallback callback;
+ public final int uid;
+
+ CallbackRecord(ICallback callback, int uid) {
+ this.callback = callback;
+ this.uid = uid;
+ }
+
+ @Override
+ public void binderDied() {
+ synchronized (mLock) {
+ mCallbacks.remove(callback.asBinder());
+ }
+ }
+ }
}
final class SessionsListenerRecord implements IBinder.DeathRecipient {
@@ -1305,44 +1348,53 @@ public class MediaSessionService extends SystemService implements Monitor {
}
@Override
- public void setCallback(ICallback callback) {
+ public void registerCallback(final ICallback callback) {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(uid);
final long token = Binder.clearCallingIdentity();
try {
- if (!UserHandle.isSameApp(uid, Process.BLUETOOTH_UID)) {
- throw new SecurityException("Only Bluetooth service processes can set"
- + " Callback");
+ if (!hasMediaControlPermission(pid, uid)) {
+ throw new SecurityException("MEDIA_CONTENT_CONTROL permission is required to"
+ + " register Callback");
}
synchronized (mLock) {
- int userId = UserHandle.getUserId(uid);
FullUserRecord user = getFullUserRecordLocked(userId);
if (user == null || user.mFullUserId != userId) {
- Log.w(TAG, "Only the full user can set the callback"
+ Log.w(TAG, "Only the full user can register the callback"
+ ", userId=" + userId);
return;
}
- user.mCallback = callback;
- Log.d(TAG, "The callback " + user.mCallback
- + " is set by " + getCallingPackageName(uid));
- if (user.mCallback == null) {
+ user.registerCallbackLocked(callback, uid);
+ Log.d(TAG, "The callback (" + callback.asBinder()
+ + ") is registered by " + getCallingPackageName(uid));
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void unregisterCallback(final ICallback callback) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(uid);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (!hasMediaControlPermission(pid, uid)) {
+ throw new SecurityException("MEDIA_CONTENT_CONTROL permission is required to"
+ + " unregister Callback");
+ }
+ synchronized (mLock) {
+ FullUserRecord user = getFullUserRecordLocked(userId);
+ if (user == null || user.mFullUserId != userId) {
+ Log.w(TAG, "Only the full user can unregister the callback"
+ + ", userId=" + userId);
return;
}
- try {
- user.mCallback.asBinder().linkToDeath(
- new IBinder.DeathRecipient() {
- @Override
- public void binderDied() {
- synchronized (mLock) {
- user.mCallback = null;
- }
- }
- }, 0);
- user.pushAddressedPlayerChangedLocked();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to set callback", e);
- user.mCallback = null;
- }
+ user.unregisterCallbackLocked(callback);
+ Log.d(TAG, "The callback (" + callback.asBinder()
+ + ") is unregistered by " + getCallingPackageName(uid));
}
} finally {
Binder.restoreCallingIdentity(token);
@@ -1771,6 +1823,7 @@ public class MediaSessionService extends SystemService implements Monitor {
public boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid)
throws RemoteException {
final int uid = Binder.getCallingUid();
+ final int userId = UserHandle.getUserId(uid);
final long token = Binder.clearCallingIdentity();
try {
// Don't perform sanity check between controllerPackageName and controllerUid.
@@ -1781,8 +1834,8 @@ public class MediaSessionService extends SystemService implements Monitor {
// Note that we can use Context#getOpPackageName() instead of
// Context#getPackageName() for getting package name that matches with the PID/UID,
// but it doesn't tell which package has created the MediaController, so useless.
- return hasMediaControlPermission(UserHandle.getUserId(uid), controllerPackageName,
- controllerPid, controllerUid);
+ return hasMediaControlPermission(controllerPid, controllerUid)
+ || hasEnabledNotificationListener(userId, controllerPackageName);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1808,13 +1861,7 @@ public class MediaSessionService extends SystemService implements Monitor {
return resolvedUserId;
}
- private boolean hasMediaControlPermission(int resolvedUserId, String packageName,
- int pid, int uid) throws RemoteException {
- // Allow API calls from the System UI and Settings
- if (hasStatusBarServicePermission(pid, uid)) {
- return true;
- }
-
+ private boolean hasMediaControlPermission(int pid, int uid) {
// Check if it's system server or has MEDIA_CONTENT_CONTROL.
// Note that system server doesn't have MEDIA_CONTENT_CONTROL, so we need extra
// check here.
@@ -1823,11 +1870,15 @@ public class MediaSessionService extends SystemService implements Monitor {
== PackageManager.PERMISSION_GRANTED) {
return true;
} else if (DEBUG) {
- Log.d(TAG, packageName + " (uid=" + uid + ") hasn't granted MEDIA_CONTENT_CONTROL");
+ Log.d(TAG, "uid(" + uid + ") hasn't granted MEDIA_CONTENT_CONTROL");
}
+ return false;
+ }
+ private boolean hasEnabledNotificationListener(int resolvedUserId, String packageName)
+ throws RemoteException {
// You may not access another user's content as an enabled listener.
- final int userId = UserHandle.getUserId(uid);
+ final int userId = UserHandle.getUserId(resolvedUserId);
if (resolvedUserId != userId) {
return false;
}
@@ -1845,7 +1896,7 @@ public class MediaSessionService extends SystemService implements Monitor {
}
}
if (DEBUG) {
- Log.d(TAG, packageName + " (uid=" + uid + ") doesn't have an enabled "
+ Log.d(TAG, packageName + " (uid=" + resolvedUserId + ") doesn't have an enabled "
+ "notification listener");
}
return false;
@@ -1950,13 +2001,14 @@ public class MediaSessionService extends SystemService implements Monitor {
session.sendMediaButton(packageName, pid, uid, asSystemService, keyEvent,
needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
mKeyEventReceiver);
- if (mCurrentFullUserRecord.mCallback != null) {
- try {
- mCurrentFullUserRecord.mCallback.onMediaKeyEventDispatchedToMediaSession(
+ try {
+ for (FullUserRecord.CallbackRecord cr
+ : mCurrentFullUserRecord.mCallbacks.values()) {
+ cr.callback.onMediaKeyEventDispatchedToMediaSession(
keyEvent, session.getSessionToken());
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to send callback", e);
}
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to send callback", e);
}
} else if (mCurrentFullUserRecord.mLastMediaButtonReceiver != null
|| mCurrentFullUserRecord.mRestoredMediaButtonReceiver != null) {
@@ -1980,12 +2032,12 @@ public class MediaSessionService extends SystemService implements Monitor {
receiver.send(mContext,
needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
mediaButtonIntent, mKeyEventReceiver, mHandler);
- if (mCurrentFullUserRecord.mCallback != null) {
- ComponentName componentName = mCurrentFullUserRecord
- .mLastMediaButtonReceiver.getIntent().getComponent();
- if (componentName != null) {
- mCurrentFullUserRecord.mCallback
- .onMediaKeyEventDispatchedToMediaButtonReceiver(
+ ComponentName componentName = mCurrentFullUserRecord
+ .mLastMediaButtonReceiver.getIntent().getComponent();
+ if (componentName != null) {
+ for (FullUserRecord.CallbackRecord cr
+ : mCurrentFullUserRecord.mCallbacks.values()) {
+ cr.callback.onMediaKeyEventDispatchedToMediaButtonReceiver(
keyEvent, componentName);
}
}
@@ -2018,9 +2070,9 @@ public class MediaSessionService extends SystemService implements Monitor {
Log.w(TAG, "Error sending media button to the restored intent "
+ receiver + ", type=" + componentType, e);
}
- if (mCurrentFullUserRecord.mCallback != null) {
- mCurrentFullUserRecord.mCallback
- .onMediaKeyEventDispatchedToMediaButtonReceiver(
+ for (FullUserRecord.CallbackRecord cr
+ : mCurrentFullUserRecord.mCallbacks.values()) {
+ cr.callback.onMediaKeyEventDispatchedToMediaButtonReceiver(
keyEvent, receiver);
}
}
diff --git a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistShellCommand.java b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistShellCommand.java
index 766d8ca8a47c..3b24f46d4714 100644
--- a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistShellCommand.java
+++ b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistShellCommand.java
@@ -17,8 +17,6 @@
package com.android.server.net.watchlist;
import android.content.Context;
-import android.content.Intent;
-import android.net.NetworkWatchlistManager;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -26,7 +24,6 @@ import android.os.ShellCommand;
import android.provider.Settings;
import java.io.FileInputStream;
-import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
@@ -74,10 +71,12 @@ class NetworkWatchlistShellCommand extends ShellCommand {
try {
final String configXmlPath = getNextArgRequired();
final ParcelFileDescriptor pfd = openFileForSystem(configXmlPath, "r");
- if (pfd != null) {
- final InputStream fileStream = new FileInputStream(pfd.getFileDescriptor());
- WatchlistConfig.getInstance().setTestMode(fileStream);
+ if (pfd == null) {
+ pw.println("Error: can't open input file " + configXmlPath);
+ return -1;
}
+ final InputStream fileStream = new FileInputStream(pfd.getFileDescriptor());
+ WatchlistConfig.getInstance().setTestMode(fileStream);
pw.println("Success!");
} catch (Exception ex) {
pw.println("Error: " + ex.toString());
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 7529434f9cd2..976931c5e86b 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -207,6 +207,7 @@ import android.util.Xml;
import android.util.proto.ProtoOutputStream;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
+import android.widget.RemoteViews;
import android.widget.Toast;
import com.android.internal.R;
@@ -463,6 +464,9 @@ public class NotificationManagerService extends SystemService {
private boolean mIsAutomotive;
private boolean mNotificationEffectsEnabledForAutomotive;
+ private int mWarnRemoteViewsSizeBytes;
+ private int mStripRemoteViewsSizeBytes;
+
private MetricsLogger mMetricsLogger;
private TriPredicate<String, Integer, String> mAllowedManagedServicePackages;
@@ -1723,6 +1727,11 @@ public class NotificationManagerService extends SystemService {
mZenModeHelper.setPriorityOnlyDndExemptPackages(getContext().getResources().getStringArray(
com.android.internal.R.array.config_priorityOnlyDndExemptPackages));
+
+ mWarnRemoteViewsSizeBytes = getContext().getResources().getInteger(
+ com.android.internal.R.integer.config_notificationWarnRemoteViewSizeBytes);
+ mStripRemoteViewsSizeBytes = getContext().getResources().getInteger(
+ com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes);
}
@Override
@@ -2256,7 +2265,7 @@ public class NotificationManagerService extends SystemService {
final int callingUid = Binder.getCallingUid();
final boolean isSystemToast = isCallerSystemOrPhone()
|| PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg);
- final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
+ final boolean isPackageSuspended = isPackagePaused(pkg);
final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg,
callingUid);
@@ -4104,17 +4113,7 @@ public class NotificationManagerService extends SystemService {
Preconditions.checkNotNull(pkg);
checkCallerIsSameApp(pkg);
- boolean isPaused;
-
- final PackageManagerInternal pmi = LocalServices.getService(
- PackageManagerInternal.class);
- int flags = pmi.getDistractingPackageRestrictions(
- pkg, Binder.getCallingUserHandle().getIdentifier());
- isPaused = ((flags & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0);
-
- isPaused |= isPackageSuspendedForUser(pkg, Binder.getCallingUid());
-
- return isPaused;
+ return isPackagePausedOrSuspended(pkg, Binder.getCallingUid());
}
private void verifyPrivilegedListener(INotificationListener token, UserHandle user,
@@ -4722,7 +4721,7 @@ public class NotificationManagerService extends SystemService {
// Fix the notification as best we can.
try {
- fixNotification(notification, pkg, userId);
+ fixNotification(notification, pkg, tag, id, userId);
} catch (NameNotFoundException e) {
Slog.e(TAG, "Cannot create a context for sending app", e);
@@ -4827,8 +4826,8 @@ public class NotificationManagerService extends SystemService {
}
@VisibleForTesting
- protected void fixNotification(Notification notification, String pkg, int userId)
- throws NameNotFoundException {
+ protected void fixNotification(Notification notification, String pkg, String tag, int id,
+ int userId) throws NameNotFoundException {
final ApplicationInfo ai = mPackageManagerClient.getApplicationInfoAsUser(
pkg, PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
(userId == UserHandle.USER_ALL) ? USER_SYSTEM : userId);
@@ -4851,6 +4850,50 @@ public class NotificationManagerService extends SystemService {
": Use of fullScreenIntent requires the USE_FULL_SCREEN_INTENT permission");
}
}
+
+ // Remote views? Are they too big?
+ checkRemoteViews(pkg, tag, id, notification);
+ }
+
+ private void checkRemoteViews(String pkg, String tag, int id, Notification notification) {
+ if (removeRemoteView(pkg, tag, id, notification.contentView)) {
+ notification.contentView = null;
+ }
+ if (removeRemoteView(pkg, tag, id, notification.bigContentView)) {
+ notification.bigContentView = null;
+ }
+ if (removeRemoteView(pkg, tag, id, notification.headsUpContentView)) {
+ notification.headsUpContentView = null;
+ }
+ if (notification.publicVersion != null) {
+ if (removeRemoteView(pkg, tag, id, notification.publicVersion.contentView)) {
+ notification.publicVersion.contentView = null;
+ }
+ if (removeRemoteView(pkg, tag, id, notification.publicVersion.bigContentView)) {
+ notification.publicVersion.bigContentView = null;
+ }
+ if (removeRemoteView(pkg, tag, id, notification.publicVersion.headsUpContentView)) {
+ notification.publicVersion.headsUpContentView = null;
+ }
+ }
+ }
+
+ private boolean removeRemoteView(String pkg, String tag, int id, RemoteViews contentView) {
+ if (contentView == null) {
+ return false;
+ }
+ final int contentViewSize = contentView.estimateMemoryUsage();
+ if (contentViewSize > mWarnRemoteViewsSizeBytes
+ && contentViewSize < mStripRemoteViewsSizeBytes) {
+ Slog.w(TAG, "RemoteViews too large on tag: " + tag + " id: " + id
+ + " this might be stripped in a future release");
+ }
+ if (contentViewSize >= mStripRemoteViewsSizeBytes) {
+ mUsageStats.registerImageRemoved(pkg);
+ Slog.w(TAG, "Removed too large RemoteViews on tag: " + tag + " id: " + id);
+ return true;
+ }
+ return false;
}
/**
@@ -5079,23 +5122,25 @@ public class NotificationManagerService extends SystemService {
}
}
- // snoozed apps
- if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
- MetricsLogger.action(r.getLogMaker()
- .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
- .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
- if (DBG) {
- Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
+ synchronized (mNotificationLock) {
+ // snoozed apps
+ if (mSnoozeHelper.isSnoozed(userId, pkg, r.getKey())) {
+ MetricsLogger.action(r.getLogMaker()
+ .setType(MetricsProto.MetricsEvent.TYPE_UPDATE)
+ .setCategory(MetricsProto.MetricsEvent.NOTIFICATION_SNOOZED));
+ if (DBG) {
+ Slog.d(TAG, "Ignored enqueue for snoozed notification " + r.getKey());
+ }
+ mSnoozeHelper.update(userId, r);
+ handleSavePolicyFile();
+ return false;
}
- mSnoozeHelper.update(userId, r);
- handleSavePolicyFile();
- return false;
- }
- // blocked apps
- if (isBlocked(r, mUsageStats)) {
- return false;
+ // blocked apps
+ if (isBlocked(r, mUsageStats)) {
+ return false;
+ }
}
return true;
@@ -5375,11 +5420,18 @@ public class NotificationManagerService extends SystemService {
}
@GuardedBy("mNotificationLock")
- private boolean isPackageSuspendedLocked(NotificationRecord r) {
- final String pkg = r.sbn.getPackageName();
- final int callingUid = r.sbn.getUid();
+ boolean isPackagePausedOrSuspended(String pkg, int uid) {
+ boolean isPaused;
+
+ final PackageManagerInternal pmi = LocalServices.getService(
+ PackageManagerInternal.class);
+ int flags = pmi.getDistractingPackageRestrictions(
+ pkg, Binder.getCallingUserHandle().getIdentifier());
+ isPaused = ((flags & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0);
+
+ isPaused |= isPackageSuspendedForUser(pkg, uid);
- return isPackageSuspendedForUser(pkg, callingUid);
+ return isPaused;
}
protected class PostNotificationRunnable implements Runnable {
@@ -5412,7 +5464,8 @@ public class NotificationManagerService extends SystemService {
return;
}
- final boolean isPackageSuspended = isPackageSuspendedLocked(r);
+ final boolean isPackageSuspended =
+ isPackagePausedOrSuspended(r.sbn.getPackageName(), r.getUid());
r.setHidden(isPackageSuspended);
if (isPackageSuspended) {
mUsageStats.registerSuspendedByAdmin(r);
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 6748f80b4f77..a12607351775 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -34,11 +34,8 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
-import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.drawable.Icon;
import android.media.AudioAttributes;
import android.media.AudioSystem;
import android.metrics.LogMaker;
@@ -453,16 +450,11 @@ public final class NotificationRecord {
void dump(PrintWriter pw, String prefix, Context baseContext, boolean redact) {
final Notification notification = sbn.getNotification();
- final Icon icon = notification.getSmallIcon();
- String iconStr = String.valueOf(icon);
- if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) {
- iconStr += " / " + idDebugString(baseContext, icon.getResPackage(), icon.getResId());
- }
pw.println(prefix + this);
prefix = prefix + " ";
pw.println(prefix + "uid=" + sbn.getUid() + " userId=" + sbn.getUserId());
pw.println(prefix + "opPkg=" + sbn.getOpPkg());
- pw.println(prefix + "icon=" + iconStr);
+ pw.println(prefix + "icon=" + notification.getSmallIcon());
pw.println(prefix + "flags=0x" + Integer.toHexString(notification.flags));
pw.println(prefix + "pri=" + notification.priority);
pw.println(prefix + "key=" + sbn.getKey());
@@ -592,28 +584,6 @@ public final class NotificationRecord {
pw.println(prefix + "mAdjustments=" + mAdjustments);
}
-
- static String idDebugString(Context baseContext, String packageName, int id) {
- Context c;
-
- if (packageName != null) {
- try {
- c = baseContext.createPackageContext(packageName, 0);
- } catch (NameNotFoundException e) {
- c = baseContext;
- }
- } else {
- c = baseContext;
- }
-
- Resources r = c.getResources();
- try {
- return r.getResourceName(id);
- } catch (Resources.NotFoundException e) {
- return "<name unknown>";
- }
- }
-
@Override
public final String toString() {
return String.format(
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index dd393b8846f0..fe3d0eb3e469 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -41,7 +41,6 @@ import org.json.JSONException;
import org.json.JSONObject;
import java.io.PrintWriter;
-import java.lang.Math;
import java.util.ArrayDeque;
import java.util.Calendar;
import java.util.GregorianCalendar;
@@ -263,6 +262,17 @@ public class NotificationUsageStats {
}
}
+ /**
+ * Call this when RemoteViews object has been removed from a notification because the images
+ * it contains are too big (even after rescaling).
+ */
+ public synchronized void registerImageRemoved(String packageName) {
+ AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(packageName);
+ for (AggregatedStats stats : aggregatedStatsArray) {
+ stats.numImagesRemoved++;
+ }
+ }
+
// Locked by this.
private AggregatedStats[] getAggregatedStatsLocked(NotificationRecord record) {
return getAggregatedStatsLocked(record.sbn.getPackageName());
@@ -405,6 +415,7 @@ public class NotificationUsageStats {
public int numAlertViolations;
public int numQuotaViolations;
public long mLastAccessTime;
+ public int numImagesRemoved;
public AggregatedStats(Context context, String key) {
this.key = key;
@@ -529,6 +540,7 @@ public class NotificationUsageStats {
maybeCount("note_over_rate", (numRateViolations - previous.numRateViolations));
maybeCount("note_over_alert_rate", (numAlertViolations - previous.numAlertViolations));
maybeCount("note_over_quota", (numQuotaViolations - previous.numQuotaViolations));
+ maybeCount("note_images_removed", (numImagesRemoved - previous.numImagesRemoved));
noisyImportance.maybeCount(previous.noisyImportance);
quietImportance.maybeCount(previous.quietImportance);
finalImportance.maybeCount(previous.finalImportance);
@@ -562,6 +574,7 @@ public class NotificationUsageStats {
previous.numRateViolations = numRateViolations;
previous.numAlertViolations = numAlertViolations;
previous.numQuotaViolations = numQuotaViolations;
+ previous.numImagesRemoved = numImagesRemoved;
noisyImportance.update(previous.noisyImportance);
quietImportance.update(previous.quietImportance);
finalImportance.update(previous.finalImportance);
@@ -667,6 +680,8 @@ public class NotificationUsageStats {
output.append("numAlertViolations=").append(numAlertViolations).append("\n");
output.append(indentPlusTwo);
output.append("numQuotaViolations=").append(numQuotaViolations).append("\n");
+ output.append(indentPlusTwo);
+ output.append("numImagesRemoved=").append(numImagesRemoved).append("\n");
output.append(indentPlusTwo).append(noisyImportance.toString()).append("\n");
output.append(indentPlusTwo).append(quietImportance.toString()).append("\n");
output.append(indentPlusTwo).append(finalImportance.toString()).append("\n");
@@ -709,6 +724,7 @@ public class NotificationUsageStats {
maybePut(dump, "numQuotaLViolations", numQuotaViolations);
maybePut(dump, "notificationEnqueueRate", getEnqueueRate());
maybePut(dump, "numAlertViolations", numAlertViolations);
+ maybePut(dump, "numImagesRemoved", numImagesRemoved);
noisyImportance.maybePut(dump, previous.noisyImportance);
quietImportance.maybePut(dump, previous.quietImportance);
finalImportance.maybePut(dump, previous.finalImportance);
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 03224d1939b9..dd099b15a464 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -11,7 +11,7 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
- * limitations under the License.s
+ * limitations under the License.
*/
package com.android.server.pm;
@@ -29,12 +29,11 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.PackageParserException;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.ServiceManager.ServiceNotFoundException;
import android.sysprop.ApexProperties;
import android.util.Slog;
@@ -55,103 +54,33 @@ import java.util.stream.Collectors;
* ApexManager class handles communications with the apex service to perform operation and queries,
* as well as providing caching to avoid unnecessary calls to the service.
*/
-class ApexManager {
- static final String TAG = "ApexManager";
- private final IApexService mApexService;
- private final Context mContext;
- private final Object mLock = new Object();
- /**
- * A map from {@code APEX packageName} to the {@Link PackageInfo} generated from the {@code
- * AndroidManifest.xml}
- *
- * <p>Note that key of this map is {@code packageName} field of the corresponding {@code
- * AndroidManifest.xml}.
- */
- @GuardedBy("mLock")
- private List<PackageInfo> mAllPackagesCache;
-
- ApexManager(Context context) {
- mContext = context;
- if (!isApexSupported()) {
- mApexService = null;
- return;
- }
- try {
- mApexService = IApexService.Stub.asInterface(
- ServiceManager.getServiceOrThrow("apexservice"));
- } catch (ServiceNotFoundException e) {
- throw new IllegalStateException("Required service apexservice not available");
- }
- }
+abstract class ApexManager {
+
+ private static final String TAG = "ApexManager";
static final int MATCH_ACTIVE_PACKAGE = 1 << 0;
static final int MATCH_FACTORY_PACKAGE = 1 << 1;
- @IntDef(
- flag = true,
- prefix = { "MATCH_"},
- value = {MATCH_ACTIVE_PACKAGE, MATCH_FACTORY_PACKAGE})
- @Retention(RetentionPolicy.SOURCE)
- @interface PackageInfoFlags{}
-
- void systemReady() {
- if (!isApexSupported()) return;
- mContext.registerReceiver(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- onBootCompleted();
- mContext.unregisterReceiver(this);
- }
- }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
- }
- private void populateAllPackagesCacheIfNeeded() {
- synchronized (mLock) {
- if (mAllPackagesCache != null) {
- return;
- }
+ /**
+ * Returns an instance of either {@link ApexManagerImpl} or {@link ApexManagerNoOp} depending
+ * on whenever this device supports APEX, i.e. {@link ApexProperties#updatable()} evaluates to
+ * {@code true}.
+ */
+ static ApexManager create(Context systemContext) {
+ if (ApexProperties.updatable().orElse(false)) {
try {
- mAllPackagesCache = new ArrayList<>();
- HashSet<String> activePackagesSet = new HashSet<>();
- HashSet<String> factoryPackagesSet = new HashSet<>();
- final ApexInfo[] allPkgs = mApexService.getAllPackages();
- for (ApexInfo ai : allPkgs) {
- // If the device is using flattened APEX, don't report any APEX
- // packages since they won't be managed or updated by PackageManager.
- if ((new File(ai.modulePath)).isDirectory()) {
- break;
- }
- try {
- final PackageInfo pkg = PackageParser.generatePackageInfoFromApex(
- ai, PackageManager.GET_META_DATA
- | PackageManager.GET_SIGNING_CERTIFICATES);
- mAllPackagesCache.add(pkg);
- if (ai.isActive) {
- if (activePackagesSet.contains(pkg.packageName)) {
- throw new IllegalStateException(
- "Two active packages have the same name: "
- + pkg.packageName);
- }
- activePackagesSet.add(pkg.packageName);
- }
- if (ai.isFactory) {
- if (factoryPackagesSet.contains(pkg.packageName)) {
- throw new IllegalStateException(
- "Two factory packages have the same name: "
- + pkg.packageName);
- }
- factoryPackagesSet.add(pkg.packageName);
- }
- } catch (PackageParserException pe) {
- throw new IllegalStateException("Unable to parse: " + ai, pe);
- }
- }
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
- throw new RuntimeException(re);
+ return new ApexManagerImpl(systemContext, IApexService.Stub.asInterface(
+ ServiceManager.getServiceOrThrow("apexservice")));
+ } catch (ServiceManager.ServiceNotFoundException e) {
+ throw new IllegalStateException("Required service apexservice not available");
}
+ } else {
+ return new ApexManagerNoOp();
}
}
+ abstract void systemReady();
+
/**
* Retrieves information about an APEX package.
*
@@ -164,22 +93,8 @@ class ApexManager {
* @return a PackageInfo object with the information about the package, or null if the package
* is not found.
*/
- @Nullable PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) {
- if (!isApexSupported()) return null;
- populateAllPackagesCacheIfNeeded();
- boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0;
- boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0;
- for (PackageInfo packageInfo: mAllPackagesCache) {
- if (!packageInfo.packageName.equals(packageName)) {
- continue;
- }
- if ((!matchActive || isActive(packageInfo))
- && (!matchFactory || isFactory(packageInfo))) {
- return packageInfo;
- }
- }
- return null;
- }
+ @Nullable
+ abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags);
/**
* Retrieves information about all active APEX packages.
@@ -187,14 +102,7 @@ class ApexManager {
* @return a List of PackageInfo object, each one containing information about a different
* active package.
*/
- List<PackageInfo> getActivePackages() {
- if (!isApexSupported()) return Collections.emptyList();
- populateAllPackagesCacheIfNeeded();
- return mAllPackagesCache
- .stream()
- .filter(item -> isActive(item))
- .collect(Collectors.toList());
- }
+ abstract List<PackageInfo> getActivePackages();
/**
* Retrieves information about all active pre-installed APEX packages.
@@ -202,14 +110,7 @@ class ApexManager {
* @return a List of PackageInfo object, each one containing information about a different
* active pre-installed package.
*/
- List<PackageInfo> getFactoryPackages() {
- if (!isApexSupported()) return Collections.emptyList();
- populateAllPackagesCacheIfNeeded();
- return mAllPackagesCache
- .stream()
- .filter(item -> isFactory(item))
- .collect(Collectors.toList());
- }
+ abstract List<PackageInfo> getFactoryPackages();
/**
* Retrieves information about all inactive APEX packages.
@@ -217,14 +118,7 @@ class ApexManager {
* @return a List of PackageInfo object, each one containing information about a different
* inactive package.
*/
- List<PackageInfo> getInactivePackages() {
- if (!isApexSupported()) return Collections.emptyList();
- populateAllPackagesCacheIfNeeded();
- return mAllPackagesCache
- .stream()
- .filter(item -> !isActive(item))
- .collect(Collectors.toList());
- }
+ abstract List<PackageInfo> getInactivePackages();
/**
* Checks if {@code packageName} is an apex package.
@@ -232,16 +126,7 @@ class ApexManager {
* @param packageName package to check.
* @return {@code true} if {@code packageName} is an apex package.
*/
- boolean isApexPackage(String packageName) {
- if (!isApexSupported()) return false;
- populateAllPackagesCacheIfNeeded();
- for (PackageInfo packageInfo : mAllPackagesCache) {
- if (packageInfo.packageName.equals(packageName)) {
- return true;
- }
- }
- return false;
- }
+ abstract boolean isApexPackage(String packageName);
/**
* Retrieves information about an apexd staged session i.e. the internal state used by apexd to
@@ -250,19 +135,8 @@ class ApexManager {
* @param sessionId the identifier of the session.
* @return an ApexSessionInfo object, or null if the session is not known.
*/
- @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) {
- if (!isApexSupported()) return null;
- try {
- ApexSessionInfo apexSessionInfo = mApexService.getStagedSessionInfo(sessionId);
- if (apexSessionInfo.isUnknown) {
- return null;
- }
- return apexSessionInfo;
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to contact apexservice", re);
- throw new RuntimeException(re);
- }
- }
+ @Nullable
+ abstract ApexSessionInfo getStagedSessionInfo(int sessionId);
/**
* Submit a staged session to apex service. This causes the apex service to perform some initial
@@ -274,39 +148,19 @@ class ApexManager {
* @param childSessionIds if {@code sessionId} is a multi-package session, this should contain
* an array of identifiers of all the child sessions. Otherwise it should
* be an empty array.
- * @param apexInfoList this is an output parameter, which needs to be initialized by tha caller
- * and will be filled with a list of {@link ApexInfo} objects, each of which
- * contains metadata about one of the packages being submitted as part of
- * the session.
- * @return whether the submission of the session was successful.
+ * @throws PackageManagerException if call to apexd fails
*/
- boolean submitStagedSession(
- int sessionId, @NonNull int[] childSessionIds, @NonNull ApexInfoList apexInfoList) {
- if (!isApexSupported()) return false;
- try {
- return mApexService.submitStagedSession(sessionId, childSessionIds, apexInfoList);
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to contact apexservice", re);
- throw new RuntimeException(re);
- }
- }
+ abstract ApexInfoList submitStagedSession(int sessionId, @NonNull int[] childSessionIds)
+ throws PackageManagerException;
/**
* Mark a staged session previously submitted using {@code submitStagedSession} as ready to be
* applied at next reboot.
*
* @param sessionId the identifier of the {@link PackageInstallerSession} being marked as ready.
- * @return true upon success, false if the session is unknown.
+ * @throws PackageManagerException if call to apexd fails
*/
- boolean markStagedSessionReady(int sessionId) {
- if (!isApexSupported()) return false;
- try {
- return mApexService.markStagedSessionReady(sessionId);
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to contact apexservice", re);
- throw new RuntimeException(re);
- }
- }
+ abstract void markStagedSessionReady(int sessionId) throws PackageManagerException;
/**
* Marks a staged session as successful.
@@ -316,44 +170,21 @@ class ApexManager {
* @param sessionId the identifier of the {@link PackageInstallerSession} being marked as
* successful.
*/
- void markStagedSessionSuccessful(int sessionId) {
- if (!isApexSupported()) return;
- try {
- mApexService.markStagedSessionSuccessful(sessionId);
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to contact apexservice", re);
- throw new RuntimeException(re);
- } catch (Exception e) {
- // It is fine to just log an exception in this case. APEXd will be able to recover in
- // case markStagedSessionSuccessful fails.
- Slog.e(TAG, "Failed to mark session " + sessionId + " as successful", e);
- }
- }
+ abstract void markStagedSessionSuccessful(int sessionId);
/**
* Whether the current device supports the management of APEX packages.
*
* @return true if APEX packages can be managed on this device, false otherwise.
*/
- boolean isApexSupported() {
- return ApexProperties.updatable().orElse(false);
- }
+ abstract boolean isApexSupported();
/**
* Abandons the (only) active session previously submitted.
*
* @return {@code true} upon success, {@code false} if any remote exception occurs
*/
- boolean abortActiveSession() {
- if (!isApexSupported()) return false;
- try {
- mApexService.abortActiveSession();
- return true;
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to contact apexservice", re);
- return false;
- }
- }
+ abstract boolean abortActiveSession();
/**
* Uninstalls given {@code apexPackage}.
@@ -363,120 +194,419 @@ class ApexManager {
* @param apexPackagePath package to uninstall.
* @return {@code true} upon successful uninstall, {@code false} otherwise.
*/
- boolean uninstallApex(String apexPackagePath) {
- if (!isApexSupported()) return false;
- try {
- mApexService.unstagePackages(Collections.singletonList(apexPackagePath));
- return true;
- } catch (Exception e) {
- return false;
- }
- }
+ abstract boolean uninstallApex(String apexPackagePath);
/**
- * Whether an APEX package is active or not.
+ * Dumps various state information to the provided {@link PrintWriter} object.
*
- * @param packageInfo the package to check
- * @return {@code true} if this package is active, {@code false} otherwise.
+ * @param pw the {@link PrintWriter} object to send information to.
+ * @param packageName a {@link String} containing a package name, or {@code null}. If set, only
+ * information about that specific package will be dumped.
*/
- private static boolean isActive(PackageInfo packageInfo) {
- return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
- }
+ abstract void dump(PrintWriter pw, @Nullable String packageName);
- /**
- * Whether the APEX package is pre-installed or not.
- *
- * @param packageInfo the package to check
- * @return {@code true} if this package is pre-installed, {@code false} otherwise.
- */
- private static boolean isFactory(PackageInfo packageInfo) {
- return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
- }
+ @IntDef(
+ flag = true,
+ prefix = { "MATCH_"},
+ value = {MATCH_ACTIVE_PACKAGE, MATCH_FACTORY_PACKAGE})
+ @Retention(RetentionPolicy.SOURCE)
+ @interface PackageInfoFlags{}
/**
- * Dump information about the packages contained in a particular cache
- * @param packagesCache the cache to print information about.
- * @param packageName a {@link String} containing a package name, or {@code null}. If set, only
- * information about that specific package will be dumped.
- * @param ipw the {@link IndentingPrintWriter} object to send information to.
+ * An implementation of {@link ApexManager} that should be used in case device supports updating
+ * APEX packages.
*/
- void dumpFromPackagesCache(
- List<PackageInfo> packagesCache,
- @Nullable String packageName,
- IndentingPrintWriter ipw) {
- ipw.println();
- ipw.increaseIndent();
- for (PackageInfo pi : packagesCache) {
- if (packageName != null && !packageName.equals(pi.packageName)) {
- continue;
+ private static class ApexManagerImpl extends ApexManager {
+ private final IApexService mApexService;
+ private final Context mContext;
+ private final Object mLock = new Object();
+ /**
+ * A map from {@code APEX packageName} to the {@Link PackageInfo} generated from the {@code
+ * AndroidManifest.xml}
+ *
+ * <p>Note that key of this map is {@code packageName} field of the corresponding {@code
+ * AndroidManifest.xml}.
+ */
+ @GuardedBy("mLock")
+ private List<PackageInfo> mAllPackagesCache;
+
+ ApexManagerImpl(Context context, IApexService apexService) {
+ mContext = context;
+ mApexService = apexService;
+ }
+
+ /**
+ * Whether an APEX package is active or not.
+ *
+ * @param packageInfo the package to check
+ * @return {@code true} if this package is active, {@code false} otherwise.
+ */
+ private static boolean isActive(PackageInfo packageInfo) {
+ return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
+ }
+
+ /**
+ * Whether the APEX package is pre-installed or not.
+ *
+ * @param packageInfo the package to check
+ * @return {@code true} if this package is pre-installed, {@code false} otherwise.
+ */
+ private static boolean isFactory(PackageInfo packageInfo) {
+ return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ }
+
+ @Override
+ void systemReady() {
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ populateAllPackagesCacheIfNeeded();
+ mContext.unregisterReceiver(this);
+ }
+ }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+ }
+
+ private void populateAllPackagesCacheIfNeeded() {
+ synchronized (mLock) {
+ if (mAllPackagesCache != null) {
+ return;
+ }
+ try {
+ mAllPackagesCache = new ArrayList<>();
+ HashSet<String> activePackagesSet = new HashSet<>();
+ HashSet<String> factoryPackagesSet = new HashSet<>();
+ final ApexInfo[] allPkgs = mApexService.getAllPackages();
+ for (ApexInfo ai : allPkgs) {
+ // If the device is using flattened APEX, don't report any APEX
+ // packages since they won't be managed or updated by PackageManager.
+ if ((new File(ai.modulePath)).isDirectory()) {
+ break;
+ }
+ try {
+ final PackageInfo pkg = PackageParser.generatePackageInfoFromApex(
+ ai, PackageManager.GET_META_DATA
+ | PackageManager.GET_SIGNING_CERTIFICATES);
+ mAllPackagesCache.add(pkg);
+ if (ai.isActive) {
+ if (activePackagesSet.contains(pkg.packageName)) {
+ throw new IllegalStateException(
+ "Two active packages have the same name: "
+ + pkg.packageName);
+ }
+ activePackagesSet.add(pkg.packageName);
+ }
+ if (ai.isFactory) {
+ if (factoryPackagesSet.contains(pkg.packageName)) {
+ throw new IllegalStateException(
+ "Two factory packages have the same name: "
+ + pkg.packageName);
+ }
+ factoryPackagesSet.add(pkg.packageName);
+ }
+ } catch (PackageParser.PackageParserException pe) {
+ throw new IllegalStateException("Unable to parse: " + ai, pe);
+ }
+ }
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString());
+ throw new RuntimeException(re);
+ }
}
- ipw.println(pi.packageName);
- ipw.increaseIndent();
- ipw.println("Version: " + pi.versionCode);
- ipw.println("Path: " + pi.applicationInfo.sourceDir);
- ipw.println("IsActive: " + isActive(pi));
- ipw.println("IsFactory: " + isFactory(pi));
- ipw.decreaseIndent();
}
- ipw.decreaseIndent();
- ipw.println();
- }
- /**
- * Dumps various state information to the provided {@link PrintWriter} object.
- *
- * @param pw the {@link PrintWriter} object to send information to.
- * @param packageName a {@link String} containing a package name, or {@code null}. If set, only
- * information about that specific package will be dumped.
- */
- void dump(PrintWriter pw, @Nullable String packageName) {
- if (!isApexSupported()) return;
- final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
- try {
+ @Override
+ @Nullable PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) {
+ populateAllPackagesCacheIfNeeded();
+ boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0;
+ boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0;
+ for (PackageInfo packageInfo: mAllPackagesCache) {
+ if (!packageInfo.packageName.equals(packageName)) {
+ continue;
+ }
+ if ((!matchActive || isActive(packageInfo))
+ && (!matchFactory || isFactory(packageInfo))) {
+ return packageInfo;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ List<PackageInfo> getActivePackages() {
+ populateAllPackagesCacheIfNeeded();
+ return mAllPackagesCache
+ .stream()
+ .filter(item -> isActive(item))
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ List<PackageInfo> getFactoryPackages() {
+ populateAllPackagesCacheIfNeeded();
+ return mAllPackagesCache
+ .stream()
+ .filter(item -> isFactory(item))
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ List<PackageInfo> getInactivePackages() {
+ populateAllPackagesCacheIfNeeded();
+ return mAllPackagesCache
+ .stream()
+ .filter(item -> !isActive(item))
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ boolean isApexPackage(String packageName) {
+ if (!isApexSupported()) return false;
populateAllPackagesCacheIfNeeded();
+ for (PackageInfo packageInfo : mAllPackagesCache) {
+ if (packageInfo.packageName.equals(packageName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) {
+ try {
+ ApexSessionInfo apexSessionInfo = mApexService.getStagedSessionInfo(sessionId);
+ if (apexSessionInfo.isUnknown) {
+ return null;
+ }
+ return apexSessionInfo;
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Unable to contact apexservice", re);
+ throw new RuntimeException(re);
+ }
+ }
+
+ @Override
+ ApexInfoList submitStagedSession(int sessionId, @NonNull int[] childSessionIds)
+ throws PackageManagerException {
+ try {
+ final ApexInfoList apexInfoList = new ApexInfoList();
+ mApexService.submitStagedSession(sessionId, childSessionIds, apexInfoList);
+ return apexInfoList;
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Unable to contact apexservice", re);
+ throw new RuntimeException(re);
+ } catch (Exception e) {
+ throw new PackageManagerException(
+ PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+ "apexd verification failed : " + e.getMessage());
+ }
+ }
+
+ @Override
+ void markStagedSessionReady(int sessionId) throws PackageManagerException {
+ try {
+ mApexService.markStagedSessionReady(sessionId);
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Unable to contact apexservice", re);
+ throw new RuntimeException(re);
+ } catch (Exception e) {
+ throw new PackageManagerException(
+ PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+ "Failed to mark apexd session as ready : " + e.getMessage());
+ }
+ }
+
+ @Override
+ void markStagedSessionSuccessful(int sessionId) {
+ try {
+ mApexService.markStagedSessionSuccessful(sessionId);
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Unable to contact apexservice", re);
+ throw new RuntimeException(re);
+ } catch (Exception e) {
+ // It is fine to just log an exception in this case. APEXd will be able to recover
+ // in case markStagedSessionSuccessful fails.
+ Slog.e(TAG, "Failed to mark session " + sessionId + " as successful", e);
+ }
+ }
+
+ @Override
+ boolean isApexSupported() {
+ return true;
+ }
+
+ @Override
+ boolean abortActiveSession() {
+ try {
+ mApexService.abortActiveSession();
+ return true;
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Unable to contact apexservice", re);
+ return false;
+ }
+ }
+
+ @Override
+ boolean uninstallApex(String apexPackagePath) {
+ try {
+ mApexService.unstagePackages(Collections.singletonList(apexPackagePath));
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ /**
+ * Dump information about the packages contained in a particular cache
+ * @param packagesCache the cache to print information about.
+ * @param packageName a {@link String} containing a package name, or {@code null}. If set,
+ * only information about that specific package will be dumped.
+ * @param ipw the {@link IndentingPrintWriter} object to send information to.
+ */
+ void dumpFromPackagesCache(
+ List<PackageInfo> packagesCache,
+ @Nullable String packageName,
+ IndentingPrintWriter ipw) {
ipw.println();
- ipw.println("Active APEX packages:");
- dumpFromPackagesCache(getActivePackages(), packageName, ipw);
- ipw.println("Inactive APEX packages:");
- dumpFromPackagesCache(getInactivePackages(), packageName, ipw);
- ipw.println("Factory APEX packages:");
- dumpFromPackagesCache(getFactoryPackages(), packageName, ipw);
- ipw.increaseIndent();
- ipw.println("APEX session state:");
ipw.increaseIndent();
- final ApexSessionInfo[] sessions = mApexService.getSessions();
- for (ApexSessionInfo si : sessions) {
- ipw.println("Session ID: " + si.sessionId);
- ipw.increaseIndent();
- if (si.isUnknown) {
- ipw.println("State: UNKNOWN");
- } else if (si.isVerified) {
- ipw.println("State: VERIFIED");
- } else if (si.isStaged) {
- ipw.println("State: STAGED");
- } else if (si.isActivated) {
- ipw.println("State: ACTIVATED");
- } else if (si.isActivationFailed) {
- ipw.println("State: ACTIVATION FAILED");
- } else if (si.isSuccess) {
- ipw.println("State: SUCCESS");
- } else if (si.isRollbackInProgress) {
- ipw.println("State: ROLLBACK IN PROGRESS");
- } else if (si.isRolledBack) {
- ipw.println("State: ROLLED BACK");
- } else if (si.isRollbackFailed) {
- ipw.println("State: ROLLBACK FAILED");
+ for (PackageInfo pi : packagesCache) {
+ if (packageName != null && !packageName.equals(pi.packageName)) {
+ continue;
}
+ ipw.println(pi.packageName);
+ ipw.increaseIndent();
+ ipw.println("Version: " + pi.versionCode);
+ ipw.println("Path: " + pi.applicationInfo.sourceDir);
+ ipw.println("IsActive: " + isActive(pi));
+ ipw.println("IsFactory: " + isFactory(pi));
ipw.decreaseIndent();
}
ipw.decreaseIndent();
- } catch (RemoteException e) {
- ipw.println("Couldn't communicate with apexd.");
+ ipw.println();
+ }
+
+ @Override
+ void dump(PrintWriter pw, @Nullable String packageName) {
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
+ try {
+ populateAllPackagesCacheIfNeeded();
+ ipw.println();
+ ipw.println("Active APEX packages:");
+ dumpFromPackagesCache(getActivePackages(), packageName, ipw);
+ ipw.println("Inactive APEX packages:");
+ dumpFromPackagesCache(getInactivePackages(), packageName, ipw);
+ ipw.println("Factory APEX packages:");
+ dumpFromPackagesCache(getFactoryPackages(), packageName, ipw);
+ ipw.increaseIndent();
+ ipw.println("APEX session state:");
+ ipw.increaseIndent();
+ final ApexSessionInfo[] sessions = mApexService.getSessions();
+ for (ApexSessionInfo si : sessions) {
+ ipw.println("Session ID: " + si.sessionId);
+ ipw.increaseIndent();
+ if (si.isUnknown) {
+ ipw.println("State: UNKNOWN");
+ } else if (si.isVerified) {
+ ipw.println("State: VERIFIED");
+ } else if (si.isStaged) {
+ ipw.println("State: STAGED");
+ } else if (si.isActivated) {
+ ipw.println("State: ACTIVATED");
+ } else if (si.isActivationFailed) {
+ ipw.println("State: ACTIVATION FAILED");
+ } else if (si.isSuccess) {
+ ipw.println("State: SUCCESS");
+ } else if (si.isRollbackInProgress) {
+ ipw.println("State: ROLLBACK IN PROGRESS");
+ } else if (si.isRolledBack) {
+ ipw.println("State: ROLLED BACK");
+ } else if (si.isRollbackFailed) {
+ ipw.println("State: ROLLBACK FAILED");
+ }
+ ipw.decreaseIndent();
+ }
+ ipw.decreaseIndent();
+ } catch (RemoteException e) {
+ ipw.println("Couldn't communicate with apexd.");
+ }
}
}
- public void onBootCompleted() {
- if (!isApexSupported()) return;
- populateAllPackagesCacheIfNeeded();
+ /**
+ * An implementation of {@link ApexManager} that should be used in case device does not support
+ * updating APEX packages.
+ */
+ private static final class ApexManagerNoOp extends ApexManager {
+
+ @Override
+ void systemReady() {
+ // No-op
+ }
+
+ @Override
+ PackageInfo getPackageInfo(String packageName, int flags) {
+ return null;
+ }
+
+ @Override
+ List<PackageInfo> getActivePackages() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ List<PackageInfo> getFactoryPackages() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ List<PackageInfo> getInactivePackages() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ boolean isApexPackage(String packageName) {
+ return false;
+ }
+
+ @Override
+ ApexSessionInfo getStagedSessionInfo(int sessionId) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ ApexInfoList submitStagedSession(int sessionId, int[] childSessionIds)
+ throws PackageManagerException {
+ throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
+ "Device doesn't support updating APEX");
+ }
+
+ @Override
+ void markStagedSessionReady(int sessionId) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ void markStagedSessionSuccessful(int sessionId) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ boolean isApexSupported() {
+ return false;
+ }
+
+ @Override
+ boolean abortActiveSession() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ boolean uninstallApex(String apexPackagePath) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ void dump(PrintWriter pw, String packageName) {
+ // No-op
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index ad9ac1232437..2b33aced7151 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -254,9 +254,16 @@ public class BackgroundDexOptService extends JobService {
@Override
public void run() {
int result = idleOptimization(pm, pkgs, BackgroundDexOptService.this);
- if (result != OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
+ if (result == OPTIMIZE_PROCESSED) {
+ Log.i(TAG, "Idle optimizations completed.");
+ } else if (result == OPTIMIZE_ABORT_NO_SPACE_LEFT) {
Log.w(TAG, "Idle optimizations aborted because of space constraints.");
- // If we didn't abort we ran to completion (or stopped because of space).
+ } else if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
+ Log.w(TAG, "Idle optimizations aborted by job scheduler.");
+ } else {
+ Log.w(TAG, "Idle optimizations ended with unexpected code: " + result);
+ }
+ if (result != OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
// Abandon our timeslice and do not reschedule.
jobFinished(jobParams, /* reschedule */ false);
}
@@ -339,6 +346,7 @@ public class BackgroundDexOptService extends JobService {
long lowStorageThreshold, boolean isForPrimaryDex) {
ArraySet<String> updatedPackages = new ArraySet<>();
Set<String> unusedPackages = pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis);
+ boolean hadSomeLowSpaceFailure = false;
Log.d(TAG, "Unsused Packages " + String.join(",", unusedPackages));
// Only downgrade apps when space is low on device.
// Threshold is selected above the lowStorageThreshold so that we can pro-actively clean
@@ -359,6 +367,7 @@ public class BackgroundDexOptService extends JobService {
} else {
if (abort_code == OPTIMIZE_ABORT_NO_SPACE_LEFT) {
// can't dexopt because of low space.
+ hadSomeLowSpaceFailure = true;
continue;
}
dex_opt_performed = optimizePackage(pm, pkg, isForPrimaryDex);
@@ -369,7 +378,7 @@ public class BackgroundDexOptService extends JobService {
}
notifyPinService(updatedPackages);
- return OPTIMIZE_PROCESSED;
+ return hadSomeLowSpaceFailure ? OPTIMIZE_ABORT_NO_SPACE_LEFT : OPTIMIZE_PROCESSED;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index deaca8476a45..5ab8ec3b04ab 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1768,11 +1768,12 @@ public class PackageManagerService extends IPackageManager.Stub
private PermissionCallback mPermissionCallback = new PermissionCallback() {
@Override
- public void onGidsChanged(int appId, int userId) {
+ public void onGidsChanged(int appId, @UserIdInt int userId) {
mHandler.post(() -> killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED));
}
+
@Override
- public void onPermissionGranted(int uid, int userId) {
+ public void onPermissionGranted(int uid, @UserIdInt int userId) {
mOnPermissionChangeListeners.onPermissionsChanged(uid);
// Not critical; if this is lost, the application has to request again.
@@ -1780,14 +1781,16 @@ public class PackageManagerService extends IPackageManager.Stub
mSettings.writeRuntimePermissionsForUserLPr(userId, false);
}
}
+
@Override
public void onInstallPermissionGranted() {
synchronized (mPackages) {
scheduleWriteSettingsLocked();
}
}
+
@Override
- public void onPermissionRevoked(int uid, int userId) {
+ public void onPermissionRevoked(int uid, @UserIdInt int userId) {
mOnPermissionChangeListeners.onPermissionsChanged(uid);
synchronized (mPackages) {
@@ -1798,26 +1801,43 @@ public class PackageManagerService extends IPackageManager.Stub
final int appId = UserHandle.getAppId(uid);
killUid(appId, userId, KILL_APP_REASON_PERMISSIONS_REVOKED);
}
+
@Override
public void onInstallPermissionRevoked() {
synchronized (mPackages) {
scheduleWriteSettingsLocked();
}
}
+
@Override
- public void onPermissionUpdated(int[] updatedUserIds, boolean sync) {
+ public void onPermissionUpdated(@UserIdInt int[] updatedUserIds, boolean sync) {
synchronized (mPackages) {
for (int userId : updatedUserIds) {
mSettings.writeRuntimePermissionsForUserLPr(userId, sync);
}
}
}
+
+ @Override
+ public void onPermissionUpdatedNotifyListener(@UserIdInt int[] updatedUserIds, boolean sync,
+ int uid) {
+ onPermissionUpdated(updatedUserIds, sync);
+ mOnPermissionChangeListeners.onPermissionsChanged(uid);
+ }
+
@Override
public void onInstallPermissionUpdated() {
synchronized (mPackages) {
scheduleWriteSettingsLocked();
}
}
+
+ @Override
+ public void onInstallPermissionUpdatedNotifyListener(int uid) {
+ onInstallPermissionUpdated();
+ mOnPermissionChangeListeners.onPermissionsChanged(uid);
+ }
+
@Override
public void onPermissionRemoved() {
synchronized (mPackages) {
@@ -2489,7 +2509,7 @@ public class PackageManagerService extends IPackageManager.Stub
mProtectedPackages = new ProtectedPackages(mContext);
- mApexManager = new ApexManager(context);
+ mApexManager = ApexManager.create(context);
// CHECKSTYLE:OFF IndentationCheck
synchronized (mInstallLock) {
// writer
@@ -4630,30 +4650,15 @@ public class PackageManagerService extends IPackageManager.Stub
return null;
}
- @Override
- public PermissionInfo getPermissionInfo(String name, String packageName, int flags) {
- return mPermissionManager.getPermissionInfo(name, packageName, flags, getCallingUid());
- }
-
- @Override
- public @Nullable ParceledListSlice<PermissionInfo> queryPermissionsByGroup(String groupName,
- int flags) {
- final List<PermissionInfo> permissionList =
- mPermissionManager.getPermissionInfoByGroup(groupName, flags, getCallingUid());
- return (permissionList == null) ? null : new ParceledListSlice<>(permissionList);
- }
-
+ // NOTE: Can't remove due to unsupported app usage
@Override
public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags) {
- return mPermissionManager.getPermissionGroupInfo(groupName, flags, getCallingUid());
- }
-
- @Override
- public @NonNull ParceledListSlice<PermissionGroupInfo> getAllPermissionGroups(int flags) {
- final List<PermissionGroupInfo> permissionList =
- mPermissionManager.getAllPermissionGroups(flags, getCallingUid());
- return (permissionList == null)
- ? ParceledListSlice.emptyList() : new ParceledListSlice<>(permissionList);
+ try {
+ // Because this is accessed via the package manager service AIDL,
+ // go through the permission manager service AIDL
+ return mPermissionManagerService.getPermissionGroupInfo(groupName, flags);
+ } catch (RemoteException ignore) { }
+ return null;
}
@GuardedBy("mPackages")
@@ -5710,37 +5715,36 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- private boolean addDynamicPermission(PermissionInfo info, final boolean async) {
- return mPermissionManager.addDynamicPermission(
- info, async, getCallingUid(), new PermissionCallback() {
- @Override
- public void onPermissionChanged() {
- if (!async) {
- mSettings.writeLPr();
- } else {
- scheduleWriteSettingsLocked();
- }
- }
- });
- }
-
+ // NOTE: Can't remove due to unsupported app usage
@Override
public boolean addPermission(PermissionInfo info) {
- synchronized (mPackages) {
- return addDynamicPermission(info, false);
- }
+ try {
+ // Because this is accessed via the package manager service AIDL,
+ // go through the permission manager service AIDL
+ return mPermissionManagerService.addPermission(info, false);
+ } catch (RemoteException ignore) { }
+ return false;
}
+ // NOTE: Can't remove due to unsupported app usage
@Override
public boolean addPermissionAsync(PermissionInfo info) {
- synchronized (mPackages) {
- return addDynamicPermission(info, true);
- }
+ try {
+ // Because this is accessed via the package manager service AIDL,
+ // go through the permission manager service AIDL
+ return mPermissionManagerService.addPermission(info, true);
+ } catch (RemoteException ignore) { }
+ return false;
}
+ // NOTE: Can't remove due to unsupported app usage
@Override
public void removePermission(String permName) {
- mPermissionManager.removeDynamicPermission(permName, getCallingUid(), mPermissionCallback);
+ try {
+ // Because this is accessed via the package manager service AIDL,
+ // go through the permission manager service AIDL
+ mPermissionManagerService.removePermission(permName);
+ } catch (RemoteException ignore) { }
}
@Override
@@ -6571,11 +6575,12 @@ public class PackageManagerService extends IPackageManager.Stub
return false;
}
+ // NOTE: Can't remove due to unsupported app usage
@Override
public String[] getAppOpPermissionPackages(String permName) {
try {
- // NOTE: Because this is defined in the package manager service AIDL, we want
- // ensure we also go through the permission manager service AIDL
+ // Because this is accessed via the package manager service AIDL,
+ // go through the permission manager service AIDL
return mPermissionManagerService.getAppOpPermissionPackages(permName);
} catch (RemoteException ignore) { }
return null;
@@ -21758,7 +21763,7 @@ public class PackageManagerService extends IPackageManager.Stub
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
ResultReceiver resultReceiver) {
- (new PackageManagerShellCommand(this)).exec(
+ (new PackageManagerShellCommand(this, mPermissionManagerService)).exec(
this, in, out, err, args, callback, resultReceiver);
}
@@ -25020,6 +25025,17 @@ public class PackageManagerService extends IPackageManager.Stub
Slog.wtf(TAG, e);
}
}
+
+ @Override
+ public void writeSettings(boolean async) {
+ synchronized (mPackages) {
+ if (async) {
+ scheduleWriteSettingsLocked();
+ } else {
+ mSettings.writeLPr();
+ }
+ }
+ }
}
@GuardedBy("mPackages")
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 5b80556cee92..a25c68f8afe9 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -87,6 +87,7 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
+import android.permission.IPermissionManager;
import android.system.ErrnoException;
import android.system.Os;
import android.text.TextUtils;
@@ -132,6 +133,7 @@ class PackageManagerShellCommand extends ShellCommand {
private static final int DEFAULT_WAIT_MS = 60 * 1000;
final IPackageManager mInterface;
+ final IPermissionManager mPermissionManager;
final private WeakHashMap<String, Resources> mResourceCache =
new WeakHashMap<String, Resources>();
int mTargetUser;
@@ -139,8 +141,10 @@ class PackageManagerShellCommand extends ShellCommand {
boolean mComponents;
int mQueryFlags;
- PackageManagerShellCommand(PackageManagerService service) {
+ PackageManagerShellCommand(
+ PackageManagerService service, IPermissionManager permissionManager) {
mInterface = service;
+ mPermissionManager = permissionManager;
}
@Override
@@ -786,7 +790,8 @@ class PackageManagerShellCommand extends ShellCommand {
private int runListPermissionGroups() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
- final List<PermissionGroupInfo> pgs = mInterface.getAllPermissionGroups(0).getList();
+ final List<PermissionGroupInfo> pgs =
+ mPermissionManager.getAllPermissionGroups(0).getList();
final int count = pgs.size();
for (int p = 0; p < count ; p++) {
@@ -833,7 +838,7 @@ class PackageManagerShellCommand extends ShellCommand {
final ArrayList<String> groupList = new ArrayList<String>();
if (groups) {
final List<PermissionGroupInfo> infos =
- mInterface.getAllPermissionGroups(0 /*flags*/).getList();
+ mPermissionManager.getAllPermissionGroups(0 /*flags*/).getList();
final int count = infos.size();
for (int i = 0; i < count; i++) {
groupList.add(infos.get(i).name);
@@ -2933,8 +2938,8 @@ class PackageManagerShellCommand extends ShellCommand {
}
prefix = " ";
}
- List<PermissionInfo> ps =
- mInterface.queryPermissionsByGroup(groupList.get(i), 0 /*flags*/).getList();
+ List<PermissionInfo> ps = mPermissionManager
+ .queryPermissionsByGroup(groupList.get(i), 0 /*flags*/).getList();
final int count = ps.size();
boolean first = true;
for (int p = 0 ; p < count ; p++) {
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index f9a019703f4d..42b65c357959 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -155,13 +155,10 @@ public class StagingManager {
}
}
}
- final ApexInfoList apexInfoList = new ApexInfoList();
- boolean submittedToApexd = mApexManager.submitStagedSession(session.sessionId,
- childSessionsIds.toArray(), apexInfoList);
- if (!submittedToApexd) {
- throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
- "APEX staging failed, check logcat messages from apexd for more details.");
- }
+ // submitStagedSession will throw a PackageManagerException if apexd verification fails,
+ // which will be propagated to populate stagedSessionErrorMessage of this session.
+ final ApexInfoList apexInfoList = mApexManager.submitStagedSession(session.sessionId,
+ childSessionsIds.toArray());
final List<PackageInfo> result = new ArrayList<>();
for (ApexInfo newPackage : apexInfoList.apexInfos) {
final PackageInfo pkg;
@@ -281,10 +278,14 @@ public class StagingManager {
// session as ready), then if a device gets rebooted right after the call to apexd, only
// apex part of the train will be applied, leaving device in an inconsistent state.
session.setStagedSessionReady();
- if (hasApex && !mApexManager.markStagedSessionReady(session.sessionId)) {
- session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
- "APEX staging failed, check logcat messages from apexd for more "
- + "details.");
+ if (!hasApex) {
+ // Session doesn't contain apex, nothing to do.
+ return;
+ }
+ try {
+ mApexManager.markStagedSessionReady(session.sessionId);
+ } catch (PackageManagerException e) {
+ session.setStagedSessionFailed(e.error, e.getMessage());
}
}
diff --git a/services/core/java/com/android/server/pm/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index 15dc6ae36656..e375fa44cb3f 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -8,6 +8,14 @@
},
{
"name": "CtsCompilationTestCases"
+ },
+ {
+ "name": "CtsPermissionTestCases",
+ "options": [
+ {
+ "include-filter": "android.permission.cts.PermissionUpdateListenerTest"
+ }
+ ]
}
],
"imports": [
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 8a3b3e3f627c..f4ba4492dcbb 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -90,7 +90,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsService;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.os.BackgroundThread;
-import com.android.internal.os.RoSystemProperties;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
@@ -2217,10 +2216,11 @@ public class UserManagerService extends IUserManager.Stub {
@GuardedBy({"mPackagesLock", "mRestrictionsLock"})
private void fallbackToSingleUserLP() {
- int flags = UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_ADMIN;
- // In headless system user mode, the primary flag is assigned to the first human user.
- if (!RoSystemProperties.MULTIUSER_HEADLESS_SYSTEM_USER) {
- flags |= UserInfo.FLAG_PRIMARY;
+ int flags = UserInfo.FLAG_INITIALIZED;
+ // In split system user mode, the admin and primary flags are assigned to the first human
+ // user.
+ if (!UserManager.isSplitSystemUser()) {
+ flags |= UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY;
}
// Create the system user
UserInfo system = new UserInfo(UserHandle.USER_SYSTEM, null, null, flags);
@@ -2734,9 +2734,9 @@ public class UserManagerService extends IUserManager.Stub {
return null;
}
}
- // In headless system user mode, we assign the first human user the primary flag.
+ // In split system user mode, we assign the first human user the primary flag.
// And if there is no device owner, we also assign the admin flag to primary user.
- if (RoSystemProperties.MULTIUSER_HEADLESS_SYSTEM_USER
+ if (UserManager.isSplitSystemUser()
&& !isGuest && !isManagedProfile && getPrimaryUser() == null) {
flags |= UserInfo.FLAG_PRIMARY;
synchronized (mUsersLock) {
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 4035d0d11a66..9b00dcaee1d7 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -51,10 +51,13 @@ import android.annotation.UserIdInt;
import android.app.ApplicationPackageManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.PermissionGroupInfoFlags;
+import android.content.pm.PackageManager.PermissionInfoFlags;
import android.content.pm.PackageManager.PermissionWhitelistFlags;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.Package;
+import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.metrics.LogMaker;
@@ -319,6 +322,140 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
+ @Override
+ @NonNull
+ public ParceledListSlice<PermissionGroupInfo> getAllPermissionGroups(
+ @PermissionGroupInfoFlags int flags) {
+ final int callingUid = getCallingUid();
+ if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
+ return ParceledListSlice.emptyList();
+ }
+ synchronized (mLock) {
+ final int n = mSettings.mPermissionGroups.size();
+ final ArrayList<PermissionGroupInfo> out =
+ new ArrayList<PermissionGroupInfo>(n);
+ for (PackageParser.PermissionGroup pg : mSettings.mPermissionGroups.values()) {
+ out.add(PackageParser.generatePermissionGroupInfo(pg, flags));
+ }
+ return new ParceledListSlice<>(out);
+ }
+ }
+
+
+ @Override
+ @Nullable
+ public PermissionGroupInfo getPermissionGroupInfo(String groupName,
+ @PermissionGroupInfoFlags int flags) {
+ final int callingUid = getCallingUid();
+ if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
+ return null;
+ }
+ synchronized (mLock) {
+ return PackageParser.generatePermissionGroupInfo(
+ mSettings.mPermissionGroups.get(groupName), flags);
+ }
+ }
+
+
+ @Override
+ @Nullable
+ public PermissionInfo getPermissionInfo(String permName, String packageName,
+ @PermissionInfoFlags int flags) {
+ final int callingUid = getCallingUid();
+ if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
+ return null;
+ }
+ synchronized (mLock) {
+ final BasePermission bp = mSettings.getPermissionLocked(permName);
+ if (bp == null) {
+ return null;
+ }
+ final int adjustedProtectionLevel = adjustPermissionProtectionFlagsLocked(
+ bp.getProtectionLevel(), packageName, callingUid);
+ return bp.generatePermissionInfo(adjustedProtectionLevel, flags);
+ }
+ }
+
+ @Override
+ @Nullable
+ public ParceledListSlice<PermissionInfo> queryPermissionsByGroup(String groupName,
+ @PermissionInfoFlags int flags) {
+ final int callingUid = getCallingUid();
+ if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
+ return null;
+ }
+ synchronized (mLock) {
+ if (groupName != null && !mSettings.mPermissionGroups.containsKey(groupName)) {
+ return null;
+ }
+ final ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10);
+ for (BasePermission bp : mSettings.mPermissions.values()) {
+ final PermissionInfo pi = bp.generatePermissionInfo(groupName, flags);
+ if (pi != null) {
+ out.add(pi);
+ }
+ }
+ return new ParceledListSlice<>(out);
+ }
+ }
+
+ @Override
+ public boolean addPermission(PermissionInfo info, boolean async) {
+ final int callingUid = getCallingUid();
+ if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
+ throw new SecurityException("Instant apps can't add permissions");
+ }
+ if (info.labelRes == 0 && info.nonLocalizedLabel == null) {
+ throw new SecurityException("Label must be specified in permission");
+ }
+ final BasePermission tree = mSettings.enforcePermissionTree(info.name, callingUid);
+ final boolean added;
+ final boolean changed;
+ synchronized (mLock) {
+ BasePermission bp = mSettings.getPermissionLocked(info.name);
+ added = bp == null;
+ int fixedLevel = PermissionInfo.fixProtectionLevel(info.protectionLevel);
+ if (added) {
+ enforcePermissionCapLocked(info, tree);
+ bp = new BasePermission(info.name, tree.getSourcePackageName(),
+ BasePermission.TYPE_DYNAMIC);
+ } else if (!bp.isDynamic()) {
+ throw new SecurityException("Not allowed to modify non-dynamic permission "
+ + info.name);
+ }
+ changed = bp.addToTree(fixedLevel, info, tree);
+ if (added) {
+ mSettings.putPermissionLocked(info.name, bp);
+ }
+ }
+ if (changed) {
+ mPackageManagerInt.writeSettings(async);
+ }
+ return added;
+ }
+
+ @Override
+ public void removePermission(String permName) {
+ final int callingUid = getCallingUid();
+ if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
+ throw new SecurityException("Instant applications don't have access to this method");
+ }
+ final BasePermission tree = mSettings.enforcePermissionTree(permName, callingUid);
+ synchronized (mLock) {
+ final BasePermission bp = mSettings.getPermissionLocked(permName);
+ if (bp == null) {
+ return;
+ }
+ if (bp.isDynamic()) {
+ // TODO: switch this back to SecurityException
+ Slog.wtf(TAG, "Not allowed to modify non-dynamic permission "
+ + permName);
+ }
+ mSettings.removePermissionLocked(permName);
+ mPackageManagerInt.writeSettings(false);
+ }
+ }
+
private int checkPermission(String permName, String pkgName, int callingUid, int userId) {
if (!mUserManagerInt.exists(userId)) {
return PackageManager.PERMISSION_DENIED;
@@ -517,69 +654,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
&& permissionsState.hasPermission(FULLER_PERMISSION_MAP.get(permName), userId);
}
- private PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags,
- int callingUid) {
- if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
- return null;
- }
- synchronized (mLock) {
- return PackageParser.generatePermissionGroupInfo(
- mSettings.mPermissionGroups.get(groupName), flags);
- }
- }
-
- private List<PermissionGroupInfo> getAllPermissionGroups(int flags, int callingUid) {
- if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
- return null;
- }
- synchronized (mLock) {
- final int N = mSettings.mPermissionGroups.size();
- final ArrayList<PermissionGroupInfo> out
- = new ArrayList<PermissionGroupInfo>(N);
- for (PackageParser.PermissionGroup pg : mSettings.mPermissionGroups.values()) {
- out.add(PackageParser.generatePermissionGroupInfo(pg, flags));
- }
- return out;
- }
- }
-
- private PermissionInfo getPermissionInfo(String permName, String packageName, int flags,
- int callingUid) {
- if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
- return null;
- }
- // reader
- synchronized (mLock) {
- final BasePermission bp = mSettings.getPermissionLocked(permName);
- if (bp == null) {
- return null;
- }
- final int adjustedProtectionLevel = adjustPermissionProtectionFlagsLocked(
- bp.getProtectionLevel(), packageName, callingUid);
- return bp.generatePermissionInfo(adjustedProtectionLevel, flags);
- }
- }
-
- private List<PermissionInfo> getPermissionInfoByGroup(
- String groupName, int flags, int callingUid) {
- if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
- return null;
- }
- synchronized (mLock) {
- if (groupName != null && !mSettings.mPermissionGroups.containsKey(groupName)) {
- return null;
- }
- final ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10);
- for (BasePermission bp : mSettings.mPermissions.values()) {
- final PermissionInfo pi = bp.generatePermissionInfo(groupName, flags);
- if (pi != null) {
- out.add(pi);
- }
- }
- return out;
- }
- }
-
private int adjustPermissionProtectionFlagsLocked(
int protectionLevel, String packageName, int uid) {
// Signature permission flags area always reported
@@ -825,63 +899,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
}
}
- private boolean addDynamicPermission(
- PermissionInfo info, int callingUid, PermissionCallback callback) {
- if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
- throw new SecurityException("Instant apps can't add permissions");
- }
- if (info.labelRes == 0 && info.nonLocalizedLabel == null) {
- throw new SecurityException("Label must be specified in permission");
- }
- final BasePermission tree = mSettings.enforcePermissionTree(info.name, callingUid);
- final boolean added;
- final boolean changed;
- synchronized (mLock) {
- BasePermission bp = mSettings.getPermissionLocked(info.name);
- added = bp == null;
- int fixedLevel = PermissionInfo.fixProtectionLevel(info.protectionLevel);
- if (added) {
- enforcePermissionCapLocked(info, tree);
- bp = new BasePermission(info.name, tree.getSourcePackageName(),
- BasePermission.TYPE_DYNAMIC);
- } else if (!bp.isDynamic()) {
- throw new SecurityException("Not allowed to modify non-dynamic permission "
- + info.name);
- }
- changed = bp.addToTree(fixedLevel, info, tree);
- if (added) {
- mSettings.putPermissionLocked(info.name, bp);
- }
- }
- if (changed && callback != null) {
- callback.onPermissionChanged();
- }
- return added;
- }
-
- private void removeDynamicPermission(
- String permName, int callingUid, PermissionCallback callback) {
- if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
- throw new SecurityException("Instant applications don't have access to this method");
- }
- final BasePermission tree = mSettings.enforcePermissionTree(permName, callingUid);
- synchronized (mLock) {
- final BasePermission bp = mSettings.getPermissionLocked(permName);
- if (bp == null) {
- return;
- }
- if (bp.isDynamic()) {
- // TODO: switch this back to SecurityException
- Slog.wtf(TAG, "Not allowed to modify non-dynamic permission "
- + permName);
- }
- mSettings.removePermissionLocked(permName);
- if (callback != null) {
- callback.onPermissionRemoved();
- }
- }
- }
-
/**
* Restore the permission state for a package.
*
@@ -2317,6 +2334,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return;
}
+ // Permission is already revoked, no need to do anything.
+ if (!permissionsState.hasRuntimePermission(permName, userId)) {
+ return;
+ }
+
if (permissionsState.revokeRuntimePermission(bp, userId) ==
PERMISSION_OPERATION_FAILURE) {
return;
@@ -2935,10 +2957,11 @@ public class PermissionManagerService extends IPermissionManager.Stub {
// Install and runtime permissions are stored in different places,
// so figure out what permission changed and persist the change.
if (permissionsState.getInstallPermissionState(permName) != null) {
- callback.onInstallPermissionUpdated();
+ callback.onInstallPermissionUpdatedNotifyListener(pkg.applicationInfo.uid);
} else if (permissionsState.getRuntimePermissionState(permName, userId) != null
|| hadState) {
- callback.onPermissionUpdated(new int[] { userId }, false);
+ callback.onPermissionUpdatedNotifyListener(new int[] { userId }, false,
+ pkg.applicationInfo.uid);
}
}
}
@@ -2972,6 +2995,8 @@ public class PermissionManagerService extends IPermissionManager.Stub {
PermissionsState permissionsState = ps.getPermissionsState();
changed |= permissionsState.updatePermissionFlagsForAllPermissions(
userId, flagMask, flagValues);
+ callback.onPermissionUpdatedNotifyListener(new int[] { userId }, false,
+ pkg.applicationInfo.uid);
}
return changed;
}
@@ -3146,16 +3171,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
PermissionManagerService.this.removeAllPermissions(pkg, chatty);
}
@Override
- public boolean addDynamicPermission(PermissionInfo info, boolean async, int callingUid,
- PermissionCallback callback) {
- return PermissionManagerService.this.addDynamicPermission(info, callingUid, callback);
- }
- @Override
- public void removeDynamicPermission(String permName, int callingUid,
- PermissionCallback callback) {
- PermissionManagerService.this.removeDynamicPermission(permName, callingUid, callback);
- }
- @Override
public void grantRuntimePermission(String permName, String packageName,
boolean overridePolicy, int callingUid, int userId,
PermissionCallback callback) {
@@ -3262,27 +3277,6 @@ public class PermissionManagerService extends IPermissionManager.Stub {
return PermissionManagerService.this.checkUidPermission(permName, pkg, uid, callingUid);
}
@Override
- public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags,
- int callingUid) {
- return PermissionManagerService.this.getPermissionGroupInfo(
- groupName, flags, callingUid);
- }
- @Override
- public List<PermissionGroupInfo> getAllPermissionGroups(int flags, int callingUid) {
- return PermissionManagerService.this.getAllPermissionGroups(flags, callingUid);
- }
- @Override
- public PermissionInfo getPermissionInfo(String permName, String packageName, int flags,
- int callingUid) {
- return PermissionManagerService.this.getPermissionInfo(
- permName, packageName, flags, callingUid);
- }
- @Override
- public List<PermissionInfo> getPermissionInfoByGroup(String group, int flags,
- int callingUid) {
- return PermissionManagerService.this.getPermissionInfoByGroup(group, flags, callingUid);
- }
- @Override
public PermissionSettings getPermissionSettings() {
return mSettings;
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 8cc6d76256d4..a78557523345 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -16,13 +16,12 @@
package com.android.server.pm.permission;
+import android.annotation.AppIdInt;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.PermissionInfoFlags;
import android.content.pm.PackageParser;
-import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.permission.PermissionManagerInternal;
@@ -44,24 +43,29 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
* callback methods.
*/
public static class PermissionCallback {
- public void onGidsChanged(int appId, int userId) {
+ public void onGidsChanged(@AppIdInt int appId, @UserIdInt int userId) {
}
public void onPermissionChanged() {
}
- public void onPermissionGranted(int uid, int userId) {
+ public void onPermissionGranted(int uid, @UserIdInt int userId) {
}
public void onInstallPermissionGranted() {
}
- public void onPermissionRevoked(int uid, int userId) {
+ public void onPermissionRevoked(int uid, @UserIdInt int userId) {
}
public void onInstallPermissionRevoked() {
}
- public void onPermissionUpdated(int[] updatedUserIds, boolean sync) {
+ public void onPermissionUpdated(@UserIdInt int[] updatedUserIds, boolean sync) {
+ }
+ public void onPermissionUpdatedNotifyListener(@UserIdInt int[] updatedUserIds, boolean sync,
+ int uid) {
}
public void onPermissionRemoved() {
}
public void onInstallPermissionUpdated() {
}
+ public void onInstallPermissionUpdatedNotifyListener(int uid) {
+ }
}
public abstract void systemReady();
@@ -150,10 +154,6 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
public abstract void addAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty);
public abstract void addAllPermissionGroups(@NonNull PackageParser.Package pkg, boolean chatty);
public abstract void removeAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty);
- public abstract boolean addDynamicPermission(@NonNull PermissionInfo info, boolean async,
- int callingUid, @Nullable PermissionCallback callback);
- public abstract void removeDynamicPermission(@NonNull String permName, int callingUid,
- @Nullable PermissionCallback callback);
/** Retrieve the packages that have requested the given app op permission */
public abstract @Nullable String[] getAppOpPermissionPackages(
@@ -161,26 +161,6 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
public abstract int getPermissionFlags(@NonNull String permName,
@NonNull String packageName, int callingUid, int userId);
- /**
- * Retrieve all of the information we know about a particular group of permissions.
- */
- public abstract @Nullable PermissionGroupInfo getPermissionGroupInfo(
- @NonNull String groupName, int flags, int callingUid);
- /**
- * Retrieve all of the known permission groups in the system.
- */
- public abstract @Nullable List<PermissionGroupInfo> getAllPermissionGroups(int flags,
- int callingUid);
- /**
- * Retrieve all of the information we know about a particular permission.
- */
- public abstract @Nullable PermissionInfo getPermissionInfo(@NonNull String permName,
- @NonNull String packageName, @PermissionInfoFlags int flags, int callingUid);
- /**
- * Retrieve all of the permissions associated with a particular group.
- */
- public abstract @Nullable List<PermissionInfo> getPermissionInfoByGroup(@NonNull String group,
- @PermissionInfoFlags int flags, int callingUid);
/**
* Updates the flags associated with a permission by replacing the flags in
diff --git a/services/core/java/com/android/server/pm/permission/TEST_MAPPING b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
index 3f9eb2d7fd8c..ee7a098b167b 100644
--- a/services/core/java/com/android/server/pm/permission/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/permission/TEST_MAPPING
@@ -14,6 +14,9 @@
},
{
"include-filter": "android.permission.cts.SharedUidPermissionsTest"
+ },
+ {
+ "include-filter": "android.permission.cts.PermissionUpdateListenerTest"
}
]
},
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index 9cd6b0d32793..c6a1867fa1e9 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -49,6 +49,7 @@ import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.UserHandle;
import android.os.UserManagerInternal;
+import android.provider.Telephony;
import android.service.sms.FinancialSmsService;
import android.telephony.IFinancialSmsCallback;
import android.text.TextUtils;
@@ -60,6 +61,7 @@ import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.telephony.SmsApplication;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.BitUtils;
import com.android.internal.util.CollectionUtils;
@@ -377,13 +379,16 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
}
@Override
- public void onRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId) {
+ public void onRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId,
+ @Nullable String removedHolder, @Nullable String addedHolder) {
mListenerHandler.sendMessage(PooledLambda.obtainMessage(
- RoleManagerService::notifyRoleHoldersChanged, this, roleName, userId));
+ RoleManagerService::notifyRoleHoldersChanged, this, roleName, userId,
+ removedHolder, addedHolder));
}
@WorkerThread
- private void notifyRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId) {
+ private void notifyRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId,
+ @Nullable String removedHolder, @Nullable String addedHolder) {
RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = getListeners(userId);
if (listeners != null) {
notifyRoleHoldersChangedForListeners(listeners, roleName, userId);
@@ -394,6 +399,12 @@ public class RoleManagerService extends SystemService implements RoleUserState.C
if (allUsersListeners != null) {
notifyRoleHoldersChangedForListeners(allUsersListeners, roleName, userId);
}
+
+ // Legacy: sms app changed broadcasts
+ if (RoleManager.ROLE_SMS.equals(roleName)) {
+ SmsApplication.broadcastSmsAppChange(getContext(), UserHandle.of(userId),
+ removedHolder, addedHolder);
+ }
}
@WorkerThread
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index c7e3fa4f2074..6375b4851283 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -294,7 +294,7 @@ public class RoleUserState {
}
if (changed) {
- mCallback.onRoleHoldersChanged(roleName, mUserId);
+ mCallback.onRoleHoldersChanged(roleName, mUserId, null, packageName);
}
return true;
}
@@ -328,7 +328,7 @@ public class RoleUserState {
}
if (changed) {
- mCallback.onRoleHoldersChanged(roleName, mUserId);
+ mCallback.onRoleHoldersChanged(roleName, mUserId, packageName, null);
}
return true;
}
@@ -632,6 +632,7 @@ public class RoleUserState {
* @param roleName the name of the role whose holders are changed
* @param userId the user id for this role holder change
*/
- void onRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId);
+ void onRoleHoldersChanged(@NonNull String roleName, @UserIdInt int userId,
+ @Nullable String removedHolder, @Nullable String addedHolder);
}
}
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 42a16132e5e1..cfa370bf63a3 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -75,6 +75,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -85,9 +86,9 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
private static final String TAG = "RollbackManager";
- // Rollbacks expire after 48 hours.
+ // Rollbacks expire after 14 days.
private static final long DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS =
- TimeUnit.HOURS.toMillis(48);
+ TimeUnit.DAYS.toMillis(14);
// Lock used to synchronize accesses to in-memory rollback data
// structures. By convention, methods with the suffix "Locked" require
@@ -114,9 +115,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
private final Set<NewRollback> mNewRollbacks = new ArraySet<>();
// The list of all rollbacks, including available and committed rollbacks.
- // This list is null until the rollback data has been loaded.
@GuardedBy("mLock")
- private List<RollbackData> mRollbacks;
+ private final List<RollbackData> mRollbacks;
private final RollbackStore mRollbackStore;
@@ -138,29 +138,25 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
// SystemService#onStart.
mInstaller = new Installer(mContext);
mInstaller.onStart();
- mHandlerThread = new HandlerThread("RollbackManagerServiceHandler");
- mHandlerThread.start();
-
- // Monitor the handler thread
- Watchdog.getInstance().addThread(getHandler(), HANDLER_THREAD_TIMEOUT_DURATION_MILLIS);
mRollbackStore = new RollbackStore(new File(Environment.getDataDirectory(), "rollback"));
mPackageHealthObserver = new RollbackPackageHealthObserver(mContext);
mAppDataRollbackHelper = new AppDataRollbackHelper(mInstaller);
- // Kick off loading of the rollback data from strorage in a background
- // thread.
- // TODO: Consider loading the rollback data directly here instead, to
- // avoid the need to call ensureRollbackDataLoaded every time before
- // accessing the rollback data?
- // TODO: Test that this kicks off initial scheduling of rollback
- // expiration.
- getHandler().post(() -> ensureRollbackDataLoaded());
-
- // TODO: Make sure to register these call backs when a new user is
- // added too.
- SessionCallback sessionCallback = new SessionCallback();
+ // Load rollback data from device storage.
+ synchronized (mLock) {
+ mRollbacks = mRollbackStore.loadAllRollbackData();
+ for (RollbackData data : mRollbacks) {
+ mAllocatedRollbackIds.put(data.info.getRollbackId(), true);
+ }
+ }
+
+ // Kick off and start monitoring the handler thread.
+ mHandlerThread = new HandlerThread("RollbackManagerServiceHandler");
+ mHandlerThread.start();
+ Watchdog.getInstance().addThread(getHandler(), HANDLER_THREAD_TIMEOUT_DURATION_MILLIS);
+
for (UserInfo userInfo : UserManager.get(mContext).getUsers(true)) {
registerUserCallbacks(userInfo.getUserHandle());
}
@@ -254,9 +250,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
return;
}
- // TODO: Reuse the same SessionCallback and broadcast receiver
- // instances, rather than creating new instances for each user.
-
context.getPackageManager().getPackageInstaller()
.registerSessionCallback(new SessionCallback(), getHandler());
@@ -299,20 +292,15 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
// to get the most up-to-date results. This is intended to reduce test
// flakiness when checking available rollbacks immediately after
// installing a package with rollback enabled.
- final LinkedBlockingQueue<Boolean> result = new LinkedBlockingQueue<>();
- getHandler().post(() -> result.offer(true));
-
+ CountDownLatch latch = new CountDownLatch(1);
+ getHandler().post(() -> latch.countDown());
try {
- result.take();
+ latch.await();
} catch (InterruptedException ie) {
- // We may not get the most up-to-date information, but whatever we
- // can get now is better than nothing, so log but otherwise ignore
- // the exception.
- Slog.w(TAG, "Interrupted while waiting for handler thread in getAvailableRollbacks");
+ throw new IllegalStateException("RollbackManagerHandlerThread interrupted");
}
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
List<RollbackInfo> rollbacks = new ArrayList<>();
for (int i = 0; i < mRollbacks.size(); ++i) {
RollbackData data = mRollbacks.get(i);
@@ -329,7 +317,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
enforceManageRollbacks("getRecentlyCommittedRollbacks");
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
List<RollbackInfo> rollbacks = new ArrayList<>();
for (int i = 0; i < mRollbacks.size(); ++i) {
RollbackData data = mRollbacks.get(i);
@@ -364,8 +351,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
final long timeDifference = mRelativeBootTime - oldRelativeBootTime;
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
-
Iterator<RollbackData> iter = mRollbacks.iterator();
while (iter.hasNext()) {
RollbackData data = iter.next();
@@ -544,13 +529,21 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
Manifest.permission.TEST_MANAGE_ROLLBACKS,
"reloadPersistedData");
- synchronized (mLock) {
- mRollbacks = null;
- }
+ CountDownLatch latch = new CountDownLatch(1);
getHandler().post(() -> {
updateRollbackLifetimeDurationInMillis();
- ensureRollbackDataLoaded();
+ synchronized (mLock) {
+ mRollbacks.clear();
+ mRollbacks.addAll(mRollbackStore.loadAllRollbackData());
+ }
+ latch.countDown();
});
+
+ try {
+ latch.await();
+ } catch (InterruptedException ie) {
+ throw new IllegalStateException("RollbackManagerHandlerThread interrupted");
+ }
}
@Override
@@ -559,7 +552,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
Manifest.permission.TEST_MANAGE_ROLLBACKS,
"expireRollbackForPackage");
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
Iterator<RollbackData> iter = mRollbacks.iterator();
while (iter.hasNext()) {
RollbackData data = iter.next();
@@ -583,7 +575,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
- // ignored.
+ throw new IllegalStateException("RollbackManagerHandlerThread interrupted");
}
});
}
@@ -626,7 +618,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
List<RollbackData> restoreInProgress = new ArrayList<>();
Set<String> apexPackageNames = new HashSet<>();
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
for (RollbackData data : mRollbacks) {
if (data.isStaged()) {
if (data.state == RollbackData.ROLLBACK_STATE_ENABLING) {
@@ -686,41 +677,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
}
/**
- * Load rollback data from storage if it has not already been loaded.
- * After calling this function, mRollbacks will be non-null.
- */
- private void ensureRollbackDataLoaded() {
- synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
- }
- }
-
- /**
- * Load rollback data from storage if it has not already been loaded.
- * After calling this function, mRollbacks will be non-null.
- */
- @GuardedBy("mLock")
- private void ensureRollbackDataLoadedLocked() {
- if (mRollbacks == null) {
- loadAllRollbackDataLocked();
- }
- }
-
- /**
- * Load all rollback data from storage.
- * Note: We do potentially heavy IO here while holding mLock, because we
- * have to have the rollback data loaded before we can do anything else
- * meaningful.
- */
- @GuardedBy("mLock")
- private void loadAllRollbackDataLocked() {
- mRollbacks = mRollbackStore.loadAllRollbackData();
- for (RollbackData data : mRollbacks) {
- mAllocatedRollbackIds.put(data.info.getRollbackId(), true);
- }
- }
-
- /**
* Called when a package has been replaced with a different version.
* Removes all backups for the package not matching the currently
* installed package version.
@@ -731,7 +687,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
VersionedPackage installedVersion = getInstalledPackageVersion(packageName);
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
Iterator<RollbackData> iter = mRollbacks.iterator();
while (iter.hasNext()) {
RollbackData data = iter.next();
@@ -800,8 +755,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
Instant now = Instant.now();
Instant oldest = null;
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
-
Iterator<RollbackData> iter = mRollbacks.iterator();
while (iter.hasNext()) {
RollbackData data = iter.next();
@@ -921,7 +874,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
// TODO: This check could be made more efficient.
RollbackData rd = null;
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
for (int i = 0; i < mRollbacks.size(); ++i) {
RollbackData data = mRollbacks.get(i);
if (data.apkSessionId == parentSession.getSessionId()) {
@@ -1077,7 +1029,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
private void snapshotUserDataInternal(String packageName) {
synchronized (mLock) {
// staged installs
- ensureRollbackDataLoadedLocked();
for (int i = 0; i < mRollbacks.size(); i++) {
RollbackData data = mRollbacks.get(i);
if (data.state != RollbackData.ROLLBACK_STATE_ENABLING) {
@@ -1110,7 +1061,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
PackageRollbackInfo info = null;
RollbackData rollbackData = null;
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
for (int i = 0; i < mRollbacks.size(); ++i) {
RollbackData data = mRollbacks.get(i);
if (data.restoreUserDataInProgress) {
@@ -1206,7 +1156,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
getHandler().post(() -> {
RollbackData rd = null;
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
for (int i = 0; i < mRollbacks.size(); ++i) {
RollbackData data = mRollbacks.get(i);
if (data.stagedSessionId == originalSessionId) {
@@ -1298,7 +1247,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
private boolean packageVersionsEqual(VersionedPackage a, VersionedPackage b) {
- return a.getPackageName().equals(b.getPackageName())
+ return a != null && b != null
+ && a.getPackageName().equals(b.getPackageName())
&& a.getLongVersionCode() == b.getLongVersionCode();
}
@@ -1377,7 +1327,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
// device reboots between when the session is
// committed and this point. Revisit this after
// adding support for rollback of staged installs.
- ensureRollbackDataLoadedLocked();
mRollbacks.add(data);
}
@@ -1414,9 +1363,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
*/
private RollbackData getRollbackForId(int rollbackId) {
synchronized (mLock) {
- // TODO: Have ensureRollbackDataLoadedLocked return the list of
- // available rollbacks, to hopefully avoid forgetting to call it?
- ensureRollbackDataLoadedLocked();
for (int i = 0; i < mRollbacks.size(); ++i) {
RollbackData data = mRollbacks.get(i);
if (data.info.getRollbackId() == rollbackId) {
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 5f00148335a7..ab3d7b7f763c 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -30,6 +30,7 @@ import android.os.UserHandle;
import android.service.textclassifier.ITextClassifierCallback;
import android.service.textclassifier.ITextClassifierService;
import android.service.textclassifier.TextClassifierService;
+import android.util.ArrayMap;
import android.util.Slog;
import android.util.SparseArray;
import android.view.textclassifier.ConversationActions;
@@ -54,6 +55,7 @@ import com.android.server.SystemService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayDeque;
+import java.util.Map;
import java.util.Queue;
/**
@@ -119,6 +121,8 @@ public final class TextClassificationManagerService extends ITextClassifierServi
private final Object mLock;
@GuardedBy("mLock")
final SparseArray<UserState> mUserStates = new SparseArray<>();
+ @GuardedBy("mLock")
+ private final Map<TextClassificationSessionId, Integer> mSessionUserIds = new ArrayMap<>();
private TextClassificationManagerService(Context context) {
mContext = Preconditions.checkNotNull(context);
@@ -127,15 +131,16 @@ public final class TextClassificationManagerService extends ITextClassifierServi
@Override
public void onSuggestSelection(
- TextClassificationSessionId sessionId,
+ @Nullable TextClassificationSessionId sessionId,
TextSelection.Request request, ITextClassifierCallback callback)
throws RemoteException {
Preconditions.checkNotNull(request);
Preconditions.checkNotNull(callback);
- validateInput(mContext, request.getCallingPackageName());
+ final int userId = request.getUserId();
+ validateInput(mContext, request.getCallingPackageName(), userId);
synchronized (mLock) {
- UserState userState = getCallingUserStateLocked();
+ UserState userState = getUserStateLocked(userId);
if (!userState.bindLocked()) {
callback.onFailure();
} else if (userState.isBoundLocked()) {
@@ -150,15 +155,16 @@ public final class TextClassificationManagerService extends ITextClassifierServi
@Override
public void onClassifyText(
- TextClassificationSessionId sessionId,
+ @Nullable TextClassificationSessionId sessionId,
TextClassification.Request request, ITextClassifierCallback callback)
throws RemoteException {
Preconditions.checkNotNull(request);
Preconditions.checkNotNull(callback);
- validateInput(mContext, request.getCallingPackageName());
+ final int userId = request.getUserId();
+ validateInput(mContext, request.getCallingPackageName(), userId);
synchronized (mLock) {
- UserState userState = getCallingUserStateLocked();
+ UserState userState = getUserStateLocked(userId);
if (!userState.bindLocked()) {
callback.onFailure();
} else if (userState.isBoundLocked()) {
@@ -173,15 +179,16 @@ public final class TextClassificationManagerService extends ITextClassifierServi
@Override
public void onGenerateLinks(
- TextClassificationSessionId sessionId,
+ @Nullable TextClassificationSessionId sessionId,
TextLinks.Request request, ITextClassifierCallback callback)
throws RemoteException {
Preconditions.checkNotNull(request);
Preconditions.checkNotNull(callback);
- validateInput(mContext, request.getCallingPackageName());
+ final int userId = request.getUserId();
+ validateInput(mContext, request.getCallingPackageName(), userId);
synchronized (mLock) {
- UserState userState = getCallingUserStateLocked();
+ UserState userState = getUserStateLocked(userId);
if (!userState.bindLocked()) {
callback.onFailure();
} else if (userState.isBoundLocked()) {
@@ -196,12 +203,14 @@ public final class TextClassificationManagerService extends ITextClassifierServi
@Override
public void onSelectionEvent(
- TextClassificationSessionId sessionId, SelectionEvent event) throws RemoteException {
+ @Nullable TextClassificationSessionId sessionId, SelectionEvent event)
+ throws RemoteException {
Preconditions.checkNotNull(event);
- validateInput(mContext, event.getPackageName());
+ final int userId = event.getUserId();
+ validateInput(mContext, event.getPackageName(), userId);
synchronized (mLock) {
- UserState userState = getCallingUserStateLocked();
+ UserState userState = getUserStateLocked(userId);
if (userState.isBoundLocked()) {
userState.mService.onSelectionEvent(sessionId, event);
} else {
@@ -213,16 +222,19 @@ public final class TextClassificationManagerService extends ITextClassifierServi
}
@Override
public void onTextClassifierEvent(
- TextClassificationSessionId sessionId,
+ @Nullable TextClassificationSessionId sessionId,
TextClassifierEvent event) throws RemoteException {
Preconditions.checkNotNull(event);
final String packageName = event.getEventContext() == null
? null
: event.getEventContext().getPackageName();
- validateInput(mContext, packageName);
+ final int userId = event.getEventContext() == null
+ ? UserHandle.getCallingUserId()
+ : event.getEventContext().getUserId();
+ validateInput(mContext, packageName, userId);
synchronized (mLock) {
- UserState userState = getCallingUserStateLocked();
+ UserState userState = getUserStateLocked(userId);
if (userState.isBoundLocked()) {
userState.mService.onTextClassifierEvent(sessionId, event);
} else {
@@ -235,15 +247,16 @@ public final class TextClassificationManagerService extends ITextClassifierServi
@Override
public void onDetectLanguage(
- TextClassificationSessionId sessionId,
+ @Nullable TextClassificationSessionId sessionId,
TextLanguage.Request request,
ITextClassifierCallback callback) throws RemoteException {
Preconditions.checkNotNull(request);
Preconditions.checkNotNull(callback);
- validateInput(mContext, request.getCallingPackageName());
+ final int userId = request.getUserId();
+ validateInput(mContext, request.getCallingPackageName(), userId);
synchronized (mLock) {
- UserState userState = getCallingUserStateLocked();
+ UserState userState = getUserStateLocked(userId);
if (!userState.bindLocked()) {
callback.onFailure();
} else if (userState.isBoundLocked()) {
@@ -258,15 +271,16 @@ public final class TextClassificationManagerService extends ITextClassifierServi
@Override
public void onSuggestConversationActions(
- TextClassificationSessionId sessionId,
+ @Nullable TextClassificationSessionId sessionId,
ConversationActions.Request request,
ITextClassifierCallback callback) throws RemoteException {
Preconditions.checkNotNull(request);
Preconditions.checkNotNull(callback);
- validateInput(mContext, request.getCallingPackageName());
+ final int userId = request.getUserId();
+ validateInput(mContext, request.getCallingPackageName(), userId);
synchronized (mLock) {
- UserState userState = getCallingUserStateLocked();
+ UserState userState = getUserStateLocked(userId);
if (!userState.bindLocked()) {
callback.onFailure();
} else if (userState.isBoundLocked()) {
@@ -285,13 +299,15 @@ public final class TextClassificationManagerService extends ITextClassifierServi
throws RemoteException {
Preconditions.checkNotNull(sessionId);
Preconditions.checkNotNull(classificationContext);
- validateInput(mContext, classificationContext.getPackageName());
+ final int userId = classificationContext.getUserId();
+ validateInput(mContext, classificationContext.getPackageName(), userId);
synchronized (mLock) {
- UserState userState = getCallingUserStateLocked();
+ UserState userState = getUserStateLocked(userId);
if (userState.isBoundLocked()) {
userState.mService.onCreateTextClassificationSession(
classificationContext, sessionId);
+ mSessionUserIds.put(sessionId, userId);
} else {
userState.mPendingRequests.add(new PendingRequest(
() -> onCreateTextClassificationSession(classificationContext, sessionId),
@@ -306,9 +322,15 @@ public final class TextClassificationManagerService extends ITextClassifierServi
Preconditions.checkNotNull(sessionId);
synchronized (mLock) {
- UserState userState = getCallingUserStateLocked();
+ final int userId = mSessionUserIds.containsKey(sessionId)
+ ? mSessionUserIds.get(sessionId)
+ : UserHandle.getCallingUserId();
+ validateInput(mContext, null /* packageName */, userId);
+
+ UserState userState = getUserStateLocked(userId);
if (userState.isBoundLocked()) {
userState.mService.onDestroyTextClassificationSession(sessionId);
+ mSessionUserIds.remove(sessionId);
} else {
userState.mPendingRequests.add(new PendingRequest(
() -> onDestroyTextClassificationSession(sessionId),
@@ -318,11 +340,6 @@ public final class TextClassificationManagerService extends ITextClassifierServi
}
@GuardedBy("mLock")
- private UserState getCallingUserStateLocked() {
- return getUserStateLocked(UserHandle.getCallingUserId());
- }
-
- @GuardedBy("mLock")
private UserState getUserStateLocked(int userId) {
UserState result = mUserStates.get(userId);
if (result == null) {
@@ -356,6 +373,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi
pw.decreaseIndent();
}
}
+ pw.println("Number of active sessions: " + mSessionUserIds.size());
}
}
@@ -420,20 +438,32 @@ public final class TextClassificationManagerService extends ITextClassifierServi
e -> Slog.d(LOG_TAG, "Error " + opDesc + ": " + e.getMessage()));
}
- private static void validateInput(Context context, @Nullable String packageName)
+ private static void validateInput(
+ Context context, @Nullable String packageName, @UserIdInt int userId)
throws RemoteException {
- if (packageName == null) return;
try {
- final int packageUid = context.getPackageManager()
- .getPackageUidAsUser(packageName, UserHandle.getCallingUserId());
- final int callingUid = Binder.getCallingUid();
- Preconditions.checkArgument(callingUid == packageUid
- // Trust the system process:
- || callingUid == android.os.Process.SYSTEM_UID);
+ if (packageName != null) {
+ final int packageUid = context.getPackageManager()
+ .getPackageUidAsUser(packageName, UserHandle.getCallingUserId());
+ final int callingUid = Binder.getCallingUid();
+ Preconditions.checkArgument(callingUid == packageUid
+ // Trust the system process:
+ || callingUid == android.os.Process.SYSTEM_UID,
+ "Invalid package name. Package=" + packageName
+ + ", CallingUid=" + callingUid);
+ }
+
+ Preconditions.checkArgument(userId != UserHandle.USER_NULL, "Null userId");
+ final int callingUserId = UserHandle.getCallingUserId();
+ if (callingUserId != userId) {
+ context.enforceCallingPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "Invalid userId. UserId=" + userId + ", CallingUserId=" + callingUserId);
+ }
} catch (Exception e) {
- throw new RemoteException(
- String.format("Invalid package: name=%s, error=%s", packageName, e));
+ throw new RemoteException("Invalid request", e,
+ /* enableSuppression */ true, /* writableStackTrace */ true);
}
}
diff --git a/services/core/java/com/android/server/textservices/LazyIntToIntMap.java b/services/core/java/com/android/server/textservices/LazyIntToIntMap.java
deleted file mode 100644
index 2e7f2a92e1d9..000000000000
--- a/services/core/java/com/android/server/textservices/LazyIntToIntMap.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.server.textservices;
-
-import android.annotation.NonNull;
-import android.util.SparseIntArray;
-
-import java.util.function.IntUnaryOperator;
-
-/**
- * Simple int-to-int key-value-store that is to be lazily initialized with the given
- * {@link IntUnaryOperator}.
- */
-final class LazyIntToIntMap {
-
- private final SparseIntArray mMap = new SparseIntArray();
-
- @NonNull
- private final IntUnaryOperator mMappingFunction;
-
- /**
- * @param mappingFunction int to int mapping rules to be (lazily) evaluated
- */
- public LazyIntToIntMap(@NonNull IntUnaryOperator mappingFunction) {
- mMappingFunction = mappingFunction;
- }
-
- /**
- * Deletes {@code key} and associated value.
- * @param key key to be deleted
- */
- public void delete(int key) {
- mMap.delete(key);
- }
-
- /**
- * @param key key associated with the value
- * @return value associated with the {@code key}. If this is the first time to access
- * {@code key}, then {@code mappingFunction} passed to the constructor will be evaluated
- */
- public int get(int key) {
- final int index = mMap.indexOfKey(key);
- if (index >= 0) {
- return mMap.valueAt(index);
- }
- final int value = mMappingFunction.applyAsInt(key);
- mMap.append(key, value);
- return value;
- }
-}
diff --git a/services/core/java/com/android/server/textservices/TextServicesManagerService.java b/services/core/java/com/android/server/textservices/TextServicesManagerService.java
index d4aa59d3ce85..e0bac93cce16 100644
--- a/services/core/java/com/android/server/textservices/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/textservices/TextServicesManagerService.java
@@ -43,7 +43,6 @@ import android.service.textservice.SpellCheckerService;
import android.text.TextUtils;
import android.util.Slog;
import android.util.SparseArray;
-import android.view.inputmethod.InputMethodSystemProperty;
import android.view.textservice.SpellCheckerInfo;
import android.view.textservice.SpellCheckerSubtype;
@@ -86,10 +85,6 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
private final UserManager mUserManager;
private final Object mLock = new Object();
- @NonNull
- @GuardedBy("mLock")
- private final LazyIntToIntMap mSpellCheckerOwnerUserIdMap;
-
private static class TextServicesData {
@UserIdInt
private final int mUserId;
@@ -312,9 +307,6 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
void onStopUser(@UserIdInt int userId) {
synchronized (mLock) {
- // Clear user ID mapping table.
- mSpellCheckerOwnerUserIdMap.delete(userId);
-
// Clean per-user data
TextServicesData tsd = mUserData.get(userId);
if (tsd == null) return;
@@ -334,33 +326,12 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
public TextServicesManagerService(Context context) {
mContext = context;
mUserManager = mContext.getSystemService(UserManager.class);
- mSpellCheckerOwnerUserIdMap = new LazyIntToIntMap(callingUserId -> {
- if (!InputMethodSystemProperty.PER_PROFILE_IME_ENABLED) {
- final long token = Binder.clearCallingIdentity();
- try {
- final UserInfo parent = mUserManager.getProfileParent(callingUserId);
- return (parent != null) ? parent.id : callingUserId;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- } else {
- return callingUserId;
- }
- });
-
mMonitor = new TextServicesMonitor();
mMonitor.register(context, null, UserHandle.ALL, true);
}
@GuardedBy("mLock")
private void initializeInternalStateLocked(@UserIdInt int userId) {
- // When DISABLE_PER_PROFILE_SPELL_CHECKER is true, we make sure here that work profile users
- // will never have non-null TextServicesData for their user ID.
- if (!InputMethodSystemProperty.PER_PROFILE_IME_ENABLED
- && userId != mSpellCheckerOwnerUserIdMap.get(userId)) {
- return;
- }
-
TextServicesData tsd = mUserData.get(userId);
if (tsd == null) {
tsd = new TextServicesData(userId, mContext);
@@ -506,8 +477,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
@Nullable
private SpellCheckerInfo getCurrentSpellCheckerForUser(@UserIdInt int userId) {
synchronized (mLock) {
- final int spellCheckerOwnerUserId = mSpellCheckerOwnerUserIdMap.get(userId);
- final TextServicesData data = mUserData.get(spellCheckerOwnerUserId);
+ final TextServicesData data = mUserData.get(userId);
return data != null ? data.getCurrentSpellChecker() : null;
}
}
@@ -790,27 +760,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
@GuardedBy("mLock")
@Nullable
private TextServicesData getDataFromCallingUserIdLocked(@UserIdInt int callingUserId) {
- final int spellCheckerOwnerUserId = mSpellCheckerOwnerUserIdMap.get(callingUserId);
- final TextServicesData data = mUserData.get(spellCheckerOwnerUserId);
- if (!InputMethodSystemProperty.PER_PROFILE_IME_ENABLED) {
- if (spellCheckerOwnerUserId != callingUserId) {
- // Calling process is running under child profile.
- if (data == null) {
- return null;
- }
- final SpellCheckerInfo info = data.getCurrentSpellChecker();
- if (info == null) {
- return null;
- }
- final ServiceInfo serviceInfo = info.getServiceInfo();
- if ((serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
- // To be conservative, non pre-installed spell checker services are not allowed
- // to be used for child profiles.
- return null;
- }
- }
- }
- return data;
+ return mUserData.get(callingUserId);
}
private static final class SessionRequest {
diff --git a/services/core/java/com/android/server/updates/CertificateTransparencyLogInstallReceiver.java b/services/core/java/com/android/server/updates/CertificateTransparencyLogInstallReceiver.java
index ec65f8dafe52..bf32045146f6 100644
--- a/services/core/java/com/android/server/updates/CertificateTransparencyLogInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/CertificateTransparencyLogInstallReceiver.java
@@ -16,25 +16,30 @@
package com.android.server.updates;
-import com.android.internal.util.HexDump;
import android.os.FileUtils;
-import android.system.Os;
import android.system.ErrnoException;
+import android.system.Os;
import android.util.Base64;
import android.util.Slog;
+
+import com.android.internal.util.HexDump;
+
+import libcore.io.Streams;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStreamWriter;
-import java.io.StringBufferInputStream;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
-import java.security.PublicKey;
import java.security.NoSuchAlgorithmException;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
public class CertificateTransparencyLogInstallReceiver extends ConfigUpdateInstallReceiver {
@@ -46,14 +51,13 @@ public class CertificateTransparencyLogInstallReceiver extends ConfigUpdateInsta
}
@Override
- protected void install(byte[] content, int version) throws IOException {
+ protected void install(InputStream inputStream, int version) throws IOException {
/* Install is complicated here because we translate the input, which is a JSON file
* containing log information to a directory with a file per log. To support atomically
* replacing the old configuration directory with the new there's a bunch of steps. We
* create a new directory with the logs and then do an atomic update of the current symlink
* to point to the new directory.
*/
-
// 1. Ensure that the update dir exists and is readable
updateDir.mkdir();
if (!updateDir.isDirectory()) {
@@ -72,7 +76,8 @@ public class CertificateTransparencyLogInstallReceiver extends ConfigUpdateInsta
// and so we cannot delete the directory since its in use. Instead just bump the version
// and return.
if (newVersion.getCanonicalPath().equals(currentSymlink.getCanonicalPath())) {
- writeUpdate(updateDir, updateVersion, Long.toString(version).getBytes());
+ writeUpdate(updateDir, updateVersion,
+ new ByteArrayInputStream(Long.toString(version).getBytes()));
deleteOldLogDirectories();
return;
} else {
@@ -92,6 +97,7 @@ public class CertificateTransparencyLogInstallReceiver extends ConfigUpdateInsta
// 4. For each log in the log file create the corresponding file in <new_version>/ .
try {
+ byte[] content = Streams.readFullyNoClose(inputStream);
JSONObject json = new JSONObject(new String(content, StandardCharsets.UTF_8));
JSONArray logs = json.getJSONArray("logs");
for (int i = 0; i < logs.length(); i++) {
@@ -119,7 +125,8 @@ public class CertificateTransparencyLogInstallReceiver extends ConfigUpdateInsta
}
Slog.i(TAG, "CT log directory updated to " + newVersion.getAbsolutePath());
// 7. Update the current version information
- writeUpdate(updateDir, updateVersion, Long.toString(version).getBytes());
+ writeUpdate(updateDir, updateVersion,
+ new ByteArrayInputStream(Long.toString(version).getBytes()));
// 8. Cleanup
deleteOldLogDirectories();
}
diff --git a/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java b/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
index c3c841c73ca9..73bb4bf956c3 100644
--- a/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/ConfigUpdateInstallReceiver.java
@@ -16,9 +16,6 @@
package com.android.server.updates;
-import com.android.server.EventLogTags;
-import com.android.internal.util.HexDump;
-
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -26,6 +23,14 @@ import android.net.Uri;
import android.util.EventLog;
import android.util.Slog;
+import com.android.internal.util.HexDump;
+import com.android.server.EventLogTags;
+
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -33,9 +38,6 @@ import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-import libcore.io.IoUtils;
-import libcore.io.Streams;
-
public class ConfigUpdateInstallReceiver extends BroadcastReceiver {
private static final String TAG = "ConfigUpdateInstallReceiver";
@@ -61,8 +63,6 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver {
@Override
public void run() {
try {
- // get the content path from the extras
- byte[] altContent = getAltContent(context, intent);
// get the version from the extras
int altVersion = getVersionFromIntent(intent);
// get the previous value from the extras
@@ -75,11 +75,13 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver {
Slog.i(TAG, "Not installing, new version is <= current version");
} else if (!verifyPreviousHash(currentHash, altRequiredHash)) {
EventLog.writeEvent(EventLogTags.CONFIG_INSTALL_FAILED,
- "Current hash did not match required value");
+ "Current hash did not match required value");
} else {
// install the new content
Slog.i(TAG, "Found new update, installing...");
- install(altContent, altVersion);
+ try (BufferedInputStream altContent = getAltContent(context, intent)) {
+ install(altContent, altVersion);
+ }
Slog.i(TAG, "Installation successful");
postInstall(context, intent);
}
@@ -130,14 +132,9 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver {
}
}
- private byte[] getAltContent(Context c, Intent i) throws IOException {
+ private BufferedInputStream getAltContent(Context c, Intent i) throws IOException {
Uri content = getContentFromIntent(i);
- InputStream is = c.getContentResolver().openInputStream(content);
- try {
- return Streams.readFullyNoClose(is);
- } finally {
- is.close();
- }
+ return new BufferedInputStream(c.getContentResolver().openInputStream(content));
}
private byte[] getCurrentContent() {
@@ -175,7 +172,7 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver {
return current.equals(required);
}
- protected void writeUpdate(File dir, File file, byte[] content) throws IOException {
+ protected void writeUpdate(File dir, File file, InputStream inputStream) throws IOException {
FileOutputStream out = null;
File tmp = null;
try {
@@ -192,7 +189,7 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver {
tmp.setReadable(true, false);
// write to it
out = new FileOutputStream(tmp);
- out.write(content);
+ Streams.copy(inputStream, out);
// sync to disk
out.getFD().sync();
// atomic rename
@@ -207,9 +204,10 @@ public class ConfigUpdateInstallReceiver extends BroadcastReceiver {
}
}
- protected void install(byte[] content, int version) throws IOException {
- writeUpdate(updateDir, updateContent, content);
- writeUpdate(updateDir, updateVersion, Long.toString(version).getBytes());
+ protected void install(InputStream inputStream, int version) throws IOException {
+ writeUpdate(updateDir, updateContent, inputStream);
+ writeUpdate(updateDir, updateVersion,
+ new ByteArrayInputStream(Long.toString(version).getBytes()));
}
protected void postInstall(Context context, Intent intent) {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 9908b3657121..b0f1e5d69be4 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1172,8 +1172,16 @@ public class WallpaperManagerService extends IWallpaperManager.Stub
return false;
}
final int displayId = display.getDisplayId();
- return displayId == DEFAULT_DISPLAY
- || mWindowManagerInternal.shouldShowSystemDecorOnDisplay(displayId);
+ if (displayId == DEFAULT_DISPLAY) {
+ return true;
+ }
+
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ return mWindowManagerInternal.shouldShowSystemDecorOnDisplay(displayId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
void forEachDisplayConnector(Consumer<DisplayConnector> action) {
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 637ad0384dac..fe4811dce274 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -29,6 +29,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.os.Build.VERSION_CODES.N;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.FLAG_PRIVATE;
import static android.view.Display.REMOVE_MODE_DESTROY_CONTENT;
@@ -55,18 +56,24 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.WindowConfiguration;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Point;
import android.os.IBinder;
+import android.os.Message;
import android.os.UserHandle;
+import android.provider.Settings;
import android.util.IntArray;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.am.EventLogTags;
import java.io.PrintWriter;
@@ -156,6 +163,9 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
// Used in updating the display size
private Point mTmpDisplaySize = new Point();
+ // Used in updating override configurations
+ private final Configuration mTempConfig = new Configuration();
+
private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
ActivityDisplay(RootActivityContainer root, Display display) {
@@ -999,6 +1009,89 @@ class ActivityDisplay extends ConfigurationContainer<ActivityStack>
return mStacks.indexOf(stack);
}
+ boolean updateDisplayOverrideConfigurationLocked() {
+ Configuration values = new Configuration();
+ mDisplayContent.computeScreenConfiguration(values);
+
+ if (mService.mWindowManager != null) {
+ final Message msg = PooledLambda.obtainMessage(
+ ActivityManagerInternal::updateOomLevelsForDisplay, mService.mAmInternal,
+ mDisplayId);
+ mService.mH.sendMessage(msg);
+ }
+
+ Settings.System.clearConfiguration(values);
+ updateDisplayOverrideConfigurationLocked(values, null /* starting */,
+ false /* deferResume */, mService.mTmpUpdateConfigurationResult);
+ return mService.mTmpUpdateConfigurationResult.changes != 0;
+ }
+
+ /**
+ * Updates override configuration specific for the selected display. If no config is provided,
+ * new one will be computed in WM based on current display info.
+ */
+ boolean updateDisplayOverrideConfigurationLocked(Configuration values,
+ ActivityRecord starting, boolean deferResume,
+ ActivityTaskManagerService.UpdateConfigurationResult result) {
+
+ int changes = 0;
+ boolean kept = true;
+
+ if (mService.mWindowManager != null) {
+ mService.mWindowManager.deferSurfaceLayout();
+ }
+ try {
+ if (values != null) {
+ if (mDisplayId == DEFAULT_DISPLAY) {
+ // Override configuration of the default display duplicates global config, so
+ // we're calling global config update instead for default display. It will also
+ // apply the correct override config.
+ changes = mService.updateGlobalConfigurationLocked(values,
+ false /* initLocale */, false /* persistent */,
+ UserHandle.USER_NULL /* userId */, deferResume);
+ } else {
+ changes = performDisplayOverrideConfigUpdate(values, deferResume);
+ }
+ }
+
+ kept = mService.ensureConfigAndVisibilityAfterUpdate(starting, changes);
+ } finally {
+ if (mService.mWindowManager != null) {
+ mService.mWindowManager.continueSurfaceLayout();
+ }
+ }
+
+ if (result != null) {
+ result.changes = changes;
+ result.activityRelaunched = !kept;
+ }
+ return kept;
+ }
+
+ int performDisplayOverrideConfigUpdate(Configuration values, boolean deferResume) {
+ mTempConfig.setTo(getRequestedOverrideConfiguration());
+ final int changes = mTempConfig.updateFrom(values);
+ if (changes != 0) {
+ Slog.i(TAG, "Override config changes=" + Integer.toHexString(changes) + " "
+ + mTempConfig + " for displayId=" + mDisplayId);
+ onRequestedOverrideConfigurationChanged(mTempConfig);
+
+ final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
+ if (isDensityChange && mDisplayId == DEFAULT_DISPLAY) {
+ mService.mAppWarnings.onDensityChanged();
+
+ // Post message to start process to avoid possible deadlock of calling into AMS with
+ // the ATMS lock held.
+ final Message msg = PooledLambda.obtainMessage(
+ ActivityManagerInternal::killAllBackgroundProcessesExcept,
+ mService.mAmInternal, N,
+ ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
+ mService.mH.sendMessage(msg);
+ }
+ }
+ return changes;
+ }
+
@Override
public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
final int currRotation =
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index bc0f74715240..a0a296792680 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -225,7 +225,7 @@ class ActivityMetricsLogger {
private WindowingModeTransitionInfoSnapshot(WindowingModeTransitionInfo info,
ActivityRecord launchedActivity, int windowsFullyDrawnDelayMs) {
- applicationInfo = launchedActivity.appInfo;
+ applicationInfo = launchedActivity.info.applicationInfo;
packageName = launchedActivity.packageName;
launchedActivityName = launchedActivity.info.name;
launchedActivityLaunchedFromPackage = launchedActivity.launchedFromPackage;
@@ -582,7 +582,7 @@ class ActivityMetricsLogger {
final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.valueAt(i);
// App isn't attached to record yet, so match with info.
- if (info.launchedActivity.appInfo == appInfo) {
+ if (info.launchedActivity.info.applicationInfo == appInfo) {
info.bindApplicationDelayMs = calculateCurrentDelay();
}
}
@@ -649,13 +649,13 @@ class ActivityMetricsLogger {
mMetricsLogger.write(builder);
StatsLog.write(
StatsLog.APP_START_CANCELED,
- info.launchedActivity.appInfo.uid,
+ info.launchedActivity.info.applicationInfo.uid,
info.launchedActivity.packageName,
convertAppStartTransitionType(type),
info.launchedActivity.info.name);
if (DEBUG_METRICS) {
Slog.i(TAG, String.format("APP_START_CANCELED(%s, %s, %s, %s)",
- info.launchedActivity.appInfo.uid,
+ info.launchedActivity.info.applicationInfo.uid,
info.launchedActivity.packageName,
convertAppStartTransitionType(type),
info.launchedActivity.info.name));
@@ -821,7 +821,7 @@ class ActivityMetricsLogger {
mMetricsLogger.write(builder);
StatsLog.write(
StatsLog.APP_START_FULLY_DRAWN,
- info.launchedActivity.appInfo.uid,
+ info.launchedActivity.info.applicationInfo.uid,
info.launchedActivity.packageName,
restoredFromBundle
? StatsLog.APP_START_FULLY_DRAWN__TYPE__WITH_BUNDLE
@@ -961,7 +961,7 @@ class ActivityMetricsLogger {
private WindowProcessController findProcessForActivity(ActivityRecord launchedActivity) {
return launchedActivity != null
? mSupervisor.mService.mProcessNames.get(
- launchedActivity.processName, launchedActivity.appInfo.uid)
+ launchedActivity.processName, launchedActivity.info.applicationInfo.uid)
: null;
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index f6eb8eab1ade..9c87ce8e1744 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -246,8 +246,6 @@ final class ActivityRecord extends ConfigurationContainer {
private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
- private static final boolean SHOW_ACTIVITY_START_TIME = true;
-
private static final String ATTR_ID = "id";
private static final String TAG_INTENT = "intent";
private static final String ATTR_USERID = "user_id";
@@ -263,9 +261,7 @@ final class ActivityRecord extends ConfigurationContainer {
// TODO: Remove after unification
AppWindowToken mAppWindowToken;
- final ActivityInfo info; // all about me
- // TODO: This is duplicated state already contained in info.applicationInfo - remove
- ApplicationInfo appInfo; // information about activity's app
+ final ActivityInfo info; // activity info provided by developer in AndroidManifest
final int launchedFromPid; // always the pid who started the activity.
final int launchedFromUid; // always the uid who started the activity.
final String launchedFromPackage; // always the package who started the activity.
@@ -448,7 +444,8 @@ final class ActivityRecord extends ConfigurationContainer {
pw.print(prefix); pw.print("taskAffinity="); pw.println(taskAffinity);
pw.print(prefix); pw.print("mActivityComponent=");
pw.println(mActivityComponent.flattenToShortString());
- if (appInfo != null) {
+ if (info != null && info.applicationInfo != null) {
+ final ApplicationInfo appInfo = info.applicationInfo;
pw.print(prefix); pw.print("baseDir="); pw.println(appInfo.sourceDir);
if (!Objects.equals(appInfo.sourceDir, appInfo.publicSourceDir)) {
pw.print(prefix); pw.print("resDir="); pw.println(appInfo.publicSourceDir);
@@ -618,7 +615,6 @@ final class ActivityRecord extends ConfigurationContainer {
}
void updateApplicationInfo(ApplicationInfo aInfo) {
- appInfo = aInfo;
info.applicationInfo = aInfo;
}
@@ -992,7 +988,6 @@ final class ActivityRecord extends ConfigurationContainer {
}
taskAffinity = aInfo.taskAffinity;
stateNotNeeded = (aInfo.flags & FLAG_STATE_NOT_NEEDED) != 0;
- appInfo = aInfo.applicationInfo;
nonLocalizedLabel = aInfo.nonLocalizedLabel;
labelRes = aInfo.labelRes;
if (nonLocalizedLabel == null && labelRes == 0) {
@@ -1051,7 +1046,8 @@ final class ActivityRecord extends ConfigurationContainer {
mRotationAnimationHint = aInfo.rotationAnimation;
lockTaskLaunchMode = aInfo.lockTaskLaunchMode;
- if (appInfo.isPrivilegedApp() && (lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_ALWAYS
+ if (info.applicationInfo.isPrivilegedApp()
+ && (lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_ALWAYS
|| lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_NEVER)) {
lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_DEFAULT;
}
@@ -1121,7 +1117,8 @@ final class ActivityRecord extends ConfigurationContainer {
task.voiceSession != null, container.getDisplayContent(),
ActivityTaskManagerService.getInputDispatchingTimeoutLocked(this)
* 1000000L, fullscreen,
- (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, appInfo.targetSdkVersion,
+ (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0,
+ info.applicationInfo.targetSdkVersion,
info.screenOrientation, mRotationAnimationHint,
mLaunchTaskBehind, isAlwaysFocusable());
if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) {
@@ -1290,7 +1287,7 @@ final class ActivityRecord extends ConfigurationContainer {
info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
}
} else if (mAtmService.getRecentTasks().isRecentsComponent(mActivityComponent,
- appInfo.uid)) {
+ info.applicationInfo.uid)) {
activityType = ACTIVITY_TYPE_RECENTS;
} else if (options != null && options.getLaunchActivityType() == ACTIVITY_TYPE_ASSISTANT
&& canLaunchAssistActivity(launchedFromPackage)) {
@@ -1488,7 +1485,7 @@ final class ActivityRecord extends ConfigurationContainer {
*/
private boolean checkEnterPictureInPictureAppOpsState() {
return mAtmService.getAppOpsService().checkOperation(
- OP_PICTURE_IN_PICTURE, appInfo.uid, packageName) == MODE_ALLOWED;
+ OP_PICTURE_IN_PICTURE, info.applicationInfo.uid, packageName) == MODE_ALLOWED;
}
boolean isAlwaysFocusable() {
@@ -1615,8 +1612,11 @@ final class ActivityRecord extends ConfigurationContainer {
try {
ArrayList<ReferrerIntent> ar = new ArrayList<>(1);
ar.add(rintent);
+ // Making sure the client state is RESUMED after transaction completed and doing
+ // so only if activity is currently RESUMED. Otherwise, client may have extra
+ // life-cycle calls to RESUMED (and PAUSED later).
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
- NewIntentItem.obtain(ar));
+ NewIntentItem.obtain(ar, mState == RESUMED));
unsent = false;
} catch (RemoteException e) {
Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
@@ -2474,8 +2474,8 @@ final class ActivityRecord extends ConfigurationContainer {
if (windowFromSameProcessAsActivity) {
return mAtmService.mAmInternal.inputDispatchingTimedOut(anrApp.mOwner,
- anrActivity.shortComponentName, anrActivity.appInfo, shortComponentName,
- app, false, reason);
+ anrActivity.shortComponentName, anrActivity.info.applicationInfo,
+ shortComponentName, app, false, reason);
} else {
// In this case another process added windows using this activity token. So, we call the
// generic service input dispatch timed out method so that the right process is blamed.
@@ -3365,7 +3365,7 @@ final class ActivityRecord extends ConfigurationContainer {
// If a device is in VR mode, and we're transitioning into VR ui mode, add ignore ui mode
// to the config change.
// For O and later, apps will be required to add configChanges="uimode" to their manifest.
- if (appInfo.targetSdkVersion < O
+ if (info.applicationInfo.targetSdkVersion < O
&& requestedVrComponent != null
&& onlyVrUiModeChanged) {
configChanged |= CONFIG_UI_MODE;
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 6d902fcf5ea1..18a57ae17fda 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -786,7 +786,7 @@ class ActivityStack extends ConfigurationContainer {
&& !topActivity.noDisplay) {
// Inform the user that they are starting an app that may not work correctly in
// multi-window mode.
- final String packageName = topActivity.appInfo.packageName;
+ final String packageName = topActivity.info.applicationInfo.packageName;
mService.getTaskChangeNotificationController().notifyActivityForcedResizable(
topTask.taskId, FORCED_RESIZEABLE_REASON_SPLIT_SCREEN, packageName);
}
@@ -2976,7 +2976,8 @@ class ActivityStack extends ConfigurationContainer {
}
if (next.newIntents != null) {
- transaction.addCallback(NewIntentItem.obtain(next.newIntents));
+ transaction.addCallback(
+ NewIntentItem.obtain(next.newIntents, true /* resume */));
}
// Well the app will no longer be stopped.
@@ -3262,6 +3263,9 @@ class ActivityStack extends ConfigurationContainer {
// tell WindowManager that r is visible even though it is at the back of the stack.
r.setVisibility(true);
ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+ // Go ahead to execute app transition for this activity since the app transition
+ // will not be triggered through the resume channel.
+ getDisplay().mDisplayContent.executeAppTransition();
} else if (SHOW_APP_STARTING_PREVIEW && doShow) {
// Figure out if we are transitioning from another activity that is
// "has the same starting icon" as the next one. This allows the
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index cc508d44b92f..feb4a3653ced 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -761,10 +761,10 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
final int applicationInfoUid =
(r.info.applicationInfo != null) ? r.info.applicationInfo.uid : -1;
- if ((r.mUserId != proc.mUserId) || (r.appInfo.uid != applicationInfoUid)) {
+ if ((r.mUserId != proc.mUserId) || (r.info.applicationInfo.uid != applicationInfoUid)) {
Slog.wtf(TAG,
"User ID for activity changing for " + r
- + " appInfo.uid=" + r.appInfo.uid
+ + " appInfo.uid=" + r.info.applicationInfo.uid
+ " info.ai.uid=" + applicationInfoUid
+ " old=" + r.app + " new=" + proc);
}
@@ -2072,7 +2072,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
r.mLaunchTaskBehind = false;
mRecentTasks.add(task);
mService.getTaskChangeNotificationController().notifyTaskStackChanged();
- r.setVisibility(false);
+ stack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
// When launching tasks behind, update the last active time of the top task after the new
// task has been shown briefly
@@ -2462,7 +2462,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks {
return;
}
mService.getTaskChangeNotificationController().notifyActivityForcedResizable(
- task.taskId, reason, topActivity.appInfo.packageName);
+ task.taskId, reason, topActivity.info.applicationInfo.packageName);
}
void activityRelaunchedLocked(IBinder token) {
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index eda9d24ef3c5..54eb07f56983 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1684,7 +1684,8 @@ class ActivityStarter {
mService.mUgmInternal.grantUriPermissionFromIntent(mCallingUid, mStartActivity.packageName,
mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.mUserId);
mService.getPackageManagerInternalLocked().grantEphemeralAccess(
- mStartActivity.mUserId, mIntent, UserHandle.getAppId(mStartActivity.appInfo.uid),
+ mStartActivity.mUserId, mIntent,
+ UserHandle.getAppId(mStartActivity.info.applicationInfo.uid),
UserHandle.getAppId(mCallingUid));
if (newTask) {
EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, mStartActivity.mUserId,
@@ -1845,7 +1846,7 @@ class ActivityStarter {
// of this in the record so that we can skip it when trying to find
// the top running activity.
mDoResume = doResume;
- if (!doResume || !r.okToShowLocked()) {
+ if (!doResume || !r.okToShowLocked() || mLaunchTaskBehind) {
r.delayedResume = true;
mDoResume = false;
}
@@ -2679,7 +2680,8 @@ class ActivityStarter {
if (((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) == 0)
|| mPreferredDisplayId != DEFAULT_DISPLAY) {
- final boolean onTop = aOptions == null || !aOptions.getAvoidMoveToFront();
+ final boolean onTop =
+ (aOptions == null || !aOptions.getAvoidMoveToFront()) && !mLaunchTaskBehind;
final ActivityStack stack =
mRootActivityContainer.getLaunchStack(r, aOptions, task, onTop, mLaunchParams);
return stack;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index a55513317fee..971a24d13643 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -459,7 +459,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
boolean mSuppressResizeConfigChanges;
- private final UpdateConfigurationResult mTmpUpdateConfigurationResult =
+ final UpdateConfigurationResult mTmpUpdateConfigurationResult =
new UpdateConfigurationResult();
static final class UpdateConfigurationResult {
@@ -631,7 +631,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
/** If non-null, we are tracking the time the user spends in the currently focused app. */
AppTimeTracker mCurAppTimeTracker;
- private AppWarnings mAppWarnings;
+ AppWarnings mAppWarnings;
/**
* Packages that the user has asked to have run in screen size
@@ -3751,7 +3751,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
voiceInteractor);
long token = Binder.clearCallingIdentity();
try {
- startRunningVoiceLocked(voiceSession, activityToCallback.appInfo.uid);
+ startRunningVoiceLocked(voiceSession, activityToCallback.info.applicationInfo.uid);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -4118,8 +4118,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
final ActivityStack stack = r.getActivityStack();
stack.setPictureInPictureAspectRatio(aspectRatio);
stack.setPictureInPictureActions(actions);
- MetricsLoggerWrapper.logPictureInPictureEnter(mContext, r.appInfo.uid,
- r.shortComponentName, r.supportsEnterPipOnTaskSwitch);
+ MetricsLoggerWrapper.logPictureInPictureEnter(mContext,
+ r.info.applicationInfo.uid, r.shortComponentName,
+ r.supportsEnterPipOnTaskSwitch);
logPictureInPictureArgs(params);
}
};
@@ -4387,46 +4388,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
@Override
- public boolean updateDisplayOverrideConfiguration(Configuration values, int displayId) {
- mAmInternal.enforceCallingPermission(CHANGE_CONFIGURATION, "updateDisplayOverrideConfiguration()");
-
- synchronized (mGlobalLock) {
- // Check if display is initialized in AM.
- if (!mRootActivityContainer.isDisplayAdded(displayId)) {
- // Call might come when display is not yet added or has already been removed.
- if (DEBUG_CONFIGURATION) {
- Slog.w(TAG, "Trying to update display configuration for non-existing displayId="
- + displayId);
- }
- return false;
- }
-
- if (values == null && mWindowManager != null) {
- // sentinel: fetch the current configuration from the window manager
- values = mWindowManager.computeNewConfiguration(displayId);
- }
-
- if (mWindowManager != null) {
- final Message msg = PooledLambda.obtainMessage(
- ActivityManagerInternal::updateOomLevelsForDisplay, mAmInternal, displayId);
- mH.sendMessage(msg);
- }
-
- final long origId = Binder.clearCallingIdentity();
- try {
- if (values != null) {
- Settings.System.clearConfiguration(values);
- }
- updateDisplayOverrideConfigurationLocked(values, null /* starting */,
- false /* deferResume */, displayId, mTmpUpdateConfigurationResult);
- return mTmpUpdateConfigurationResult.changes != 0;
- } finally {
- Binder.restoreCallingIdentity(origId);
- }
- }
- }
-
- @Override
public boolean updateConfiguration(Configuration values) {
mAmInternal.enforceCallingPermission(CHANGE_CONFIGURATION, "updateConfiguration()");
@@ -5164,8 +5125,12 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
/** Update default (global) configuration and notify listeners about changes. */
- private int updateGlobalConfigurationLocked(@NonNull Configuration values, boolean initLocale,
+ int updateGlobalConfigurationLocked(@NonNull Configuration values, boolean initLocale,
boolean persistent, int userId, boolean deferResume) {
+
+ final ActivityDisplay defaultDisplay =
+ mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY);
+
mTempConfig.setTo(getGlobalConfiguration());
final int changes = mTempConfig.updateFrom(values);
if (changes == 0) {
@@ -5173,7 +5138,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
// setting WindowManagerService.mWaitingForConfig to true, it is important that we call
// performDisplayOverrideConfigUpdate in order to send the new display configuration
// (even if there are no actual changes) to unfreeze the window.
- performDisplayOverrideConfigUpdate(values, deferResume, DEFAULT_DISPLAY);
+ defaultDisplay.performDisplayOverrideConfigUpdate(values, deferResume);
return 0;
}
@@ -5271,79 +5236,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
// Override configuration of the default display duplicates global config, so we need to
// update it also. This will also notify WindowManager about changes.
- performDisplayOverrideConfigUpdate(mRootActivityContainer.getConfiguration(), deferResume,
- DEFAULT_DISPLAY);
-
- return changes;
- }
-
- boolean updateDisplayOverrideConfigurationLocked(Configuration values, ActivityRecord starting,
- boolean deferResume, int displayId) {
- return updateDisplayOverrideConfigurationLocked(values, starting, deferResume /* deferResume */,
- displayId, null /* result */);
- }
+ defaultDisplay.performDisplayOverrideConfigUpdate(mRootActivityContainer.getConfiguration(),
+ deferResume);
- /**
- * Updates override configuration specific for the selected display. If no config is provided,
- * new one will be computed in WM based on current display info.
- */
- boolean updateDisplayOverrideConfigurationLocked(Configuration values,
- ActivityRecord starting, boolean deferResume, int displayId,
- ActivityTaskManagerService.UpdateConfigurationResult result) {
- int changes = 0;
- boolean kept = true;
-
- if (mWindowManager != null) {
- mWindowManager.deferSurfaceLayout();
- }
- try {
- if (values != null) {
- if (displayId == DEFAULT_DISPLAY) {
- // Override configuration of the default display duplicates global config, so
- // we're calling global config update instead for default display. It will also
- // apply the correct override config.
- changes = updateGlobalConfigurationLocked(values, false /* initLocale */,
- false /* persistent */, UserHandle.USER_NULL /* userId */, deferResume);
- } else {
- changes = performDisplayOverrideConfigUpdate(values, deferResume, displayId);
- }
- }
-
- kept = ensureConfigAndVisibilityAfterUpdate(starting, changes);
- } finally {
- if (mWindowManager != null) {
- mWindowManager.continueSurfaceLayout();
- }
- }
-
- if (result != null) {
- result.changes = changes;
- result.activityRelaunched = !kept;
- }
- return kept;
- }
-
- private int performDisplayOverrideConfigUpdate(Configuration values, boolean deferResume,
- int displayId) {
- mTempConfig.setTo(mRootActivityContainer.getDisplayOverrideConfiguration(displayId));
- final int changes = mTempConfig.updateFrom(values);
- if (changes != 0) {
- Slog.i(TAG, "Override config changes=" + Integer.toHexString(changes) + " "
- + mTempConfig + " for displayId=" + displayId);
- mRootActivityContainer.setDisplayOverrideConfiguration(mTempConfig, displayId);
-
- final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
- if (isDensityChange && displayId == DEFAULT_DISPLAY) {
- mAppWarnings.onDensityChanged();
-
- // Post message to start process to avoid possible deadlock of calling into AMS with
- // the ATMS lock held.
- final Message msg = PooledLambda.obtainMessage(
- ActivityManagerInternal::killAllBackgroundProcessesExcept, mAmInternal,
- N, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
- mH.sendMessage(msg);
- }
- }
return changes;
}
@@ -5785,7 +5680,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
/** Applies latest configuration and/or visibility updates if needed. */
- private boolean ensureConfigAndVisibilityAfterUpdate(ActivityRecord starting, int changes) {
+ boolean ensureConfigAndVisibilityAfterUpdate(ActivityRecord starting, int changes) {
boolean kept = true;
final ActivityStack mainStack = mRootActivityContainer.getTopDisplayFocusedStack();
// mainStack is null during startup.
diff --git a/services/core/java/com/android/server/wm/AppWarnings.java b/services/core/java/com/android/server/wm/AppWarnings.java
index 6c3fbc1f4160..21b68095ef67 100644
--- a/services/core/java/com/android/server/wm/AppWarnings.java
+++ b/services/core/java/com/android/server/wm/AppWarnings.java
@@ -105,7 +105,8 @@ class AppWarnings {
public void showUnsupportedDisplaySizeDialogIfNeeded(ActivityRecord r) {
final Configuration globalConfig = mAtm.getGlobalConfiguration();
if (globalConfig.densityDpi != DisplayMetrics.DENSITY_DEVICE_STABLE
- && r.appInfo.requiresSmallestWidthDp > globalConfig.smallestScreenWidthDp) {
+ && r.info.applicationInfo.requiresSmallestWidthDp
+ > globalConfig.smallestScreenWidthDp) {
mUiHandler.showUnsupportedDisplaySizeDialog(r);
}
}
@@ -116,7 +117,8 @@ class AppWarnings {
* @param r activity record for which the warning may be displayed
*/
public void showUnsupportedCompileSdkDialogIfNeeded(ActivityRecord r) {
- if (r.appInfo.compileSdkVersion == 0 || r.appInfo.compileSdkVersionCodename == null) {
+ if (r.info.applicationInfo.compileSdkVersion == 0
+ || r.info.applicationInfo.compileSdkVersionCodename == null) {
// We don't know enough about this package. Abort!
return;
}
@@ -135,14 +137,16 @@ class AppWarnings {
// the application was built OR both are pre-release with the same SDK_INT but different
// codenames (e.g. simultaneous pre-release development), then we're likely to run into
// compatibility issues. Warn the user and offer to check for an update.
- final int compileSdk = r.appInfo.compileSdkVersion;
+ final int compileSdk = r.info.applicationInfo.compileSdkVersion;
final int platformSdk = Build.VERSION.SDK_INT;
- final boolean isCompileSdkPreview = !"REL".equals(r.appInfo.compileSdkVersionCodename);
+ final boolean isCompileSdkPreview =
+ !"REL".equals(r.info.applicationInfo.compileSdkVersionCodename);
final boolean isPlatformSdkPreview = !"REL".equals(Build.VERSION.CODENAME);
if ((isCompileSdkPreview && compileSdk < platformSdk)
|| (isPlatformSdkPreview && platformSdk < compileSdk)
|| (isCompileSdkPreview && isPlatformSdkPreview && platformSdk == compileSdk
- && !Build.VERSION.CODENAME.equals(r.appInfo.compileSdkVersionCodename))) {
+ && !Build.VERSION.CODENAME.equals(
+ r.info.applicationInfo.compileSdkVersionCodename))) {
mUiHandler.showUnsupportedCompileSdkDialog(r);
}
}
@@ -153,7 +157,7 @@ class AppWarnings {
* @param r activity record for which the warning may be displayed
*/
public void showDeprecatedTargetDialogIfNeeded(ActivityRecord r) {
- if (r.appInfo.targetSdkVersion < Build.VERSION.MIN_SUPPORTED_TARGET_SDK_INT) {
+ if (r.info.applicationInfo.targetSdkVersion < Build.VERSION.MIN_SUPPORTED_TARGET_SDK_INT) {
mUiHandler.showDeprecatedTargetDialog(r);
}
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 03cae429904f..8007c0f316e0 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -33,6 +33,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE;
+import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND;
import static android.view.WindowManager.TRANSIT_UNSET;
import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
@@ -79,6 +80,7 @@ import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
import static com.android.server.wm.WindowManagerService.logWithStack;
import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY;
+import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
@@ -540,6 +542,18 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
// If the app was already visible, don't reset the waitingToShow state.
if (isHidden()) {
waitingToShow = true;
+
+ // Let's reset the draw state in order to prevent the starting window to be
+ // immediately dismissed when the app still has the surface.
+ forAllWindows(w -> {
+ if (w.mWinAnimator.mDrawState == HAS_DRAWN) {
+ w.mWinAnimator.resetDrawState();
+
+ // Force add to mResizingWindows, so that we are guaranteed to get
+ // another reportDrawn callback.
+ w.resetLastContentInsets();
+ }
+ }, true /* traverseTopToBottom */);
}
}
@@ -568,8 +582,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
displayContent.mClosingApps.add(this);
mEnteringAnimation = false;
}
- if (appTransition.getAppTransition()
- == WindowManager.TRANSIT_TASK_OPEN_BEHIND) {
+ if (appTransition.getAppTransition() == TRANSIT_TASK_OPEN_BEHIND) {
// We're launchingBehind, add the launching activity to mOpeningApps.
final WindowState win = getDisplayContent().findFocusedWindow();
if (win != null) {
@@ -580,7 +593,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
+ " adding " + focusedToken + " to mOpeningApps");
}
// Force animation to be loaded.
- focusedToken.setHidden(true);
displayContent.mOpeningApps.add(focusedToken);
}
}
@@ -607,9 +619,14 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
// * token is transitioning visibility state
// * or the token was marked as hidden and is exiting before we had a chance to play the
// transition animation
- // * or this is an opening app and windows are being replaced.
+ // * or this is an opening app and windows are being replaced
+ // * or the token is the opening app and visible while opening task behind existing one.
+ final DisplayContent displayContent = getDisplayContent();
boolean visibilityChanged = false;
- if (isHidden() == visible || (isHidden() && mIsExiting) || (visible && waitingForReplacement())) {
+ if (isHidden() == visible || (isHidden() && mIsExiting)
+ || (visible && waitingForReplacement())
+ || (visible && displayContent.mOpeningApps.contains(this)
+ && displayContent.mAppTransition.getAppTransition() == TRANSIT_TASK_OPEN_BEHIND)) {
final AccessibilityController accessibilityController =
mWmService.mAccessibilityController;
boolean changed = false;
@@ -662,13 +679,13 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
}
if (changed) {
- getDisplayContent().getInputMonitor().setUpdateInputWindowsNeededLw();
+ displayContent.getInputMonitor().setUpdateInputWindowsNeededLw();
if (performLayout) {
mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
false /*updateInputWindows*/);
mWmService.mWindowPlacerLocked.performSurfacePlacement();
}
- getDisplayContent().getInputMonitor().updateInputWindowsLw(false /*force*/);
+ displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
}
}
mUseTransferredAnimation = false;
@@ -707,14 +724,14 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
setClientHidden(!visible);
}
- if (!getDisplayContent().mClosingApps.contains(this)
- && !getDisplayContent().mOpeningApps.contains(this)) {
+ if (!displayContent.mClosingApps.contains(this)
+ && !displayContent.mOpeningApps.contains(this)) {
// The token is not closing nor opening, so even if there is an animation set, that
// doesn't mean that it goes through the normal app transition cycle so we have
// to inform the docked controller about visibility change.
// TODO(multi-display): notify docked divider on all displays where visibility was
// affected.
- getDisplayContent().getDockedDividerController().notifyAppVisibilityChanged();
+ displayContent.getDockedDividerController().notifyAppVisibilityChanged();
// Take the screenshot before possibly hiding the WSA, otherwise the screenshot
// will not be taken.
@@ -731,7 +748,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
// no animation but there will still be a transition set.
// We still need to delay hiding the surface such that it
// can be synchronized with showing the next surface in the transition.
- if (isHidden() && !delayed && !getDisplayContent().mAppTransition.isTransitionSet()) {
+ if (isHidden() && !delayed && !displayContent.mAppTransition.isTransitionSet()) {
SurfaceControl.openTransaction();
for (int i = mChildren.size() - 1; i >= 0; i--) {
mChildren.get(i).mWinAnimator.hide("immediately hidden");
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4d548bf5ea63..e2d592826a3a 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -140,7 +140,7 @@ import static com.android.server.wm.WindowManagerService.logSurface;
import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
-import static com.android.server.wm.utils.RegionUtils.forEachRect;
+import static com.android.server.wm.utils.RegionUtils.forEachRectReverse;
import static com.android.server.wm.utils.RegionUtils.rectListToRegion;
import android.animation.AnimationHandler;
@@ -1213,10 +1213,29 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
/** Notify the configuration change of this display. */
- void sendNewConfiguration() {
+ void postNewConfigurationToHandler() {
mWmService.mH.obtainMessage(SEND_NEW_CONFIGURATION, this).sendToTarget();
}
+ void sendNewConfiguration() {
+ synchronized (mWmService.mGlobalLock) {
+ final boolean configUpdated = mAcitvityDisplay
+ .updateDisplayOverrideConfigurationLocked();
+ if (!configUpdated) {
+ // Something changed (E.g. device rotation), but no configuration update is needed.
+ // E.g. changing device rotation by 180 degrees. Go ahead and perform surface
+ // placement to unfreeze the display since we froze it when the rotation was updated
+ // in DisplayContent#updateRotationUnchecked.
+ if (mWaitingForConfig) {
+ mWaitingForConfig = false;
+ mWmService.mLastFinishedFreezeSource = "config-unchanged";
+ setLayoutNeeded();
+ mWmService.mWindowPlacerLocked.performSurfacePlacement();
+ }
+ }
+ }
+ }
+
@Override
boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
ConfigurationContainer requestingContainer) {
@@ -1232,8 +1251,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
if (handled && requestingContainer instanceof ActivityRecord) {
final ActivityRecord activityRecord = (ActivityRecord) requestingContainer;
- final boolean kept = mWmService.mAtmService.updateDisplayOverrideConfigurationLocked(
- config, activityRecord, false /* deferResume */, getDisplayId());
+ final boolean kept = mAcitvityDisplay.updateDisplayOverrideConfigurationLocked(
+ config, activityRecord, false /* deferResume */, null /* result */);
activityRecord.frozenBeforeDestroy = true;
if (!kept) {
mWmService.mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities();
@@ -1241,8 +1260,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
} else {
// We have a new configuration to push so we need to update ATMS for now.
// TODO: Clean up display configuration push between ATMS and WMS after unification.
- mWmService.mAtmService.updateDisplayOverrideConfigurationLocked(
- config, null /* starting */, false /* deferResume */, getDisplayId());
+ mAcitvityDisplay.updateDisplayOverrideConfigurationLocked(
+ config, null /* starting */, false /* deferResume */, null);
}
return handled;
}
@@ -1332,7 +1351,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
boolean updateRotationAndSendNewConfigIfNeeded() {
final boolean changed = updateRotationUnchecked(false /* forceUpdate */);
if (changed) {
- sendNewConfiguration();
+ postNewConfigurationToHandler();
}
return changed;
}
@@ -1351,7 +1370,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
* Update rotation of the DisplayContent with an option to force the update. This updates
* the container's perception of rotation and, depending on the top activities, will freeze
* the screen or start seamless rotation. The display itself gets rotated in
- * {@link #applyRotationLocked} during {@link WindowManagerService#sendNewConfiguration}.
+ * {@link #applyRotationLocked} during {@link DisplayContent#sendNewConfiguration}.
*
* @param forceUpdate Force the rotation update. Sometimes in WM we might skip updating
* orientation because we're waiting for some rotation to finish or display
@@ -3711,7 +3730,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
if (updateOrientationFromAppTokens()) {
setLayoutNeeded();
- sendNewConfiguration();
+ postNewConfigurationToHandler();
}
}
@@ -5162,7 +5181,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
final int[] remainingLeftRight =
{mSystemGestureExclusionLimit, mSystemGestureExclusionLimit};
- // Traverse all windows bottom up to assemble the gesture exclusion rects.
+ // Traverse all windows top down to assemble the gesture exclusion rects.
// For each window, we only take the rects that fall within its touchable region.
forAllWindows(w -> {
if (w.cantReceiveTouchInput() || !w.isVisible()
@@ -5170,23 +5189,25 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|| unhandled.isEmpty()) {
return;
}
- final boolean modal =
- (w.mAttrs.flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0;
// Get the touchable region of the window, and intersect with where the screen is still
// touchable, i.e. touchable regions on top are not covering it yet.
- w.getTouchableRegion(touchableRegion);
+ w.getEffectiveTouchableRegion(touchableRegion);
touchableRegion.op(unhandled, Op.INTERSECT);
- rectListToRegion(w.getSystemGestureExclusion(), local);
+ if (w.isImplicitlyExcludingAllSystemGestures()) {
+ local.set(touchableRegion);
+ } else {
+ rectListToRegion(w.getSystemGestureExclusion(), local);
- // Transform to display coordinates
- local.scale(w.mGlobalScale);
- final Rect frame = w.getWindowFrames().mFrame;
- local.translate(frame.left, frame.top);
+ // Transform to display coordinates
+ local.scale(w.mGlobalScale);
+ final Rect frame = w.getWindowFrames().mFrame;
+ local.translate(frame.left, frame.top);
- // A window can only exclude system gestures where it is actually touchable
- local.op(touchableRegion, Op.INTERSECT);
+ // A window can only exclude system gestures where it is actually touchable
+ local.op(touchableRegion, Op.INTERSECT);
+ }
// Apply restriction if necessary.
if (needsGestureExclusionRestrictions(w, mLastDispatchedSystemUiVisibility)) {
@@ -5245,13 +5266,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
r.op(edge, Op.INTERSECT);
final int[] remaining = {limit};
- forEachRect(r, rect -> {
+ forEachRectReverse(r, rect -> {
if (remaining[0] <= 0) {
return;
}
final int height = rect.height();
if (height > remaining[0]) {
- rect.bottom = rect.top + remaining[0];
+ rect.top = rect.bottom - remaining[0];
}
remaining[0] -= height;
global.op(rect, Op.UNION);
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 1d76a71aaea1..b1bc21977405 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -569,7 +569,6 @@ public class DockedStackDividerController {
mMaximizeMeetFraction = getClipRevealMeetFraction(stack);
animDuration = (long) (mAnimationDuration * mMaximizeMeetFraction);
}
- mService.mAtmInternal.notifyDockedStackMinimizedChanged(minimizedDock);
final int size = mDockedStackListeners.beginBroadcast();
for (int i = 0; i < size; ++i) {
final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
@@ -581,6 +580,9 @@ public class DockedStackDividerController {
}
}
mDockedStackListeners.finishBroadcast();
+ // Only notify ATM after we update the remote listeners, otherwise it may trigger another
+ // minimize change, which would lead to an inversion of states send to the listeners
+ mService.mAtmInternal.notifyDockedStackMinimizedChanged(minimizedDock);
}
void notifyDockSideChanged(int newDockSide) {
diff --git a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java b/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java
index c0f53b819125..315de91f1b03 100644
--- a/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java
+++ b/services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java
@@ -16,60 +16,102 @@
package com.android.server.wm;
+import static android.provider.DeviceConfig.WindowManager.KEY_HIGH_REFRESH_RATE_BLACKLIST;
+
import android.annotation.NonNull;
-import android.os.SystemProperties;
+import android.annotation.Nullable;
+import android.content.res.Resources;
+import android.provider.DeviceConfig;
import android.util.ArraySet;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
+
+import java.io.PrintWriter;
+import java.util.concurrent.Executor;
/**
* A Blacklist for packages that should force the display out of high refresh rate.
*/
class HighRefreshRateBlacklist {
- private static final String SYSPROP_KEY = "ro.window_manager.high_refresh_rate_blacklist";
- private static final String SYSPROP_KEY_LENGTH_SUFFIX = "_length";
- private static final String SYSPROP_KEY_ENTRY_SUFFIX = "_entry";
- private static final int MAX_ENTRIES = 50;
+ private final ArraySet<String> mBlacklistedPackages = new ArraySet<>();
+ @NonNull
+ private final String[] mDefaultBlacklist;
+ private final Object mLock = new Object();
- private ArraySet<String> mBlacklistedPackages = new ArraySet<>();
-
- static HighRefreshRateBlacklist create() {
- return new HighRefreshRateBlacklist(new SystemPropertyGetter() {
+ static HighRefreshRateBlacklist create(@NonNull Resources r) {
+ return new HighRefreshRateBlacklist(r, new DeviceConfigInterface() {
@Override
- public int getInt(String key, int def) {
- return SystemProperties.getInt(key, def);
+ public @Nullable String getProperty(@NonNull String namespace, @NonNull String name) {
+ return DeviceConfig.getProperty(namespace, name);
}
-
- @Override
- public String get(String key) {
- return SystemProperties.get(key);
+ public void addOnPropertiesChangedListener(@NonNull String namespace,
+ @NonNull Executor executor,
+ @NonNull DeviceConfig.OnPropertiesChangedListener listener) {
+ DeviceConfig.addOnPropertiesChangedListener(namespace, executor, listener);
}
});
}
@VisibleForTesting
- HighRefreshRateBlacklist(SystemPropertyGetter propertyGetter) {
+ HighRefreshRateBlacklist(Resources r, DeviceConfigInterface deviceConfig) {
+ mDefaultBlacklist = r.getStringArray(R.array.config_highRefreshRateBlacklist);
+ deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ BackgroundThread.getExecutor(), new OnPropertiesChangedListener());
+ final String property = deviceConfig.getProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ KEY_HIGH_REFRESH_RATE_BLACKLIST);
+ updateBlacklist(property);
+ }
- // Read and populate the blacklist
- final int length = Math.min(
- propertyGetter.getInt(SYSPROP_KEY + SYSPROP_KEY_LENGTH_SUFFIX, 0),
- MAX_ENTRIES);
- for (int i = 1; i <= length; i++) {
- final String packageName = propertyGetter.get(
- SYSPROP_KEY + SYSPROP_KEY_ENTRY_SUFFIX + i);
- if (!packageName.isEmpty()) {
- mBlacklistedPackages.add(packageName);
+ private void updateBlacklist(@Nullable String property) {
+ synchronized (mLock) {
+ mBlacklistedPackages.clear();
+ if (property != null) {
+ String[] packages = property.split(",");
+ for (String pkg : packages) {
+ String pkgName = pkg.trim();
+ if (!pkgName.isEmpty()) {
+ mBlacklistedPackages.add(pkgName);
+ }
+ }
+ } else {
+ // If there's no config, or the config has been deleted, fallback to the device's
+ // default blacklist
+ for (String pkg : mDefaultBlacklist) {
+ mBlacklistedPackages.add(pkg);
+ }
}
}
}
boolean isBlacklisted(String packageName) {
- return mBlacklistedPackages.contains(packageName);
+ synchronized (mLock) {
+ return mBlacklistedPackages.contains(packageName);
+ }
+ }
+ void dump(PrintWriter pw) {
+ pw.println("High Refresh Rate Blacklist");
+ pw.println(" Packages:");
+ synchronized (mLock) {
+ for (String pkg : mBlacklistedPackages) {
+ pw.println(" " + pkg);
+ }
+ }
}
- interface SystemPropertyGetter {
- int getInt(String key, int def);
- @NonNull String get(String key);
+ interface DeviceConfigInterface {
+ @Nullable String getProperty(@NonNull String namespace, @NonNull String name);
+ void addOnPropertiesChangedListener(@NonNull String namespace, @NonNull Executor executor,
+ @NonNull DeviceConfig.OnPropertiesChangedListener listener);
+ }
+
+ private class OnPropertiesChangedListener implements DeviceConfig.OnPropertiesChangedListener {
+ public void onPropertiesChanged(@NonNull DeviceConfig.Properties properties) {
+ updateBlacklist(
+ properties.getString(KEY_HIGH_REFRESH_RATE_BLACKLIST, null /*default*/));
+ }
}
}
+
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index 6b500967f429..b16d9564ea7a 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -133,7 +133,7 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
@Override
public void notifyConfigurationChanged() {
// TODO(multi-display): Notify proper displays that are associated with this input device.
- mService.sendNewConfiguration(DEFAULT_DISPLAY);
+ mService.mRoot.getDisplayContent(DEFAULT_DISPLAY).sendNewConfiguration();
synchronized (mInputDevicesReadyMonitor) {
if (!mInputDevicesReady) {
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index af729317392b..ef0049b068f4 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -350,7 +350,7 @@ class PinnedStackController {
// Calculate the stack bounds in the new orientation to the same same fraction along the
// rotated movement bounds.
final Rect postChangeMovementBounds = getMovementBounds(postChangeStackBounds,
- false /* adjustForIme */, false /* adjustForShelf */);
+ false /* adjustForIme */);
mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds,
snapFraction);
if (mIsMinimized) {
@@ -540,8 +540,7 @@ class PinnedStackController {
*/
private Rect getMovementBounds(Rect stackBounds) {
synchronized (mService.mGlobalLock) {
- return getMovementBounds(stackBounds, true /* adjustForIme */,
- true /* adjustForShelf */);
+ return getMovementBounds(stackBounds, true /* adjustForIme */);
}
}
@@ -549,15 +548,16 @@ class PinnedStackController {
* @return the movement bounds for the given {@param stackBounds} and the current state of the
* controller.
*/
- private Rect getMovementBounds(Rect stackBounds, boolean adjustForIme, boolean adjustForShelf) {
+ private Rect getMovementBounds(Rect stackBounds, boolean adjustForIme) {
synchronized (mService.mGlobalLock) {
final Rect movementBounds = new Rect();
getInsetBounds(movementBounds);
- // Apply the movement bounds adjustments based on the current state
+ // Apply the movement bounds adjustments based on the current state.
+ // Note that shelf offset does not affect the movement bounds here
+ // since it's been taken care of in system UI.
mSnapAlgorithm.getMovementBounds(stackBounds, movementBounds, movementBounds,
- Math.max((adjustForIme && mIsImeShowing) ? mImeHeight : 0,
- (adjustForShelf && mIsShelfShowing) ? mShelfHeight : 0));
+ (adjustForIme && mIsImeShowing) ? mImeHeight : 0);
return movementBounds;
}
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index c03dabe660ad..163be1ebd0ed 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -24,6 +24,7 @@ import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowManager.DOCKED_INVALID;
import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
import static com.android.server.wm.AnimationAdapterProto.REMOTE;
@@ -651,8 +652,8 @@ public class RecentsAnimationController implements DeathRecipient {
}
boolean isWallpaperVisible(WindowState w) {
- return w != null && w.mAppToken != null && mTargetAppToken == w.mAppToken
- && isTargetOverWallpaper();
+ return w != null && w.mAttrs.type == TYPE_BASE_APPLICATION && w.mAppToken != null
+ && mTargetAppToken == w.mAppToken && isTargetOverWallpaper();
}
/**
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index d58c61368f9a..66d42db9b4dd 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -317,11 +317,6 @@ class RootActivityContainer extends ConfigurationContainer
return activityDisplay;
}
- /** Check if display with specified id is added to the list. */
- boolean isDisplayAdded(int displayId) {
- return getActivityDisplayOrCreate(displayId) != null;
- }
-
ActivityRecord getDefaultDisplayHomeActivity() {
return getDefaultDisplayHomeActivityForUser(mCurrentUser);
}
@@ -656,9 +651,13 @@ class RootActivityContainer extends ConfigurationContainer
starting.frozenBeforeDestroy = true;
}
- // Update the configuration of the activities on the display.
- return mService.updateDisplayOverrideConfigurationLocked(config, starting, deferResume,
- displayId);
+ if (displayContent != null && displayContent.mAcitvityDisplay != null) {
+ // Update the configuration of the activities on the display.
+ return displayContent.mAcitvityDisplay.updateDisplayOverrideConfigurationLocked(config,
+ starting, deferResume, null /* result */);
+ } else {
+ return true;
+ }
}
/**
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index e2d0acd37013..0d18b30c1b0b 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -423,8 +423,8 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier {
* @return {@code true} if it should be forced to maximize; {@code false} otherwise.
*/
private boolean isTaskForcedMaximized(@NonNull ActivityRecord root) {
- if (root.appInfo.targetSdkVersion < Build.VERSION_CODES.DONUT
- || (root.appInfo.flags & SUPPORTS_SCREEN_RESIZEABLE_MASK) == 0) {
+ if (root.info.applicationInfo.targetSdkVersion < Build.VERSION_CODES.DONUT
+ || (root.info.applicationInfo.flags & SUPPORTS_SCREEN_RESIZEABLE_MASK) == 0) {
return true;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 54f712cc6cef..f52bde9a035c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -32,6 +32,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.SYSTEM_UID;
import static android.os.Process.myPid;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE;
import static android.provider.DeviceConfig.WindowManager.KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP;
import static android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -846,6 +847,7 @@ public class WindowManagerService extends IWindowManager.Stub
boolean mWindowsChanged = false;
int mSystemGestureExclusionLimitDp;
+ boolean mSystemGestureExcludedByPreQStickyImmersive;
public interface WindowChangeListener {
public void windowsChanged();
@@ -854,7 +856,7 @@ public class WindowManagerService extends IWindowManager.Stub
final Configuration mTempConfiguration = new Configuration();
- final HighRefreshRateBlacklist mHighRefreshRateBlacklist = HighRefreshRateBlacklist.create();
+ final HighRefreshRateBlacklist mHighRefreshRateBlacklist;
// If true, only the core apps and services are being launched because the device
// is in a special boot mode, such as being encrypted or waiting for a decryption password.
@@ -1141,16 +1143,26 @@ public class WindowManagerService extends IWindowManager.Stub
this, mInputManager, mActivityTaskManager, mH.getLooper());
mDragDropController = new DragDropController(this, mH.getLooper());
+ mHighRefreshRateBlacklist = HighRefreshRateBlacklist.create(context.getResources());
+
mSystemGestureExclusionLimitDp = Math.max(MIN_GESTURE_EXCLUSION_LIMIT_DP,
DeviceConfig.getInt(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0));
+ mSystemGestureExcludedByPreQStickyImmersive =
+ DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false);
DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_WINDOW_MANAGER,
new HandlerExecutor(mH), properties -> {
synchronized (mGlobalLock) {
final int exclusionLimitDp = Math.max(MIN_GESTURE_EXCLUSION_LIMIT_DP,
properties.getInt(KEY_SYSTEM_GESTURE_EXCLUSION_LIMIT_DP, 0));
- if (mSystemGestureExclusionLimitDp != exclusionLimitDp) {
+ final boolean excludedByPreQSticky = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ KEY_SYSTEM_GESTURES_EXCLUDED_BY_PRE_Q_STICKY_IMMERSIVE, false);
+ if (mSystemGestureExcludedByPreQStickyImmersive != excludedByPreQSticky
+ || mSystemGestureExclusionLimitDp != exclusionLimitDp) {
mSystemGestureExclusionLimitDp = exclusionLimitDp;
+ mSystemGestureExcludedByPreQStickyImmersive = excludedByPreQSticky;
mRoot.forAllDisplays(DisplayContent::updateSystemGestureExclusionLimit);
}
}
@@ -1597,10 +1609,10 @@ public class WindowManagerService extends IWindowManager.Stub
if (win.isVisibleOrAdding() && displayContent.updateOrientationFromAppTokens()) {
reportNewConfig = true;
}
- }
- if (reportNewConfig) {
- sendNewConfiguration(displayId);
+ if (reportNewConfig) {
+ displayContent.sendNewConfiguration();
+ }
}
Binder.restoreCallingIdentity(origId);
@@ -1638,7 +1650,7 @@ public class WindowManagerService extends IWindowManager.Stub
final Display display = mDisplayManager.getDisplay(displayId);
if (display != null) {
- displayContent = mRoot.createDisplayContent(display, null /* controller */);
+ displayContent = mRoot.createDisplayContent(display, null /* activityDisplay */);
}
}
@@ -2280,13 +2292,15 @@ public class WindowManagerService extends IWindowManager.Stub
Slog.v(TAG_WM, "Relayout complete " + win + ": outFrame=" + outFrame.toShortString());
}
win.mInRelayout = false;
- }
- if (configChanged) {
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "relayoutWindow: sendNewConfiguration");
- sendNewConfiguration(displayId);
- Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ if (configChanged) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
+ "relayoutWindow: postNewConfigurationToHandler");
+ displayContent.sendNewConfiguration();
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ }
}
+
Binder.restoreCallingIdentity(origId);
return result;
}
@@ -3737,7 +3751,7 @@ public class WindowManagerService extends IWindowManager.Stub
layoutNeeded = true;
}
if (rotationChanged || alwaysSendConfiguration) {
- displayContent.sendNewConfiguration();
+ displayContent.postNewConfigurationToHandler();
}
}
@@ -4279,34 +4293,6 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- /**
- * Instruct the Activity Manager to fetch and update the current display's configuration and
- * broadcast them to config-changed listeners if appropriate.
- * NOTE: Can't be called with the window manager lock held since it call into activity manager.
- */
- void sendNewConfiguration(int displayId) {
- try {
- final boolean configUpdated = mActivityTaskManager.updateDisplayOverrideConfiguration(
- null /* values */, displayId);
- if (!configUpdated) {
- // Something changed (E.g. device rotation), but no configuration update is needed.
- // E.g. changing device rotation by 180 degrees. Go ahead and perform surface
- // placement to unfreeze the display since we froze it when the rotation was updated
- // in DisplayContent#updateRotationUnchecked.
- synchronized (mGlobalLock) {
- final DisplayContent dc = mRoot.getDisplayContent(displayId);
- if (dc != null && dc.mWaitingForConfig) {
- dc.mWaitingForConfig = false;
- mLastFinishedFreezeSource = "config-unchanged";
- dc.setLayoutNeeded();
- mWindowPlacerLocked.performSurfacePlacement();
- }
- }
- }
- } catch (RemoteException e) {
- }
- }
-
public Configuration computeNewConfiguration(int displayId) {
synchronized (mGlobalLock) {
return computeNewConfigurationLocked(displayId);
@@ -4730,7 +4716,7 @@ public class WindowManagerService extends IWindowManager.Stub
final DisplayContent displayContent = (DisplayContent) msg.obj;
removeMessages(SEND_NEW_CONFIGURATION, displayContent);
if (displayContent.isReady()) {
- sendNewConfiguration(displayContent.getDisplayId());
+ displayContent.sendNewConfiguration();
} else {
// Message could come after display has already been removed.
if (DEBUG_CONFIGURATION) {
@@ -5214,7 +5200,7 @@ public class WindowManagerService extends IWindowManager.Stub
displayContent.mWaitingForConfig = true;
startFreezingDisplayLocked(0 /* exitAnim */,
0 /* enterAnim */, displayContent);
- displayContent.sendNewConfiguration();
+ displayContent.postNewConfigurationToHandler();
}
mWindowPlacerLocked.performSurfacePlacement();
@@ -5561,7 +5547,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (configChanged) {
- displayContent.sendNewConfiguration();
+ displayContent.postNewConfigurationToHandler();
}
mLatencyTracker.onActionEnd(ACTION_ROTATE_SCREEN);
}
@@ -5913,6 +5899,12 @@ public class WindowManagerService extends IWindowManager.Stub
mRoot.dumpTokens(pw, dumpAll);
}
+
+ private void dumpHighRefreshRateBlacklist(PrintWriter pw) {
+ pw.println("WINDOW MANAGER HIGH REFRESH RATE BLACKLIST (dumpsys window refresh)");
+ mHighRefreshRateBlacklist.dump(pw);
+ }
+
private void dumpTraceStatus(PrintWriter pw) {
pw.println("WINDOW MANAGER TRACE (dumpsys window trace)");
pw.print(mWindowTracing.getStatus() + "\n");
@@ -6313,6 +6305,9 @@ public class WindowManagerService extends IWindowManager.Stub
} else if ("trace".equals(cmd)) {
dumpTraceStatus(pw);
return;
+ } else if ("refresh".equals(cmd)) {
+ dumpHighRefreshRateBlacklist(pw);
+ return;
} else {
// Dumping a single name?
if (!dumpWindows(pw, cmd, args, opti, dumpAll)) {
@@ -6368,6 +6363,10 @@ public class WindowManagerService extends IWindowManager.Stub
pw.println(separator);
}
dumpTraceStatus(pw);
+ if (dumpAll) {
+ pw.println(separator);
+ }
+ dumpHighRefreshRateBlacklist(pw);
}
}
@@ -6874,7 +6873,7 @@ public class WindowManagerService extends IWindowManager.Stub
final long origId = Binder.clearCallingIdentity();
try {
// direct call since lock is shared.
- sendNewConfiguration(displayId);
+ displayContent.sendNewConfiguration();
} finally {
Binder.restoreCallingIdentity(origId);
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index bf874be41c5b..8b1baebbbbc0 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -24,6 +24,8 @@ import static android.os.PowerManager.DRAW_WAKE_LOCK;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.SurfaceControl.Transaction;
+import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
@@ -155,6 +157,7 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Binder;
+import android.os.Build;
import android.os.Debug;
import android.os.IBinder;
import android.os.PowerManager;
@@ -667,6 +670,15 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return true;
}
+ boolean isImplicitlyExcludingAllSystemGestures() {
+ final int immersiveStickyFlags =
+ SYSTEM_UI_FLAG_HIDE_NAVIGATION | SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+ final boolean immersiveSticky =
+ (mSystemUiVisibility & immersiveStickyFlags) == immersiveStickyFlags;
+ return immersiveSticky && mWmService.mSystemGestureExcludedByPreQStickyImmersive
+ && mAppToken != null && mAppToken.mTargetSdk < Build.VERSION_CODES.Q;
+ }
+
interface PowerManagerWrapper {
void wakeUp(long time, @WakeReason int reason, String details);
@@ -2051,7 +2063,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (wasVisible) {
final DisplayContent displayContent = getDisplayContent();
if (displayContent.updateOrientationFromAppTokens()) {
- displayContent.sendNewConfiguration();
+ displayContent.postNewConfigurationToHandler();
}
}
mWmService.updateFocusedWindowLocked(isFocused()
@@ -3018,6 +3030,25 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
subtractTouchExcludeRegionIfNeeded(outRegion);
}
+ /**
+ * Get the effective touchable region in global coordinates.
+ *
+ * In contrast to {@link #getTouchableRegion}, this takes into account
+ * {@link WindowManager.LayoutParams#FLAG_NOT_TOUCH_MODAL touch modality.}
+ */
+ void getEffectiveTouchableRegion(Region outRegion) {
+ final boolean modal = (mAttrs.flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0;
+ final DisplayContent dc = getDisplayContent();
+
+ if (modal && dc != null) {
+ outRegion.set(dc.getBounds());
+ cropRegionToStackBoundsIfNeeded(outRegion);
+ subtractTouchExcludeRegionIfNeeded(outRegion);
+ } else {
+ getTouchableRegion(outRegion);
+ }
+ }
+
private void setTouchableRegionCropIfNeeded(InputWindowHandle handle) {
final Task task = getTask();
if (task == null || !task.cropWindowsToStackBounds()) {
diff --git a/services/core/java/com/android/server/wm/utils/RegionUtils.java b/services/core/java/com/android/server/wm/utils/RegionUtils.java
index 8cd6f8826083..b1b30701df4f 100644
--- a/services/core/java/com/android/server/wm/utils/RegionUtils.java
+++ b/services/core/java/com/android/server/wm/utils/RegionUtils.java
@@ -20,6 +20,8 @@ import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.RegionIterator;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
@@ -48,14 +50,21 @@ public class RegionUtils {
/**
* Applies actions on each rect contained within a {@code Region}.
*
+ * Order is bottom to top, then right to left.
+ *
* @param region the given region.
* @param rectConsumer the action holder.
*/
- public static void forEachRect(Region region, Consumer<Rect> rectConsumer) {
+ public static void forEachRectReverse(Region region, Consumer<Rect> rectConsumer) {
final RegionIterator it = new RegionIterator(region);
+ final ArrayList<Rect> rects = new ArrayList<>();
final Rect rect = new Rect();
while (it.next(rect)) {
- rectConsumer.accept(rect);
+ rects.add(new Rect(rect));
}
+ // TODO: instead of creating an array and reversing it, expose the reverse iterator through
+ // JNI.
+ Collections.reverse(rects);
+ rects.forEach(rectConsumer);
}
}
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index da175792268f..21bdc43d0d58 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -357,6 +357,33 @@ static inline jboolean boolToJbool(bool value) {
return value ? JNI_TRUE : JNI_FALSE;
}
+template<class T>
+static inline void logHidlError(Return<T>& result, const char* errorMessage) {
+ ALOGE("%s HIDL transport error: %s", errorMessage, result.description().c_str());
+}
+
+template<class T>
+static jboolean checkHidlReturn(Return<T>& result, const char* errorMessage) {
+ if (!result.isOk()) {
+ logHidlError(result, errorMessage);
+ return JNI_FALSE;
+ } else {
+ return JNI_TRUE;
+ }
+}
+
+static jboolean checkHidlReturn(Return<bool>& result, const char* errorMessage) {
+ if (!result.isOk()) {
+ logHidlError(result, errorMessage);
+ return JNI_FALSE;
+ } else if (!result) {
+ ALOGE("%s", errorMessage);
+ return JNI_FALSE;
+ } else {
+ return JNI_TRUE;
+ }
+}
+
static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
if (env->ExceptionCheck()) {
ALOGE("An exception was thrown by callback '%s'.", methodName);
@@ -1913,8 +1940,7 @@ static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject
result = gnssHal->setCallback(gnssCbIface);
}
- if (!result.isOk() || !result) {
- ALOGE("SetCallback for IGnss interface failed.");
+ if (!checkHidlReturn(result, "IGnss setCallback() failed.")) {
return JNI_FALSE;
}
@@ -1924,35 +1950,29 @@ static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject
} else {
sp<IGnssXtraCallback> gnssXtraCbIface = new GnssXtraCallback();
result = gnssXtraIface->setCallback(gnssXtraCbIface);
- if (!result.isOk() || !result) {
+ if (!checkHidlReturn(result, "IGnssXtra setCallback() failed.")) {
gnssXtraIface = nullptr;
- ALOGI("SetCallback for IGnssXtra interface failed.");
}
}
// Set IAGnss.hal callback.
- Return<void> agnssStatus;
if (agnssIface_V2_0 != nullptr) {
sp<IAGnssCallback_V2_0> aGnssCbIface = new AGnssCallback_V2_0();
- agnssStatus = agnssIface_V2_0->setCallback(aGnssCbIface);
+ auto agnssStatus = agnssIface_V2_0->setCallback(aGnssCbIface);
+ checkHidlReturn(agnssStatus, "IAGnss 2.0 setCallback() failed.");
} else if (agnssIface != nullptr) {
sp<IAGnssCallback_V1_0> aGnssCbIface = new AGnssCallback_V1_0();
- agnssStatus = agnssIface->setCallback(aGnssCbIface);
+ auto agnssStatus = agnssIface->setCallback(aGnssCbIface);
+ checkHidlReturn(agnssStatus, "IAGnss setCallback() failed.");
} else {
ALOGI("Unable to initialize IAGnss interface.");
}
- if (!agnssStatus.isOk()) {
- ALOGI("SetCallback for IAGnss interface failed.");
- }
-
// Set IGnssGeofencing.hal callback.
sp<IGnssGeofenceCallback> gnssGeofencingCbIface = new GnssGeofenceCallback();
if (gnssGeofencingIface != nullptr) {
auto status = gnssGeofencingIface->setCallback(gnssGeofencingCbIface);
- if (!status.isOk()) {
- ALOGI("SetCallback for IGnssGeofencing interface failed.");
- }
+ checkHidlReturn(status, "IGnssGeofencing setCallback() failed.");
} else {
ALOGI("Unable to initialize IGnssGeofencing interface.");
}
@@ -1961,9 +1981,7 @@ static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject
sp<IGnssNiCallback> gnssNiCbIface = new GnssNiCallback();
if (gnssNiIface != nullptr) {
auto status = gnssNiIface->setCallback(gnssNiCbIface);
- if (!status.isOk()) {
- ALOGI("SetCallback for IGnssNi interface failed.");
- }
+ checkHidlReturn(status, "IGnssNi setCallback() failed.");
} else {
ALOGI("Unable to initialize IGnssNi interface.");
}
@@ -1972,9 +1990,7 @@ static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject
sp<IAGnssRilCallback> aGnssRilCbIface = new AGnssRilCallback();
if (agnssRilIface != nullptr) {
auto status = agnssRilIface->setCallback(aGnssRilCbIface);
- if (!status.isOk()) {
- ALOGI("SetCallback for IAGnssRil interface failed.");
- }
+ checkHidlReturn(status, "IAGnssRil setCallback() failed.");
} else {
ALOGI("Unable to initialize IAGnssRil interface.");
}
@@ -1984,9 +2000,7 @@ static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject
sp<IGnssVisibilityControlCallback> gnssVisibilityControlCbIface =
new GnssVisibilityControlCallback();
result = gnssVisibilityControlIface->setCallback(gnssVisibilityControlCbIface);
- if (!result.isOk() || !result) {
- ALOGI("SetCallback for IGnssVisibilityControl interface failed.");
- }
+ checkHidlReturn(result, "IGnssVisibilityControl setCallback() failed.");
}
// Set IMeasurementCorrections.hal callback.
@@ -1994,18 +2008,19 @@ static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject
sp<IMeasurementCorrectionsCallback> gnssCorrectionsIfaceCbIface =
new MeasurementCorrectionsCallback();
result = gnssCorrectionsIface->setCallback(gnssCorrectionsIfaceCbIface);
- if (!result.isOk() || !result) {
- ALOGI("SetCallback for IMeasurementCorrections interface failed.");
- }
+ checkHidlReturn(result, "IMeasurementCorrections setCallback() failed.");
}
return JNI_TRUE;
}
static void android_location_GnssLocationProvider_cleanup(JNIEnv* /* env */, jobject /* obj */) {
- if (gnssHal != nullptr) {
- gnssHal->cleanup();
+ if (gnssHal == nullptr) {
+ return;
}
+
+ auto result = gnssHal->cleanup();
+ checkHidlReturn(result, "IGnss cleanup() failed.");
}
static jboolean android_location_GnssLocationProvider_set_position_mode(JNIEnv* /* env */,
@@ -2026,48 +2041,37 @@ static jboolean android_location_GnssLocationProvider_set_position_mode(JNIEnv*
preferred_accuracy,
preferred_time);
}
- if (!result.isOk()) {
- ALOGE("%s: GNSS setPositionMode failed\n", __func__);
- return JNI_FALSE;
- } else {
- return result;
- }
+
+ return checkHidlReturn(result, "IGnss setPositionMode() failed.");
}
static jboolean android_location_GnssLocationProvider_start(JNIEnv* /* env */, jobject /* obj */) {
- if (gnssHal != nullptr) {
- auto result = gnssHal->start();
- if (!result.isOk()) {
- return JNI_FALSE;
- } else {
- return result;
- }
- } else {
+ if (gnssHal == nullptr) {
return JNI_FALSE;
}
+
+ auto result = gnssHal->start();
+ return checkHidlReturn(result, "IGnss start() failed.");
}
static jboolean android_location_GnssLocationProvider_stop(JNIEnv* /* env */, jobject /* obj */) {
- if (gnssHal != nullptr) {
- auto result = gnssHal->stop();
- if (!result.isOk()) {
- return JNI_FALSE;
- } else {
- return result;
- }
- } else {
+ if (gnssHal == nullptr) {
return JNI_FALSE;
}
+
+ auto result = gnssHal->stop();
+ return checkHidlReturn(result, "IGnss stop() failed.");
}
+
static void android_location_GnssLocationProvider_delete_aiding_data(JNIEnv* /* env */,
jobject /* obj */,
jint flags) {
- if (gnssHal != nullptr) {
- auto result = gnssHal->deleteAidingData(static_cast<IGnss_V1_0::GnssAidingData>(flags));
- if (!result.isOk()) {
- ALOGE("Error in deleting aiding data");
- }
+ if (gnssHal == nullptr) {
+ return;
}
+
+ auto result = gnssHal->deleteAidingData(static_cast<IGnss_V1_0::GnssAidingData>(flags));
+ checkHidlReturn(result, "IGnss deleteAidingData() failed.");
}
static void android_location_GnssLocationProvider_agps_set_reference_location_cellid(
@@ -2075,7 +2079,7 @@ static void android_location_GnssLocationProvider_agps_set_reference_location_ce
IAGnssRil_V1_0::AGnssRefLocation location;
if (agnssRilIface == nullptr) {
- ALOGE("No AGPS RIL interface in agps_set_reference_location_cellid");
+ ALOGE("%s: IAGnssRil interface not available.", __func__);
return;
}
@@ -2094,18 +2098,20 @@ static void android_location_GnssLocationProvider_agps_set_reference_location_ce
break;
}
- agnssRilIface->setRefLocation(location);
+ auto result = agnssRilIface->setRefLocation(location);
+ checkHidlReturn(result, "IAGnssRil setRefLocation() failed.");
}
static void android_location_GnssLocationProvider_agps_set_id(JNIEnv* env, jobject /* obj */,
jint type, jstring setid_string) {
if (agnssRilIface == nullptr) {
- ALOGE("no AGPS RIL interface in agps_set_id");
+ ALOGE("%s: IAGnssRil interface not available.", __func__);
return;
}
ScopedJniString jniSetId{env, setid_string};
- agnssRilIface->setSetId((IAGnssRil_V1_0::SetIDType)type, jniSetId);
+ auto result = agnssRilIface->setSetId((IAGnssRil_V1_0::SetIDType)type, jniSetId);
+ checkHidlReturn(result, "IAGnssRil setSetId() failed.");
}
static jint android_location_GnssLocationProvider_read_nmea(JNIEnv* env, jobject /* obj */,
@@ -2122,12 +2128,12 @@ static jint android_location_GnssLocationProvider_read_nmea(JNIEnv* env, jobject
static void android_location_GnssLocationProvider_inject_time(JNIEnv* /* env */, jobject /* obj */,
jlong time, jlong timeReference, jint uncertainty) {
- if (gnssHal != nullptr) {
- auto result = gnssHal->injectTime(time, timeReference, uncertainty);
- if (!result.isOk() || !result) {
- ALOGE("%s: Gnss injectTime() failed", __func__);
- }
+ if (gnssHal == nullptr) {
+ return;
}
+
+ auto result = gnssHal->injectTime(time, timeReference, uncertainty);
+ checkHidlReturn(result, "IGnss injectTime() failed.");
}
static void android_location_GnssLocationProvider_inject_best_location(
@@ -2164,10 +2170,7 @@ static void android_location_GnssLocationProvider_inject_best_location(
elapsedRealtimeNanos,
elapsedRealtimeUncertaintyNanos);
auto result = gnssHal_V2_0->injectBestLocation_2_0(location);
-
- if (!result.isOk() || !result) {
- ALOGE("%s: Gnss injectBestLocation() failed.", __func__);
- }
+ checkHidlReturn(result, "IGnss injectBestLocation_2_0() failed.");
return;
}
@@ -2185,24 +2188,20 @@ static void android_location_GnssLocationProvider_inject_best_location(
bearingAccuracyDegrees,
timestamp);
auto result = gnssHal_V1_1->injectBestLocation(location);
-
- if (!result.isOk() || !result) {
- ALOGE("%s: Gnss injectBestLocation() failed.", __func__);
- }
- return;
+ checkHidlReturn(result, "IGnss injectBestLocation() failed.");
}
- ALOGE("%s: injectBestLocation() is called but gnssHal_V1_1 is not available.", __func__);
+ ALOGE("IGnss injectBestLocation() is called but gnssHal_V1_1 is not available.");
}
static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env */,
jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy) {
- if (gnssHal != nullptr) {
- auto result = gnssHal->injectLocation(latitude, longitude, accuracy);
- if (!result.isOk() || !result) {
- ALOGE("%s: Gnss injectLocation() failed", __func__);
- }
+ if (gnssHal == nullptr) {
+ return;
}
+
+ auto result = gnssHal->injectLocation(latitude, longitude, accuracy);
+ checkHidlReturn(result, "IGnss injectLocation() failed.");
}
static jboolean android_location_GnssLocationProvider_supports_psds(
@@ -2213,12 +2212,13 @@ static jboolean android_location_GnssLocationProvider_supports_psds(
static void android_location_GnssLocationProvider_inject_psds_data(JNIEnv* env, jobject /* obj */,
jbyteArray data, jint length) {
if (gnssXtraIface == nullptr) {
- ALOGE("XTRA Interface not supported");
+ ALOGE("%s: IGnssXtra interface not available.", __func__);
return;
}
jbyte* bytes = reinterpret_cast<jbyte *>(env->GetPrimitiveArrayCritical(data, 0));
- gnssXtraIface->injectXtraData(std::string((const char*)bytes, length));
+ auto result = gnssXtraIface->injectXtraData(std::string((const char*)bytes, length));
+ checkHidlReturn(result, "IGnssXtra injectXtraData() failed.");
env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
}
@@ -2245,9 +2245,7 @@ void AGnssDispatcher::dataConnOpen(sp<IAGnss_V1_0> agnssIface, JNIEnv* env, jstr
ScopedJniString jniApn{env, apn};
auto result = agnssIface->dataConnOpen(jniApn,
static_cast<IAGnss_V1_0::ApnIpType>(apnIpType));
- if (!result.isOk() || !result){
- ALOGE("%s: Failed to set APN and its IP type", __func__);
- }
+ checkHidlReturn(result, "IAGnss dataConnOpen() failed. APN and its IP type not set.");
}
void AGnssDispatcher::dataConnOpen(sp<IAGnss_V2_0> agnssIface_V2_0, JNIEnv* env,
@@ -2255,25 +2253,19 @@ void AGnssDispatcher::dataConnOpen(sp<IAGnss_V2_0> agnssIface_V2_0, JNIEnv* env,
ScopedJniString jniApn{env, apn};
auto result = agnssIface_V2_0->dataConnOpen(static_cast<uint64_t>(networkHandle), jniApn,
static_cast<IAGnss_V2_0::ApnIpType>(apnIpType));
- if (!result.isOk() || !result){
- ALOGE("%s: Failed to set APN and its IP type", __func__);
- }
+ checkHidlReturn(result, "IAGnss 2.0 dataConnOpen() failed. APN and its IP type not set.");
}
template<class T>
void AGnssDispatcher::dataConnClosed(sp<T> agnssIface) {
auto result = agnssIface->dataConnClosed();
- if (!result.isOk() || !result) {
- ALOGE("%s: Failed to close AGnss data connection", __func__);
- }
+ checkHidlReturn(result, "IAGnss dataConnClosed() failed.");
}
template<class T>
void AGnssDispatcher::dataConnFailed(sp<T> agnssIface) {
auto result = agnssIface->dataConnFailed();
- if (!result.isOk() || !result) {
- ALOGE("%s: Failed to notify unavailability of AGnss data connection", __func__);
- }
+ checkHidlReturn(result, "IAGnss dataConnFailed() failed.");
}
template <class T, class U>
@@ -2282,9 +2274,7 @@ void AGnssDispatcher::setServer(sp<T> agnssIface, JNIEnv* env, jint type, jstrin
ScopedJniString jniHostName{env, hostname};
auto result = agnssIface->setServer(static_cast<typename U::AGnssType>(type),
jniHostName, port);
- if (!result.isOk() || !result) {
- ALOGE("%s: Failed to set AGnss host name and port", __func__);
- }
+ checkHidlReturn(result, "IAGnss setServer() failed. Host name and port not set.");
}
static void android_location_GnssNetworkConnectivityHandler_agps_data_conn_open(
@@ -2299,7 +2289,7 @@ static void android_location_GnssNetworkConnectivityHandler_agps_data_conn_open(
} else if (agnssIface != nullptr) {
AGnssDispatcher::dataConnOpen(agnssIface, env, apn, apnIpType);
} else {
- ALOGE("%s: AGPS interface not supported", __func__);
+ ALOGE("%s: IAGnss interface not available.", __func__);
return;
}
}
@@ -2311,7 +2301,7 @@ static void android_location_GnssNetworkConnectivityHandler_agps_data_conn_close
} else if (agnssIface != nullptr) {
AGnssDispatcher::dataConnClosed(agnssIface);
} else {
- ALOGE("%s: AGPS interface not supported", __func__);
+ ALOGE("%s: IAGnss interface not available.", __func__);
return;
}
}
@@ -2323,7 +2313,7 @@ static void android_location_GnssNetworkConnectivityHandler_agps_data_conn_faile
} else if (agnssIface != nullptr) {
AGnssDispatcher::dataConnFailed(agnssIface);
} else {
- ALOGE("%s: AGPS interface not supported", __func__);
+ ALOGE("%s: IAGnss interface not available.", __func__);
return;
}
}
@@ -2337,26 +2327,30 @@ static void android_location_GnssLocationProvider_set_agps_server(JNIEnv* env, j
AGnssDispatcher::setServer<IAGnss_V1_0, IAGnssCallback_V1_0>(agnssIface, env, type,
hostname, port);
} else {
- ALOGE("%s: AGPS interface not supported", __func__);
+ ALOGE("%s: IAGnss interface not available.", __func__);
return;
}
}
static void android_location_GnssLocationProvider_send_ni_response(JNIEnv* /* env */,
- jobject /* obj */, jint notifId, jint response) {
+ jobject /* obj */, jint notifId, jint response) {
if (gnssNiIface == nullptr) {
- ALOGE("no NI interface in send_ni_response");
+ ALOGE("%s: IGnssNi interface not available.", __func__);
return;
}
- gnssNiIface->respond(notifId, static_cast<IGnssNiCallback::GnssUserResponseType>(response));
+ auto result = gnssNiIface->respond(notifId,
+ static_cast<IGnssNiCallback::GnssUserResponseType>(response));
+ checkHidlReturn(result, "IGnssNi respond() failed.");
}
-const IGnssDebug_V1_0::SatelliteData& getSatelliteData(const hidl_vec<IGnssDebug_V1_0::SatelliteData>& satelliteDataArray, size_t i) {
+const IGnssDebug_V1_0::SatelliteData& getSatelliteData(
+ const hidl_vec<IGnssDebug_V1_0::SatelliteData>& satelliteDataArray, size_t i) {
return satelliteDataArray[i];
}
-const IGnssDebug_V1_0::SatelliteData& getSatelliteData(const hidl_vec<IGnssDebug_V2_0::SatelliteData>& satelliteDataArray, size_t i) {
+const IGnssDebug_V1_0::SatelliteData& getSatelliteData(
+ const hidl_vec<IGnssDebug_V2_0::SatelliteData>& satelliteDataArray, size_t i) {
return satelliteDataArray[i].v1_0;
}
@@ -2424,7 +2418,7 @@ static jstring parseDebugData(JNIEnv* env, std::stringstream& internalState, con
static jstring android_location_GnssLocationProvider_get_internal_state(JNIEnv* env,
jobject /* obj */) {
- jstring result = nullptr;
+ jstring internalStateStr = nullptr;
/*
* TODO: Create a jobject to represent GnssDebug.
*/
@@ -2432,21 +2426,27 @@ static jstring android_location_GnssLocationProvider_get_internal_state(JNIEnv*
std::stringstream internalState;
if (gnssDebugIface == nullptr) {
- internalState << "Gnss Debug Interface not available" << std::endl;
+ ALOGE("%s: IGnssDebug interface not available.", __func__);
} else if (gnssDebugIface_V2_0 != nullptr) {
IGnssDebug_V2_0::DebugData data;
- gnssDebugIface_V2_0->getDebugData_2_0([&data](const IGnssDebug_V2_0::DebugData& debugData) {
- data = debugData;
- });
- result = parseDebugData(env, internalState, data);
+ auto result = gnssDebugIface_V2_0->getDebugData_2_0(
+ [&data](const IGnssDebug_V2_0::DebugData& debugData) {
+ data = debugData;
+ });
+ if (checkHidlReturn(result, "IGnssDebug getDebugData_2_0() failed.")) {
+ internalStateStr = parseDebugData(env, internalState, data);
+ }
} else {
IGnssDebug_V1_0::DebugData data;
- gnssDebugIface->getDebugData([&data](const IGnssDebug_V1_0::DebugData& debugData) {
- data = debugData;
- });
- result = parseDebugData(env, internalState, data);
+ auto result = gnssDebugIface->getDebugData(
+ [&data](const IGnssDebug_V1_0::DebugData& debugData) {
+ data = debugData;
+ });
+ if (checkHidlReturn(result, "IGnssDebug getDebugData() failed.")) {
+ internalStateStr = parseDebugData(env, internalState, data);
+ }
}
- return result;
+ return internalStateStr;
}
static jboolean android_location_GnssLocationProvider_is_gnss_visibility_control_supported(
@@ -2473,26 +2473,20 @@ static void android_location_GnssNetworkConnectivityHandler_update_network_state
};
auto result = agnssRilIface_V2_0->updateNetworkState_2_0(networkAttributes);
- if (!result.isOk() || !result) {
- ALOGE("updateNetworkState_2_0 failed");
- }
+ checkHidlReturn(result, "IAGnssRil updateNetworkState_2_0() failed.");
} else if (agnssRilIface != nullptr) {
ScopedJniString jniApn{env, apn};
hidl_string hidlApn{jniApn};
auto result = agnssRilIface->updateNetworkState(connected,
static_cast<IAGnssRil_V1_0::NetworkType>(type), roaming);
- if (!result.isOk() || !result) {
- ALOGE("updateNetworkState failed");
- }
+ checkHidlReturn(result, "IAGnssRil updateNetworkState() failed.");
if (!hidlApn.empty()) {
result = agnssRilIface->updateNetworkAvailability(available, hidlApn);
- if (!result.isOk() || !result) {
- ALOGE("updateNetworkAvailability failed");
- }
+ checkHidlReturn(result, "IAGnssRil updateNetworkAvailability() failed.");
}
} else {
- ALOGE("AGnssRilInterface does not exist");
+ ALOGE("%s: IAGnssRil interface not available.", __func__);
}
}
@@ -2505,49 +2499,49 @@ static jboolean android_location_GnssGeofenceProvider_add_geofence(JNIEnv* /* en
jobject /* obj */, jint geofenceId, jdouble latitude, jdouble longitude, jdouble radius,
jint last_transition, jint monitor_transition, jint notification_responsiveness,
jint unknown_timer) {
- if (gnssGeofencingIface != nullptr) {
- auto result = gnssGeofencingIface->addGeofence(
- geofenceId, latitude, longitude, radius,
- static_cast<IGnssGeofenceCallback::GeofenceTransition>(last_transition),
- monitor_transition, notification_responsiveness, unknown_timer);
- return boolToJbool(result.isOk());
- } else {
- ALOGE("Geofence Interface not available");
+ if (gnssGeofencingIface == nullptr) {
+ ALOGE("%s: IGnssGeofencing interface not available.", __func__);
+ return JNI_FALSE;
}
- return JNI_FALSE;
+
+ auto result = gnssGeofencingIface->addGeofence(
+ geofenceId, latitude, longitude, radius,
+ static_cast<IGnssGeofenceCallback::GeofenceTransition>(last_transition),
+ monitor_transition, notification_responsiveness, unknown_timer);
+ return checkHidlReturn(result, "IGnssGeofencing addGeofence() failed.");
}
static jboolean android_location_GnssGeofenceProvider_remove_geofence(JNIEnv* /* env */,
jobject /* obj */, jint geofenceId) {
- if (gnssGeofencingIface != nullptr) {
- auto result = gnssGeofencingIface->removeGeofence(geofenceId);
- return boolToJbool(result.isOk());
- } else {
- ALOGE("Geofence interface not available");
+ if (gnssGeofencingIface == nullptr) {
+ ALOGE("%s: IGnssGeofencing interface not available.", __func__);
+ return JNI_FALSE;
}
- return JNI_FALSE;
+
+ auto result = gnssGeofencingIface->removeGeofence(geofenceId);
+ return checkHidlReturn(result, "IGnssGeofencing removeGeofence() failed.");
}
static jboolean android_location_GnssGeofenceProvider_pause_geofence(JNIEnv* /* env */,
jobject /* obj */, jint geofenceId) {
- if (gnssGeofencingIface != nullptr) {
- auto result = gnssGeofencingIface->pauseGeofence(geofenceId);
- return boolToJbool(result.isOk());
- } else {
- ALOGE("Geofence interface not available");
+ if (gnssGeofencingIface == nullptr) {
+ ALOGE("%s: IGnssGeofencing interface not available.", __func__);
+ return JNI_FALSE;
}
- return JNI_FALSE;
+
+ auto result = gnssGeofencingIface->pauseGeofence(geofenceId);
+ return checkHidlReturn(result, "IGnssGeofencing pauseGeofence() failed.");
}
static jboolean android_location_GnssGeofenceProvider_resume_geofence(JNIEnv* /* env */,
jobject /* obj */, jint geofenceId, jint monitor_transition) {
- if (gnssGeofencingIface != nullptr) {
- auto result = gnssGeofencingIface->resumeGeofence(geofenceId, monitor_transition);
- return boolToJbool(result.isOk());
- } else {
- ALOGE("Geofence interface not available");
+ if (gnssGeofencingIface == nullptr) {
+ ALOGE("%s: IGnssGeofencing interface not available.", __func__);
+ return JNI_FALSE;
}
- return JNI_FALSE;
+
+ auto result = gnssGeofencingIface->resumeGeofence(geofenceId, monitor_transition);
+ return checkHidlReturn(result, "IGnssGeofencing resumeGeofence() failed.");
}
static jboolean android_location_GnssMeasurementsProvider_is_measurement_supported(
@@ -2564,12 +2558,12 @@ static jboolean android_location_GnssMeasurementsProvider_start_measurement_coll
jobject /* obj */,
jboolean enableFullTracking) {
if (gnssMeasurementIface == nullptr) {
- ALOGE("GNSS Measurement interface is not available.");
+ ALOGE("%s: IGnssMeasurement interface not available.", __func__);
return JNI_FALSE;
}
sp<GnssMeasurementCallback> cbIface = new GnssMeasurementCallback();
- IGnssMeasurement_V1_0::GnssMeasurementStatus result =
+ Return<IGnssMeasurement_V1_0::GnssMeasurementStatus> result =
IGnssMeasurement_V1_0::GnssMeasurementStatus::ERROR_GENERIC;
if (gnssMeasurementIface_V2_0 != nullptr) {
result = gnssMeasurementIface_V2_0->setCallback_2_0(cbIface, enableFullTracking);
@@ -2578,14 +2572,20 @@ static jboolean android_location_GnssMeasurementsProvider_start_measurement_coll
} else {
if (enableFullTracking == JNI_TRUE) {
// full tracking mode not supported in 1.0 HAL
+ result.assertOk(); // isOk() must be called before result destructor is invoked.
return JNI_FALSE;
}
result = gnssMeasurementIface->setCallback(cbIface);
}
- if (result != IGnssMeasurement_V1_0::GnssMeasurementStatus::SUCCESS) {
+ if (!checkHidlReturn(result, "IGnssMeasurement setCallback() failed.")) {
+ return JNI_FALSE;
+ }
+
+ IGnssMeasurement_V1_0::GnssMeasurementStatus initRet = result;
+ if (initRet != IGnssMeasurement_V1_0::GnssMeasurementStatus::SUCCESS) {
ALOGE("An error has been found on GnssMeasurementInterface::init, status=%d",
- static_cast<int32_t>(result));
+ static_cast<int32_t>(initRet));
return JNI_FALSE;
} else {
ALOGD("gnss measurement infc has been enabled");
@@ -2598,12 +2598,12 @@ static jboolean android_location_GnssMeasurementsProvider_stop_measurement_colle
JNIEnv* env,
jobject obj) {
if (gnssMeasurementIface == nullptr) {
- ALOGE("Measurement interface not available");
+ ALOGE("%s: IGnssMeasurement interface not available.", __func__);
return JNI_FALSE;
}
auto result = gnssMeasurementIface->close();
- return boolToJbool(result.isOk());
+ return checkHidlReturn(result, "IGnssMeasurement close() failed.");
}
static jboolean
@@ -2718,8 +2718,8 @@ static jboolean
.satCorrections = list,
};
- gnssCorrectionsIface->setCorrections(measurementCorrections);
- return JNI_TRUE;
+ auto result = gnssCorrectionsIface->setCorrections(measurementCorrections);
+ return checkHidlReturn(result, "IMeasurementCorrections setCorrections() failed.");
}
static jboolean android_location_GnssNavigationMessageProvider_is_navigation_message_supported(
@@ -2735,17 +2735,20 @@ static jboolean android_location_GnssNavigationMessageProvider_start_navigation_
JNIEnv* env,
jobject obj) {
if (gnssNavigationMessageIface == nullptr) {
- ALOGE("Navigation Message interface is not available.");
+ ALOGE("%s: IGnssNavigationMessage interface not available.", __func__);
return JNI_FALSE;
}
sp<IGnssNavigationMessageCallback> gnssNavigationMessageCbIface =
new GnssNavigationMessageCallback();
- IGnssNavigationMessage::GnssNavigationMessageStatus result =
- gnssNavigationMessageIface->setCallback(gnssNavigationMessageCbIface);
+ auto result = gnssNavigationMessageIface->setCallback(gnssNavigationMessageCbIface);
+ if (!checkHidlReturn(result, "IGnssNavigationMessage setCallback() failed.")) {
+ return JNI_FALSE;
+ }
- if (result != IGnssNavigationMessage::GnssNavigationMessageStatus::SUCCESS) {
- ALOGE("An error has been found in %s: %d", __FUNCTION__, static_cast<int32_t>(result));
+ IGnssNavigationMessage::GnssNavigationMessageStatus initRet = result;
+ if (initRet != IGnssNavigationMessage::GnssNavigationMessageStatus::SUCCESS) {
+ ALOGE("An error has been found in %s: %d", __FUNCTION__, static_cast<int32_t>(initRet));
return JNI_FALSE;
}
@@ -2756,43 +2759,35 @@ static jboolean android_location_GnssNavigationMessageProvider_stop_navigation_m
JNIEnv* env,
jobject obj) {
if (gnssNavigationMessageIface == nullptr) {
- ALOGE("Navigation Message interface is not available.");
+ ALOGE("%s: IGnssNavigationMessage interface not available.", __func__);
return JNI_FALSE;
}
auto result = gnssNavigationMessageIface->close();
- return boolToJbool(result.isOk());
+ return checkHidlReturn(result, "IGnssNavigationMessage close() failed.");
}
static jboolean android_location_GnssConfiguration_set_emergency_supl_pdn(JNIEnv*,
jobject,
jint emergencySuplPdn) {
if (gnssConfigurationIface == nullptr) {
- ALOGE("no GNSS configuration interface available");
+ ALOGE("%s: IGnssConfiguration interface not available.", __func__);
return JNI_FALSE;
}
auto result = gnssConfigurationIface->setEmergencySuplPdn(emergencySuplPdn);
- if (result.isOk()) {
- return result;
- } else {
- return JNI_FALSE;
- }
+ return checkHidlReturn(result, "IGnssConfiguration setEmergencySuplPdn() failed.");
}
static jboolean android_location_GnssConfiguration_set_supl_version(JNIEnv*,
jobject,
jint version) {
if (gnssConfigurationIface == nullptr) {
- ALOGE("no GNSS configuration interface available");
+ ALOGE("%s: IGnssConfiguration interface not available.", __func__);
return JNI_FALSE;
}
auto result = gnssConfigurationIface->setSuplVersion(version);
- if (result.isOk()) {
- return result;
- } else {
- return JNI_FALSE;
- }
+ return checkHidlReturn(result, "IGnssConfiguration setSuplVersion() failed.");
}
static jboolean android_location_GnssConfiguration_set_supl_es(JNIEnv*,
@@ -2804,32 +2799,24 @@ static jboolean android_location_GnssConfiguration_set_supl_es(JNIEnv*,
}
if (gnssConfigurationIface == nullptr) {
- ALOGE("no GNSS configuration interface available");
+ ALOGE("%s: IGnssConfiguration interface not available.", __func__);
return JNI_FALSE;
}
auto result = gnssConfigurationIface->setSuplEs(suplEs);
- if (result.isOk()) {
- return result;
- } else {
- return JNI_FALSE;
- }
+ return checkHidlReturn(result, "IGnssConfiguration setSuplEs() failed.");
}
static jboolean android_location_GnssConfiguration_set_supl_mode(JNIEnv*,
jobject,
jint mode) {
if (gnssConfigurationIface == nullptr) {
- ALOGE("no GNSS configuration interface available");
+ ALOGE("%s: IGnssConfiguration interface not available.", __func__);
return JNI_FALSE;
}
auto result = gnssConfigurationIface->setSuplMode(mode);
- if (result.isOk()) {
- return result;
- } else {
- return JNI_FALSE;
- }
+ return checkHidlReturn(result, "IGnssConfiguration setSuplMode() failed.");
}
static jboolean android_location_GnssConfiguration_set_gps_lock(JNIEnv*,
@@ -2841,55 +2828,42 @@ static jboolean android_location_GnssConfiguration_set_gps_lock(JNIEnv*,
}
if (gnssConfigurationIface == nullptr) {
- ALOGE("no GNSS configuration interface available");
+ ALOGE("%s: IGnssConfiguration interface not available.", __func__);
return JNI_FALSE;
}
auto result = gnssConfigurationIface->setGpsLock(gpsLock);
- if (result.isOk()) {
- return result;
- } else {
- return JNI_FALSE;
- }
+ return checkHidlReturn(result, "IGnssConfiguration setGpsLock() failed.");
}
static jboolean android_location_GnssConfiguration_set_lpp_profile(JNIEnv*,
jobject,
jint lppProfile) {
if (gnssConfigurationIface == nullptr) {
- ALOGE("no GNSS configuration interface available");
+ ALOGE("%s: IGnssConfiguration interface not available.", __func__);
return JNI_FALSE;
}
auto result = gnssConfigurationIface->setLppProfile(lppProfile);
-
- if (result.isOk()) {
- return result;
- } else {
- return JNI_FALSE;
- }
+ return checkHidlReturn(result, "IGnssConfiguration setLppProfile() failed.");
}
static jboolean android_location_GnssConfiguration_set_gnss_pos_protocol_select(JNIEnv*,
jobject,
jint gnssPosProtocol) {
if (gnssConfigurationIface == nullptr) {
- ALOGE("no GNSS configuration interface available");
+ ALOGE("%s: IGnssConfiguration interface not available.", __func__);
return JNI_FALSE;
}
auto result = gnssConfigurationIface->setGlonassPositioningProtocol(gnssPosProtocol);
- if (result.isOk()) {
- return result;
- } else {
- return JNI_FALSE;
- }
+ return checkHidlReturn(result, "IGnssConfiguration setGlonassPositioningProtocol() failed.");
}
static jboolean android_location_GnssConfiguration_set_satellite_blacklist(
JNIEnv* env, jobject, jintArray constellations, jintArray sv_ids) {
if (gnssConfigurationIface_V1_1 == nullptr) {
- ALOGI("No GNSS Satellite Blacklist interface available");
+ ALOGI("IGnssConfiguration interface does not support satellite blacklist.");
return JNI_FALSE;
}
@@ -2920,17 +2894,13 @@ static jboolean android_location_GnssConfiguration_set_satellite_blacklist(
}
auto result = gnssConfigurationIface_V1_1->setBlacklist(sources);
- if (result.isOk()) {
- return result;
- } else {
- return JNI_FALSE;
- }
+ return checkHidlReturn(result, "IGnssConfiguration setBlacklist() failed.");
}
static jboolean android_location_GnssConfiguration_set_es_extension_sec(
JNIEnv*, jobject, jint emergencyExtensionSeconds) {
if (gnssConfigurationIface == nullptr) {
- ALOGE("no GNSS configuration interface available");
+ ALOGE("%s: IGnssConfiguration interface not available.", __func__);
return JNI_FALSE;
}
@@ -2941,11 +2911,7 @@ static jboolean android_location_GnssConfiguration_set_es_extension_sec(
}
auto result = gnssConfigurationIface_V2_0->setEsExtensionSec(emergencyExtensionSeconds);
- if (result.isOk()) {
- return result;
- } else {
- return JNI_FALSE;
- }
+ return checkHidlReturn(result, "IGnssConfiguration setEsExtensionSec() failed.");
}
static jint android_location_GnssBatchingProvider_get_batch_size(JNIEnv*, jclass) {
@@ -2953,20 +2919,22 @@ static jint android_location_GnssBatchingProvider_get_batch_size(JNIEnv*, jclass
return 0; // batching not supported, size = 0
}
auto result = gnssBatchingIface->getBatchSize();
- if (result.isOk()) {
- return static_cast<jint>(result);
- } else {
+ if (!checkHidlReturn(result, "IGnssBatching getBatchSize() failed.")) {
return 0; // failure in binder, don't support batching
}
+
+ return static_cast<jint>(result);
}
static jboolean android_location_GnssBatchingProvider_init_batching(JNIEnv*, jclass) {
if (gnssBatchingIface_V2_0 != nullptr) {
sp<IGnssBatchingCallback_V2_0> gnssBatchingCbIface_V2_0 = new GnssBatchingCallback_V2_0();
- return static_cast<jboolean>(gnssBatchingIface_V2_0->init_2_0(gnssBatchingCbIface_V2_0));
+ auto result = gnssBatchingIface_V2_0->init_2_0(gnssBatchingCbIface_V2_0);
+ return checkHidlReturn(result, "IGnssBatching init_2_0() failed.");
} else if (gnssBatchingIface != nullptr) {
sp<IGnssBatchingCallback_V1_0> gnssBatchingCbIface_V1_0 = new GnssBatchingCallback_V1_0();
- return static_cast<jboolean>(gnssBatchingIface->init(gnssBatchingCbIface_V1_0));
+ auto result = gnssBatchingIface->init(gnssBatchingCbIface_V1_0);
+ return checkHidlReturn(result, "IGnssBatching init() failed.");
} else {
return JNI_FALSE; // batching not supported
}
@@ -2976,7 +2944,8 @@ static void android_location_GnssBatchingProvider_cleanup_batching(JNIEnv*, jcla
if (gnssBatchingIface == nullptr) {
return; // batching not supported
}
- gnssBatchingIface->cleanup();
+ auto result = gnssBatchingIface->cleanup();
+ checkHidlReturn(result, "IGnssBatching cleanup() failed.");
}
static jboolean android_location_GnssBatchingProvider_start_batch(JNIEnv*, jclass,
@@ -2993,29 +2962,30 @@ static jboolean android_location_GnssBatchingProvider_start_batch(JNIEnv*, jclas
options.flags = 0;
}
- return static_cast<jboolean>(gnssBatchingIface->start(options));
+ auto result = gnssBatchingIface->start(options);
+ return checkHidlReturn(result, "IGnssBatching start() failed.");
}
static void android_location_GnssBatchingProvider_flush_batch(JNIEnv*, jclass) {
if (gnssBatchingIface == nullptr) {
return; // batching not supported
}
-
- gnssBatchingIface->flush();
+ auto result = gnssBatchingIface->flush();
+ checkHidlReturn(result, "IGnssBatching flush() failed.");
}
static jboolean android_location_GnssBatchingProvider_stop_batch(JNIEnv*, jclass) {
if (gnssBatchingIface == nullptr) {
return JNI_FALSE; // batching not supported
}
-
- return gnssBatchingIface->stop();
+ auto result = gnssBatchingIface->stop();
+ return checkHidlReturn(result, "IGnssBatching stop() failed.");
}
static jboolean android_location_GnssVisibilityControl_enable_nfw_location_access(
JNIEnv* env, jobject, jobjectArray proxyApps) {
if (gnssVisibilityControlIface == nullptr) {
- ALOGI("No GNSS Visibility Control interface available");
+ ALOGI("IGnssVisibilityControl interface not available.");
return JNI_FALSE;
}
@@ -3028,11 +2998,7 @@ static jboolean android_location_GnssVisibilityControl_enable_nfw_location_acces
}
auto result = gnssVisibilityControlIface->enableNfwLocationAccess(hidlProxyApps);
- if (result.isOk()) {
- return result;
- } else {
- return JNI_FALSE;
- }
+ return checkHidlReturn(result, "IGnssVisibilityControl enableNfwLocationAccess() failed.");
}
static const JNINativeMethod sMethods[] = {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 48921eae0bf7..de8612aba81b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -228,7 +228,6 @@ import android.view.IWindowManager;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodSystemProperty;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -9403,12 +9402,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return false;
}
Preconditions.checkNotNull(who, "ComponentName is null");
-
- // TODO When InputMethodManager supports per user calls remove this restriction.
- if (!InputMethodSystemProperty.PER_PROFILE_IME_ENABLED
- && !checkCallerIsCurrentUserOrProfile()) {
- return false;
- }
final int callingUserId = mInjector.userHandleGetCallingUserId();
if (packageList != null) {
List<InputMethodInfo> enabledImes = InputMethodManagerInternal.get()
@@ -9464,26 +9457,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final int callingUserId = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
List<String> result = null;
- // If we have multiple profiles we return the intersection of the
- // permitted lists. This can happen in cases where we have a device
- // and profile owner.
- int[] profileIds = InputMethodSystemProperty.PER_PROFILE_IME_ENABLED
- ? new int[]{callingUserId}
- : mUserManager.getProfileIdsWithDisabled(callingUserId);
- for (int profileId : profileIds) {
- // Just loop though all admins, only device or profiles
- // owners can have permitted lists set.
- DevicePolicyData policy = getUserDataUnchecked(profileId);
- final int N = policy.mAdminList.size();
- for (int j = 0; j < N; j++) {
- ActiveAdmin admin = policy.mAdminList.get(j);
- List<String> fromAdmin = admin.permittedInputMethods;
- if (fromAdmin != null) {
- if (result == null) {
- result = new ArrayList<String>(fromAdmin);
- } else {
- result.retainAll(fromAdmin);
- }
+ // Only device or profile owners can have permitted lists set.
+ DevicePolicyData policy = getUserDataUnchecked(callingUserId);
+ for (int i = 0; i < policy.mAdminList.size(); i++) {
+ ActiveAdmin admin = policy.mAdminList.get(i);
+ List<String> fromAdmin = admin.permittedInputMethods;
+ if (fromAdmin != null) {
+ if (result == null) {
+ result = new ArrayList<String>(fromAdmin);
+ } else {
+ result.retainAll(fromAdmin);
}
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java
index 699bec2c9329..261a83c4f67a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/OverlayPackagesProvider.java
@@ -33,7 +33,6 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.util.ArraySet;
import android.view.inputmethod.InputMethodInfo;
-import android.view.inputmethod.InputMethodSystemProperty;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
@@ -61,17 +60,11 @@ public class OverlayPackagesProvider {
@VisibleForTesting
interface Injector {
- boolean isPerProfileImeEnabled();
@NonNull
List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId);
}
private static final class DefaultInjector implements Injector {
- @Override
- public boolean isPerProfileImeEnabled() {
- return InputMethodSystemProperty.PER_PROFILE_IME_ENABLED;
- }
-
@NonNull
@Override
public List<InputMethodInfo> getInputMethodListAsUser(@UserIdInt int userId) {
@@ -108,13 +101,7 @@ public class OverlayPackagesProvider {
// Newly installed system apps are uninstalled when they are not required and are either
// disallowed or have a launcher icon.
nonRequiredApps.removeAll(getRequiredApps(provisioningAction, admin.getPackageName()));
- if (mInjector.isPerProfileImeEnabled()) {
- nonRequiredApps.removeAll(getSystemInputMethods(userId));
- } else if (ACTION_PROVISION_MANAGED_DEVICE.equals(provisioningAction)
- || ACTION_PROVISION_MANAGED_USER.equals(provisioningAction)) {
- // Don't delete the system input method packages in case of Device owner provisioning.
- nonRequiredApps.removeAll(getSystemInputMethods(userId));
- }
+ nonRequiredApps.removeAll(getSystemInputMethods(userId));
nonRequiredApps.addAll(getDisallowedApps(provisioningAction));
return nonRequiredApps;
}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/chunking/DecryptedChunkFileOutputTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/DecryptedChunkFileOutputTest.java
new file mode 100644
index 000000000000..823a63c22da4
--- /dev/null
+++ b/services/robotests/backup/src/com/android/server/backup/encryption/chunking/DecryptedChunkFileOutputTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption.chunking;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.platform.test.annotations.Presubmit;
+
+import com.android.server.backup.encryption.tasks.DecryptedChunkOutput;
+
+import com.google.common.io.Files;
+import com.google.common.primitives.Bytes;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.util.Arrays;
+
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+public class DecryptedChunkFileOutputTest {
+ private static final byte[] TEST_CHUNK_1 = {1, 2, 3};
+ private static final byte[] TEST_CHUNK_2 = {4, 5, 6, 7, 8, 9, 10};
+ private static final int TEST_BUFFER_LENGTH =
+ Math.max(TEST_CHUNK_1.length, TEST_CHUNK_2.length);
+
+ @Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ private File mOutputFile;
+ private DecryptedChunkFileOutput mDecryptedChunkFileOutput;
+
+ @Before
+ public void setUp() throws Exception {
+ mOutputFile = temporaryFolder.newFile();
+ mDecryptedChunkFileOutput = new DecryptedChunkFileOutput(mOutputFile);
+ }
+
+ @Test
+ public void open_returnsInstance() throws Exception {
+ DecryptedChunkOutput result = mDecryptedChunkFileOutput.open();
+ assertThat(result).isEqualTo(mDecryptedChunkFileOutput);
+ }
+
+ @Test
+ public void open_nonExistentOutputFolder_throwsException() throws Exception {
+ mDecryptedChunkFileOutput =
+ new DecryptedChunkFileOutput(
+ new File(temporaryFolder.newFolder(), "mOutput/directory"));
+ assertThrows(FileNotFoundException.class, () -> mDecryptedChunkFileOutput.open());
+ }
+
+ @Test
+ public void open_whenRunTwice_throwsException() throws Exception {
+ mDecryptedChunkFileOutput.open();
+ assertThrows(IllegalStateException.class, () -> mDecryptedChunkFileOutput.open());
+ }
+
+ @Test
+ public void processChunk_beforeOpen_throwsException() throws Exception {
+ assertThrows(IllegalStateException.class,
+ () -> mDecryptedChunkFileOutput.processChunk(new byte[0], 0));
+ }
+
+ @Test
+ public void processChunk_writesChunksToFile() throws Exception {
+ processTestChunks();
+
+ assertThat(Files.toByteArray(mOutputFile))
+ .isEqualTo(Bytes.concat(TEST_CHUNK_1, TEST_CHUNK_2));
+ }
+
+ @Test
+ public void getDigest_beforeClose_throws() throws Exception {
+ mDecryptedChunkFileOutput.open();
+ assertThrows(IllegalStateException.class, () -> mDecryptedChunkFileOutput.getDigest());
+ }
+
+ @Test
+ public void getDigest_returnsCorrectDigest() throws Exception {
+ processTestChunks();
+
+ byte[] actualDigest = mDecryptedChunkFileOutput.getDigest();
+
+ MessageDigest expectedDigest =
+ MessageDigest.getInstance(DecryptedChunkFileOutput.DIGEST_ALGORITHM);
+ expectedDigest.update(TEST_CHUNK_1);
+ expectedDigest.update(TEST_CHUNK_2);
+ assertThat(actualDigest).isEqualTo(expectedDigest.digest());
+ }
+
+ @Test
+ public void getDigest_whenRunTwice_returnsIdenticalDigestBothTimes() throws Exception {
+ processTestChunks();
+
+ byte[] digest1 = mDecryptedChunkFileOutput.getDigest();
+ byte[] digest2 = mDecryptedChunkFileOutput.getDigest();
+
+ assertThat(digest1).isEqualTo(digest2);
+ }
+
+ private void processTestChunks() throws IOException {
+ mDecryptedChunkFileOutput.open();
+ mDecryptedChunkFileOutput.processChunk(Arrays.copyOf(TEST_CHUNK_1, TEST_BUFFER_LENGTH),
+ TEST_CHUNK_1.length);
+ mDecryptedChunkFileOutput.processChunk(Arrays.copyOf(TEST_CHUNK_2, TEST_BUFFER_LENGTH),
+ TEST_CHUNK_2.length);
+ mDecryptedChunkFileOutput.close();
+ }
+}
diff --git a/services/robotests/backup/src/com/android/server/backup/encryption/tasks/BackupStreamEncrypterTest.java b/services/robotests/backup/src/com/android/server/backup/encryption/tasks/BackupStreamEncrypterTest.java
new file mode 100644
index 000000000000..21c4e07577da
--- /dev/null
+++ b/services/robotests/backup/src/com/android/server/backup/encryption/tasks/BackupStreamEncrypterTest.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.encryption.tasks;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.Presubmit;
+
+import com.android.server.backup.encryption.chunk.ChunkHash;
+import com.android.server.backup.encryption.chunking.EncryptedChunk;
+import com.android.server.backup.testing.CryptoTestUtils;
+import com.android.server.backup.testing.RandomInputStream;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import java.io.ByteArrayInputStream;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Random;
+
+import javax.crypto.SecretKey;
+
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+public class BackupStreamEncrypterTest {
+ private static final int SALT_LENGTH = 32;
+ private static final int BITS_PER_BYTE = 8;
+ private static final int BYTES_PER_KILOBYTE = 1024;
+ private static final int BYTES_PER_MEGABYTE = 1024 * 1024;
+ private static final int MIN_CHUNK_SIZE = 2 * BYTES_PER_KILOBYTE;
+ private static final int AVERAGE_CHUNK_SIZE = 4 * BYTES_PER_KILOBYTE;
+ private static final int MAX_CHUNK_SIZE = 64 * BYTES_PER_KILOBYTE;
+ private static final int BACKUP_SIZE = 2 * BYTES_PER_MEGABYTE;
+ private static final int SMALL_BACKUP_SIZE = BYTES_PER_KILOBYTE;
+ // 16 bytes for the mac. iv is encoded in a separate field.
+ private static final int BYTES_OVERHEAD_PER_CHUNK = 16;
+ private static final int MESSAGE_DIGEST_SIZE_IN_BYTES = 256 / BITS_PER_BYTE;
+ private static final int RANDOM_SEED = 42;
+ private static final double TOLERANCE = 0.1;
+
+ private Random mRandom;
+ private SecretKey mSecretKey;
+ private byte[] mSalt;
+
+ @Before
+ public void setUp() throws Exception {
+ mSecretKey = CryptoTestUtils.generateAesKey();
+
+ mSalt = new byte[SALT_LENGTH];
+ // Make these tests deterministic
+ mRandom = new Random(RANDOM_SEED);
+ mRandom.nextBytes(mSalt);
+ }
+
+ @Test
+ public void testBackup_producesChunksOfTheGivenAverageSize() throws Exception {
+ BackupEncrypter.Result result = runBackup(BACKUP_SIZE);
+
+ long totalSize = 0;
+ for (EncryptedChunk chunk : result.getNewChunks()) {
+ totalSize += chunk.encryptedBytes().length;
+ }
+
+ double meanSize = totalSize / result.getNewChunks().size();
+ double expectedChunkSize = AVERAGE_CHUNK_SIZE + BYTES_OVERHEAD_PER_CHUNK;
+ assertThat(Math.abs(meanSize - expectedChunkSize) / expectedChunkSize)
+ .isLessThan(TOLERANCE);
+ }
+
+ @Test
+ public void testBackup_producesNoChunksSmallerThanMinSize() throws Exception {
+ BackupEncrypter.Result result = runBackup(BACKUP_SIZE);
+ List<EncryptedChunk> chunks = result.getNewChunks();
+
+ // Last chunk could be smaller, depending on the file size and how it is chunked
+ for (EncryptedChunk chunk : chunks.subList(0, chunks.size() - 2)) {
+ assertThat(chunk.encryptedBytes().length)
+ .isAtLeast(MIN_CHUNK_SIZE + BYTES_OVERHEAD_PER_CHUNK);
+ }
+ }
+
+ @Test
+ public void testBackup_producesNoChunksLargerThanMaxSize() throws Exception {
+ BackupEncrypter.Result result = runBackup(BACKUP_SIZE);
+ List<EncryptedChunk> chunks = result.getNewChunks();
+
+ for (EncryptedChunk chunk : chunks) {
+ assertThat(chunk.encryptedBytes().length)
+ .isAtMost(MAX_CHUNK_SIZE + BYTES_OVERHEAD_PER_CHUNK);
+ }
+ }
+
+ @Test
+ public void testBackup_producesAFileOfTheExpectedSize() throws Exception {
+ BackupEncrypter.Result result = runBackup(BACKUP_SIZE);
+ HashMap<ChunkHash, EncryptedChunk> chunksBySha256 =
+ chunksIndexedByKey(result.getNewChunks());
+
+ int expectedSize = BACKUP_SIZE + result.getAllChunks().size() * BYTES_OVERHEAD_PER_CHUNK;
+ int size = 0;
+ for (ChunkHash byteString : result.getAllChunks()) {
+ size += chunksBySha256.get(byteString).encryptedBytes().length;
+ }
+ assertThat(size).isEqualTo(expectedSize);
+ }
+
+ @Test
+ public void testBackup_forSameFile_producesNoNewChunks() throws Exception {
+ byte[] backupData = getRandomData(BACKUP_SIZE);
+ BackupEncrypter.Result result = runBackup(backupData, ImmutableList.of());
+
+ BackupEncrypter.Result incrementalResult = runBackup(backupData, result.getAllChunks());
+
+ assertThat(incrementalResult.getNewChunks()).isEmpty();
+ }
+
+ @Test
+ public void testBackup_onlyUpdatesChangedChunks() throws Exception {
+ byte[] backupData = getRandomData(BACKUP_SIZE);
+ BackupEncrypter.Result result = runBackup(backupData, ImmutableList.of());
+
+ // Let's update the 2nd and 5th chunk
+ backupData[positionOfChunk(result, 1)]++;
+ backupData[positionOfChunk(result, 4)]++;
+ BackupEncrypter.Result incrementalResult = runBackup(backupData, result.getAllChunks());
+
+ assertThat(incrementalResult.getNewChunks()).hasSize(2);
+ }
+
+ @Test
+ public void testBackup_doesNotIncludeUpdatedChunksInNewListing() throws Exception {
+ byte[] backupData = getRandomData(BACKUP_SIZE);
+ BackupEncrypter.Result result = runBackup(backupData, ImmutableList.of());
+
+ // Let's update the 2nd and 5th chunk
+ backupData[positionOfChunk(result, 1)]++;
+ backupData[positionOfChunk(result, 4)]++;
+ BackupEncrypter.Result incrementalResult = runBackup(backupData, result.getAllChunks());
+
+ List<EncryptedChunk> newChunks = incrementalResult.getNewChunks();
+ List<ChunkHash> chunkListing = result.getAllChunks();
+ assertThat(newChunks).doesNotContain(chunkListing.get(1));
+ assertThat(newChunks).doesNotContain(chunkListing.get(4));
+ }
+
+ @Test
+ public void testBackup_includesUnchangedChunksInNewListing() throws Exception {
+ byte[] backupData = getRandomData(BACKUP_SIZE);
+ BackupEncrypter.Result result = runBackup(backupData, ImmutableList.of());
+
+ // Let's update the 2nd and 5th chunk
+ backupData[positionOfChunk(result, 1)]++;
+ backupData[positionOfChunk(result, 4)]++;
+ BackupEncrypter.Result incrementalResult = runBackup(backupData, result.getAllChunks());
+
+ HashSet<ChunkHash> chunksPresentInIncremental =
+ new HashSet<>(incrementalResult.getAllChunks());
+ chunksPresentInIncremental.removeAll(result.getAllChunks());
+
+ assertThat(chunksPresentInIncremental).hasSize(2);
+ }
+
+ @Test
+ public void testBackup_forSameData_createsSameDigest() throws Exception {
+ byte[] backupData = getRandomData(SMALL_BACKUP_SIZE);
+
+ BackupEncrypter.Result result = runBackup(backupData, ImmutableList.of());
+ BackupEncrypter.Result result2 = runBackup(backupData, ImmutableList.of());
+ assertThat(result.getDigest()).isEqualTo(result2.getDigest());
+ }
+
+ @Test
+ public void testBackup_forDifferentData_createsDifferentDigest() throws Exception {
+ byte[] backup1Data = getRandomData(SMALL_BACKUP_SIZE);
+ byte[] backup2Data = getRandomData(SMALL_BACKUP_SIZE);
+
+ BackupEncrypter.Result result = runBackup(backup1Data, ImmutableList.of());
+ BackupEncrypter.Result result2 = runBackup(backup2Data, ImmutableList.of());
+ assertThat(result.getDigest()).isNotEqualTo(result2.getDigest());
+ }
+
+ @Test
+ public void testBackup_createsDigestOf32Bytes() throws Exception {
+ assertThat(runBackup(getRandomData(SMALL_BACKUP_SIZE), ImmutableList.of()).getDigest())
+ .hasLength(MESSAGE_DIGEST_SIZE_IN_BYTES);
+ }
+
+ private byte[] getRandomData(int size) throws Exception {
+ RandomInputStream randomInputStream = new RandomInputStream(mRandom, size);
+ byte[] backupData = new byte[size];
+ randomInputStream.read(backupData);
+ return backupData;
+ }
+
+ private BackupEncrypter.Result runBackup(int backupSize) throws Exception {
+ RandomInputStream dataStream = new RandomInputStream(mRandom, backupSize);
+ BackupStreamEncrypter task =
+ new BackupStreamEncrypter(
+ dataStream, MIN_CHUNK_SIZE, MAX_CHUNK_SIZE, AVERAGE_CHUNK_SIZE);
+ return task.backup(mSecretKey, mSalt, ImmutableSet.of());
+ }
+
+ private BackupEncrypter.Result runBackup(byte[] data, List<ChunkHash> existingChunks)
+ throws Exception {
+ ByteArrayInputStream dataStream = new ByteArrayInputStream(data);
+ BackupStreamEncrypter task =
+ new BackupStreamEncrypter(
+ dataStream, MIN_CHUNK_SIZE, MAX_CHUNK_SIZE, AVERAGE_CHUNK_SIZE);
+ return task.backup(mSecretKey, mSalt, ImmutableSet.copyOf(existingChunks));
+ }
+
+ /** Returns a {@link HashMap} of the chunks, indexed by the SHA-256 Mac key. */
+ private static HashMap<ChunkHash, EncryptedChunk> chunksIndexedByKey(
+ List<EncryptedChunk> chunks) {
+ HashMap<ChunkHash, EncryptedChunk> chunksByKey = new HashMap<>();
+ for (EncryptedChunk chunk : chunks) {
+ chunksByKey.put(chunk.key(), chunk);
+ }
+ return chunksByKey;
+ }
+
+ /**
+ * Returns the start position of the chunk in the plaintext backup data.
+ *
+ * @param result The result from a backup.
+ * @param index The index of the chunk in question.
+ * @return the start position.
+ */
+ private static int positionOfChunk(BackupEncrypter.Result result, int index) {
+ HashMap<ChunkHash, EncryptedChunk> byKey = chunksIndexedByKey(result.getNewChunks());
+ List<ChunkHash> listing = result.getAllChunks();
+
+ int position = 0;
+ for (int i = 0; i < index - 1; i++) {
+ EncryptedChunk chunk = byKey.get(listing.get(i));
+ position += chunk.encryptedBytes().length - BYTES_OVERHEAD_PER_CHUNK;
+ }
+
+ return position;
+ }
+}
diff --git a/services/robotests/backup/src/com/android/server/backup/testing/RandomInputStream.java b/services/robotests/backup/src/com/android/server/backup/testing/RandomInputStream.java
new file mode 100644
index 000000000000..998da0bf9696
--- /dev/null
+++ b/services/robotests/backup/src/com/android/server/backup/testing/RandomInputStream.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup.testing;
+
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Random;
+
+/** {@link InputStream} that generates random bytes up to a given length. For testing purposes. */
+public class RandomInputStream extends InputStream {
+ private static final int BYTE_MAX_VALUE = 255;
+
+ private final Random mRandom;
+ private final int mSizeBytes;
+ private int mBytesRead;
+
+ /**
+ * A new instance, generating {@code sizeBytes} from {@code random} as a source.
+ *
+ * @param random Source of random bytes.
+ * @param sizeBytes The number of bytes to generate before closing the stream.
+ */
+ public RandomInputStream(Random random, int sizeBytes) {
+ mRandom = random;
+ mSizeBytes = sizeBytes;
+ mBytesRead = 0;
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (isFinished()) {
+ return -1;
+ }
+ mBytesRead++;
+ return mRandom.nextInt(BYTE_MAX_VALUE);
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ checkArgument(off + len <= b.length);
+ if (isFinished()) {
+ return -1;
+ }
+ int length = Math.min(len, mSizeBytes - mBytesRead);
+ int end = off + length;
+
+ for (int i = off; i < end; ) {
+ for (int rnd = mRandom.nextInt(), n = Math.min(end - i, Integer.SIZE / Byte.SIZE);
+ n-- > 0;
+ rnd >>= Byte.SIZE) {
+ b[i++] = (byte) rnd;
+ }
+ }
+
+ mBytesRead += length;
+ return length;
+ }
+
+ private boolean isFinished() {
+ return mBytesRead >= mSizeBytes;
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index 748c23a24f6d..22cd3d39c982 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -25,6 +25,8 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX;
+import static com.android.server.job.JobSchedulerService.RARE_INDEX;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import static org.junit.Assert.assertEquals;
@@ -662,4 +664,86 @@ public class JobSchedulerServiceTest {
assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
}
+
+ /** Tests that rare job batching works as expected. */
+ @Test
+ public void testRareJobBatching() {
+ spyOn(mService);
+ doNothing().when(mService).evaluateControllerStatesLocked(any());
+ doNothing().when(mService).noteJobsPending(any());
+ doReturn(true).when(mService).isReadyToBeExecutedLocked(any());
+ advanceElapsedClock(24 * HOUR_IN_MILLIS);
+
+ JobSchedulerService.MaybeReadyJobQueueFunctor maybeQueueFunctor =
+ mService.new MaybeReadyJobQueueFunctor();
+ mService.mConstants.MIN_READY_NON_ACTIVE_JOBS_COUNT = 5;
+ mService.mConstants.MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS = HOUR_IN_MILLIS;
+ mService.mConstants.MIN_CONNECTIVITY_COUNT = 2;
+ mService.mConstants.MIN_READY_JOBS_COUNT = 1;
+
+ JobStatus job = createJobStatus(
+ "testRareJobBatching",
+ createJobInfo().setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY));
+ job.setStandbyBucket(RARE_INDEX);
+
+ // Not enough RARE jobs to run.
+ mService.mPendingJobs.clear();
+ maybeQueueFunctor.reset();
+ for (int i = 0; i < mService.mConstants.MIN_READY_NON_ACTIVE_JOBS_COUNT / 2; ++i) {
+ maybeQueueFunctor.accept(job);
+ assertEquals(i + 1, maybeQueueFunctor.forceBatchedCount);
+ assertEquals(i + 1, maybeQueueFunctor.runnableJobs.size());
+ assertEquals(sElapsedRealtimeClock.millis(), job.getFirstForceBatchedTimeElapsed());
+ }
+ maybeQueueFunctor.postProcess();
+ assertEquals(0, mService.mPendingJobs.size());
+
+ // Enough RARE jobs to run.
+ mService.mPendingJobs.clear();
+ maybeQueueFunctor.reset();
+ for (int i = 0; i < mService.mConstants.MIN_READY_NON_ACTIVE_JOBS_COUNT; ++i) {
+ maybeQueueFunctor.accept(job);
+ assertEquals(i + 1, maybeQueueFunctor.forceBatchedCount);
+ assertEquals(i + 1, maybeQueueFunctor.runnableJobs.size());
+ assertEquals(sElapsedRealtimeClock.millis(), job.getFirstForceBatchedTimeElapsed());
+ }
+ maybeQueueFunctor.postProcess();
+ assertEquals(5, mService.mPendingJobs.size());
+
+ // Not enough RARE jobs to run, but a non-batched job saves the day.
+ mService.mPendingJobs.clear();
+ maybeQueueFunctor.reset();
+ JobStatus activeJob = createJobStatus(
+ "testRareJobBatching",
+ createJobInfo().setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY));
+ activeJob.setStandbyBucket(ACTIVE_INDEX);
+ for (int i = 0; i < mService.mConstants.MIN_READY_NON_ACTIVE_JOBS_COUNT / 2; ++i) {
+ maybeQueueFunctor.accept(job);
+ assertEquals(i + 1, maybeQueueFunctor.forceBatchedCount);
+ assertEquals(i + 1, maybeQueueFunctor.runnableJobs.size());
+ assertEquals(sElapsedRealtimeClock.millis(), job.getFirstForceBatchedTimeElapsed());
+ }
+ maybeQueueFunctor.accept(activeJob);
+ maybeQueueFunctor.postProcess();
+ assertEquals(3, mService.mPendingJobs.size());
+
+ // Not enough RARE jobs to run, but an old RARE job saves the day.
+ mService.mPendingJobs.clear();
+ maybeQueueFunctor.reset();
+ JobStatus oldRareJob = createJobStatus("testRareJobBatching", createJobInfo());
+ oldRareJob.setStandbyBucket(RARE_INDEX);
+ final long oldBatchTime = sElapsedRealtimeClock.millis()
+ - 2 * mService.mConstants.MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS;
+ oldRareJob.setFirstForceBatchedTimeElapsed(oldBatchTime);
+ for (int i = 0; i < mService.mConstants.MIN_READY_NON_ACTIVE_JOBS_COUNT / 2; ++i) {
+ maybeQueueFunctor.accept(job);
+ assertEquals(i + 1, maybeQueueFunctor.forceBatchedCount);
+ assertEquals(i + 1, maybeQueueFunctor.runnableJobs.size());
+ assertEquals(sElapsedRealtimeClock.millis(), job.getFirstForceBatchedTimeElapsed());
+ }
+ maybeQueueFunctor.accept(oldRareJob);
+ assertEquals(oldBatchTime, oldRareJob.getFirstForceBatchedTimeElapsed());
+ maybeQueueFunctor.postProcess();
+ assertEquals(3, mService.mPendingJobs.size());
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
new file mode 100644
index 000000000000..e6c484a8dbbc
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.compat;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.pm.ApplicationInfo;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class CompatConfigTest {
+
+ private ApplicationInfo makeAppInfo(String pName, int targetSdkVersion) {
+ ApplicationInfo ai = new ApplicationInfo();
+ ai.packageName = pName;
+ ai.targetSdkVersion = targetSdkVersion;
+ return ai;
+ }
+
+ @Test
+ public void testUnknownChangeEnabled() {
+ CompatConfig pc = new CompatConfig();
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isTrue();
+ }
+
+ @Test
+ public void testDisabledChangeDisabled() {
+ CompatConfig pc = new CompatConfig();
+ pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true));
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isFalse();
+ }
+
+ @Test
+ public void testTargetSdkChangeDisabled() {
+ CompatConfig pc = new CompatConfig();
+ pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, false));
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse();
+ }
+
+ @Test
+ public void testTargetSdkChangeEnabled() {
+ CompatConfig pc = new CompatConfig();
+ pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, false));
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isTrue();
+ }
+
+ @Test
+ public void testDisabledOverrideTargetSdkChange() {
+ CompatConfig pc = new CompatConfig();
+ pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, true));
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 3))).isFalse();
+ }
+
+ @Test
+ public void testGetDisabledChanges() {
+ CompatConfig pc = new CompatConfig();
+ pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true));
+ pc.addChange(new CompatChange(2345L, "OTHER_CHANGE", -1, false));
+ assertThat(pc.getDisabledChanges(
+ makeAppInfo("com.some.package", 2))).asList().containsExactly(1234L);
+ }
+
+ @Test
+ public void testGetDisabledChangesSorted() {
+ CompatConfig pc = new CompatConfig();
+ pc.addChange(new CompatChange(1234L, "MY_CHANGE", 2, true));
+ pc.addChange(new CompatChange(123L, "OTHER_CHANGE", 2, true));
+ pc.addChange(new CompatChange(12L, "THIRD_CHANGE", 2, true));
+ assertThat(pc.getDisabledChanges(
+ makeAppInfo("com.some.package", 2))).asList().containsExactly(12L, 123L, 1234L);
+ }
+
+ @Test
+ public void testPackageOverrideEnabled() {
+ CompatConfig pc = new CompatConfig();
+ pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, true)); // disabled
+ pc.addOverride(1234L, "com.some.package", true);
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isTrue();
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isFalse();
+ }
+
+ @Test
+ public void testPackageOverrideDisabled() {
+ CompatConfig pc = new CompatConfig();
+ pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false));
+ pc.addOverride(1234L, "com.some.package", false);
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse();
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isTrue();
+ }
+
+ @Test
+ public void testPackageOverrideUnknownPackage() {
+ CompatConfig pc = new CompatConfig();
+ pc.addOverride(1234L, "com.some.package", false);
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isFalse();
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.other.package", 2))).isTrue();
+ }
+
+ @Test
+ public void testPackageOverrideUnknownChange() {
+ CompatConfig pc = new CompatConfig();
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 1))).isTrue();
+ }
+
+ @Test
+ public void testRemovePackageOverride() {
+ CompatConfig pc = new CompatConfig();
+ pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false));
+ pc.addOverride(1234L, "com.some.package", false);
+ pc.removeOverride(1234L, "com.some.package");
+ assertThat(pc.isChangeEnabled(1234L, makeAppInfo("com.some.package", 2))).isTrue();
+ }
+
+ @Test
+ public void testLookupChangeId() {
+ CompatConfig pc = new CompatConfig();
+ pc.addChange(new CompatChange(1234L, "MY_CHANGE", -1, false));
+ pc.addChange(new CompatChange(2345L, "ANOTHER_CHANGE", -1, false));
+ assertThat(pc.lookupChangeId("MY_CHANGE")).isEqualTo(1234L);
+ }
+
+ @Test
+ public void testLookupChangeIdNotPresent() {
+ CompatConfig pc = new CompatConfig();
+ assertThat(pc.lookupChangeId("MY_CHANGE")).isEqualTo(-1L);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OverlayPackagesProviderTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OverlayPackagesProviderTest.java
index 757a046e9133..a3cc915b3eba 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/OverlayPackagesProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OverlayPackagesProviderTest.java
@@ -79,7 +79,6 @@ public class OverlayPackagesProviderTest extends AndroidTestCase {
InstrumentationRegistry.getTargetContext().getCacheDir());
setSystemInputMethods();
- setIsPerProfileModeEnabled(false);
setRequiredAppsManagedDevice();
setVendorRequiredAppsManagedDevice();
setDisallowedAppsManagedDevice();
@@ -164,15 +163,6 @@ public class OverlayPackagesProviderTest extends AndroidTestCase {
}
@Test
- public void testProfileOwnerImesAreRequiredForPerProfileImeMode() {
- setSystemAppsWithLauncher("app.a", "app.b");
- setSystemInputMethods("app.a");
- setIsPerProfileModeEnabled(true);
-
- verifyAppsAreNonRequired(ACTION_PROVISION_MANAGED_PROFILE, "app.b");
- }
-
- @Test
public void testManagedUserImesAreRequired() {
setSystemAppsWithLauncher("app.a", "app.b");
setSystemInputMethods("app.a");
@@ -344,10 +334,6 @@ public class OverlayPackagesProviderTest extends AndroidTestCase {
when(mInjector.getInputMethodListAsUser(eq(TEST_USER_ID))).thenReturn(inputMethods);
}
- private void setIsPerProfileModeEnabled(boolean enabled) {
- when(mInjector.isPerProfileImeEnabled()).thenReturn(enabled);
- }
-
private void setSystemAppsWithLauncher(String... apps) {
mSystemAppsWithLauncher = apps;
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
index d3f33a152734..43bcd4fc8436 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java
@@ -36,7 +36,9 @@ import com.android.internal.util.FastXmlSerializer;
import libcore.io.IoUtils;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -56,6 +58,9 @@ import java.util.List;
@RunWith(AndroidJUnit4.class)
public class PackageInstallerSessionTest {
+ @Rule
+ public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+
private File mTmpDir;
private AtomicFile mSessionsFile;
private static final String TAG_SESSIONS = "sessions";
@@ -65,7 +70,7 @@ public class PackageInstallerSessionTest {
@Before
public void setUp() throws Exception {
- mTmpDir = IoUtils.createTemporaryDirectory("PackageInstallerSessionTest");
+ mTmpDir = mTemporaryFolder.newFolder("PackageInstallerSessionTest");
mSessionsFile = new AtomicFile(
new File(mTmpDir.getAbsolutePath() + "/sessions.xml"), "package-session");
MockitoAnnotations.initMocks(this);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index 3c3721c6b20a..13a8eb1d7fad 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -43,13 +43,14 @@ import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import libcore.io.IoUtils;
-
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import java.io.File;
+import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
@@ -62,13 +63,16 @@ import java.util.Set;
@RunWith(AndroidJUnit4.class)
@MediumTest
public class PackageParserTest {
+ @Rule
+ public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+
private File mTmpDir;
private static final File FRAMEWORK = new File("/system/framework/framework-res.apk");
@Before
- public void setUp() {
+ public void setUp() throws IOException {
// Create a new temporary directory for each of our tests.
- mTmpDir = IoUtils.createTemporaryDirectory("PackageParserTest");
+ mTmpDir = mTemporaryFolder.newFolder("PackageParserTest");
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/textservices/LazyIntToIntMapTest.java b/services/tests/servicestests/src/com/android/server/textservices/LazyIntToIntMapTest.java
deleted file mode 100644
index f80afb2ebbbf..000000000000
--- a/services/tests/servicestests/src/com/android/server/textservices/LazyIntToIntMapTest.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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.server.textservices;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.function.IntUnaryOperator;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class LazyIntToIntMapTest {
- @Test
- public void testLaziness() {
- final IntUnaryOperator func = mock(IntUnaryOperator.class);
- when(func.applyAsInt(eq(1))).thenReturn(11);
- when(func.applyAsInt(eq(2))).thenReturn(22);
-
- final LazyIntToIntMap map = new LazyIntToIntMap(func);
-
- verify(func, never()).applyAsInt(anyInt());
-
- assertEquals(22, map.get(2));
- verify(func, times(0)).applyAsInt(eq(1));
- verify(func, times(1)).applyAsInt(eq(2));
-
- // Accessing to the same key does not evaluate the function again.
- assertEquals(22, map.get(2));
- verify(func, times(0)).applyAsInt(eq(1));
- verify(func, times(1)).applyAsInt(eq(2));
- }
-
- @Test
- public void testDelete() {
- final IntUnaryOperator func1 = mock(IntUnaryOperator.class);
- when(func1.applyAsInt(eq(1))).thenReturn(11);
- when(func1.applyAsInt(eq(2))).thenReturn(22);
-
- final IntUnaryOperator func2 = mock(IntUnaryOperator.class);
- when(func2.applyAsInt(eq(1))).thenReturn(111);
- when(func2.applyAsInt(eq(2))).thenReturn(222);
-
- final AtomicReference<IntUnaryOperator> funcRef = new AtomicReference<>(func1);
- final LazyIntToIntMap map = new LazyIntToIntMap(i -> funcRef.get().applyAsInt(i));
-
- verify(func1, never()).applyAsInt(anyInt());
- verify(func2, never()).applyAsInt(anyInt());
-
- assertEquals(22, map.get(2));
- verify(func1, times(1)).applyAsInt(eq(2));
- verify(func2, times(0)).applyAsInt(eq(2));
-
- // Swap func1 with func2 then invalidate the key=2
- funcRef.set(func2);
- map.delete(2);
-
- // Calling get(2) again should re-evaluate the value.
- assertEquals(222, map.get(2));
- verify(func1, times(1)).applyAsInt(eq(2));
- verify(func2, times(1)).applyAsInt(eq(2));
-
- // Trying to delete non-existing keys does nothing.
- map.delete(1);
- }
-}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 9ecf19806f7f..f14e8d216cab 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -132,6 +132,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Xml;
+import android.widget.RemoteViews;
import androidx.annotation.Nullable;
import androidx.test.InstrumentationRegistry;
@@ -174,6 +175,7 @@ import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@@ -348,12 +350,17 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mHandler = mService.new WorkerHandler(mTestableLooper.getLooper());
// MockPackageManager - default returns ApplicationInfo with matching calling UID
mContext.setMockPackageManager(mPackageManagerClient);
- final ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.uid = mUid;
+
when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt()))
- .thenReturn(applicationInfo);
+ .thenAnswer((Answer<ApplicationInfo>) invocation -> {
+ Object[] args = invocation.getArguments();
+ return getApplicationInfo((String) args[0], mUid);
+ });
when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
- .thenReturn(applicationInfo);
+ .thenAnswer((Answer<ApplicationInfo>) invocation -> {
+ Object[] args = invocation.getArguments();
+ return getApplicationInfo((String) args[0], mUid);
+ });
when(mPackageManagerClient.getPackageUidAsUser(any(), anyInt())).thenReturn(mUid);
final LightsManager mockLightsManager = mock(LightsManager.class);
when(mockLightsManager.getLight(anyInt())).thenReturn(mock(Light.class));
@@ -389,7 +396,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
when(mAssistants.isAdjustmentAllowed(anyString())).thenReturn(true);
-
mService.init(mTestableLooper.getLooper(),
mPackageManager, mPackageManagerClient, mockLightsManager,
mListeners, mAssistants, mConditionProviders,
@@ -413,12 +419,32 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@After
public void tearDown() throws Exception {
- mFile.delete();
+ if (mFile != null) mFile.delete();
clearDeviceConfig();
InstrumentationRegistry.getInstrumentation()
.getUiAutomation().dropShellPermissionIdentity();
}
+ private ApplicationInfo getApplicationInfo(String pkg, int uid) {
+ final ApplicationInfo applicationInfo = new ApplicationInfo();
+ applicationInfo.uid = uid;
+ switch (pkg) {
+ case PKG_N_MR1:
+ applicationInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1;
+ break;
+ case PKG_O:
+ applicationInfo.targetSdkVersion = Build.VERSION_CODES.O;
+ break;
+ case PKG_P:
+ applicationInfo.targetSdkVersion = Build.VERSION_CODES.P;
+ break;
+ default:
+ applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
+ break;
+ }
+ return applicationInfo;
+ }
+
public void waitForIdle() {
mTestableLooper.processAllMessages();
}
@@ -5122,4 +5148,66 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertEquals(1, notifsAfter.length);
assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0);
}
+
+ @Test
+ public void testRemoveLargeRemoteViews() throws Exception {
+ int removeSize = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes);
+
+ RemoteViews rv = mock(RemoteViews.class);
+ when(rv.estimateMemoryUsage()).thenReturn(removeSize);
+ when(rv.clone()).thenReturn(rv);
+ RemoteViews rv1 = mock(RemoteViews.class);
+ when(rv1.estimateMemoryUsage()).thenReturn(removeSize);
+ when(rv1.clone()).thenReturn(rv1);
+ RemoteViews rv2 = mock(RemoteViews.class);
+ when(rv2.estimateMemoryUsage()).thenReturn(removeSize);
+ when(rv2.clone()).thenReturn(rv2);
+ RemoteViews rv3 = mock(RemoteViews.class);
+ when(rv3.estimateMemoryUsage()).thenReturn(removeSize);
+ when(rv3.clone()).thenReturn(rv3);
+ RemoteViews rv4 = mock(RemoteViews.class);
+ when(rv4.estimateMemoryUsage()).thenReturn(removeSize);
+ when(rv4.clone()).thenReturn(rv4);
+ // note: different!
+ RemoteViews rv5 = mock(RemoteViews.class);
+ when(rv5.estimateMemoryUsage()).thenReturn(removeSize - 1);
+ when(rv5.clone()).thenReturn(rv5);
+
+ Notification np = new Notification.Builder(mContext, "test")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .setContentText("test")
+ .setCustomContentView(rv)
+ .setCustomBigContentView(rv1)
+ .setCustomHeadsUpContentView(rv2)
+ .build();
+ Notification n = new Notification.Builder(mContext, "test")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .setContentText("test")
+ .setCustomContentView(rv3)
+ .setCustomBigContentView(rv4)
+ .setCustomHeadsUpContentView(rv5)
+ .setPublicVersion(np)
+ .build();
+
+ assertNotNull(np.contentView);
+ assertNotNull(np.bigContentView);
+ assertNotNull(np.headsUpContentView);
+
+ assertTrue(n.publicVersion.extras.containsKey(Notification.EXTRA_CONTAINS_CUSTOM_VIEW));
+ assertNotNull(n.publicVersion.contentView);
+ assertNotNull(n.publicVersion.bigContentView);
+ assertNotNull(n.publicVersion.headsUpContentView);
+
+ mService.fixNotification(n, PKG, "tag", 9, 0);
+
+ assertNull(n.contentView);
+ assertNull(n.bigContentView);
+ assertNotNull(n.headsUpContentView);
+ assertNull(n.publicVersion.contentView);
+ assertNull(n.publicVersion.bigContentView);
+ assertNull(n.publicVersion.headsUpContentView);
+
+ verify(mUsageStats, times(5)).registerImageRemoved(PKG);
+ }
}
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 f49a57534938..c5e7c47919fc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -26,8 +26,13 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
import static android.view.DisplayCutout.fromBoundingRect;
+import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
+import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+import static android.view.View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
@@ -663,8 +668,8 @@ public class DisplayContentTests extends WindowTestsBase {
dc.onDescendantOrientationChanged(window.mToken.token, activityRecord));
final ArgumentCaptor<Configuration> captor = ArgumentCaptor.forClass(Configuration.class);
- verify(mWm.mAtmService).updateDisplayOverrideConfigurationLocked(captor.capture(),
- same(activityRecord), anyBoolean(), eq(dc.getDisplayId()));
+ verify(dc.mAcitvityDisplay).updateDisplayOverrideConfigurationLocked(captor.capture(),
+ same(activityRecord), anyBoolean(), same(null));
final Configuration newDisplayConfig = captor.getValue();
assertEquals(Configuration.ORIENTATION_PORTRAIT, newDisplayConfig.orientation);
}
@@ -688,8 +693,8 @@ public class DisplayContentTests extends WindowTestsBase {
assertFalse("Display shouldn't rotate to handle orientation request if fixed to"
+ " user rotation.",
dc.onDescendantOrientationChanged(window.mToken.token, activityRecord));
- verify(mWm.mAtmService, never()).updateDisplayOverrideConfigurationLocked(any(),
- eq(activityRecord), anyBoolean(), eq(dc.getDisplayId()));
+ verify(dc.mAcitvityDisplay, never()).updateDisplayOverrideConfigurationLocked(any(),
+ eq(activityRecord), anyBoolean(), same(null));
}
@Test
@@ -789,6 +794,58 @@ public class DisplayContentTests extends WindowTestsBase {
}
@Test
+ public void testCalculateSystemGestureExclusion_modal() throws Exception {
+ final DisplayContent dc = createNewDisplay();
+ final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "base");
+ win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
+ win.setSystemGestureExclusion(Collections.singletonList(new Rect(0, 0, 1000, 1000)));
+
+ final WindowState win2 = createWindow(null, TYPE_APPLICATION, dc, "modal");
+ win2.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
+ win2.getAttrs().privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION;
+ win2.getAttrs().width = 10;
+ win2.getAttrs().height = 10;
+ win2.setSystemGestureExclusion(Collections.emptyList());
+
+ dc.setLayoutNeeded();
+ dc.performLayout(true /* initial */, false /* updateImeWindows */);
+
+ win.setHasSurface(true);
+ win2.setHasSurface(true);
+
+ final Region expected = Region.obtain();
+ assertEquals(expected, dc.calculateSystemGestureExclusion());
+ }
+
+ @Test
+ public void testCalculateSystemGestureExclusion_immersiveStickyLegacyWindow() throws Exception {
+ synchronized (mWm.mGlobalLock) {
+ mWm.mSystemGestureExcludedByPreQStickyImmersive = true;
+
+ final DisplayContent dc = createNewDisplay();
+ final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win");
+ win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
+ win.getAttrs().layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+ win.getAttrs().privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION;
+ win.getAttrs().subtreeSystemUiVisibility = win.mSystemUiVisibility =
+ SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ | SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+ win.mAppToken.mTargetSdk = P;
+
+ dc.setLayoutNeeded();
+ dc.performLayout(true /* initial */, false /* updateImeWindows */);
+
+ win.setHasSurface(true);
+
+ final Region expected = Region.obtain();
+ expected.set(dc.getBounds());
+ assertEquals(expected, dc.calculateSystemGestureExclusion());
+
+ win.setHasSurface(false);
+ }
+ }
+
+ @Test
public void testOrientationChangeLogging() {
MetricsLogger mockLogger = mock(MetricsLogger.class);
Configuration oldConfig = new Configuration();
diff --git a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java
index 558672609304..daee9110543d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/HighRefreshRateBlacklistTest.java
@@ -16,71 +16,168 @@
package com.android.server.wm;
+import static android.provider.DeviceConfig.WindowManager.KEY_HIGH_REFRESH_RATE_BLACKLIST;
+
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import android.content.res.Resources;
import android.platform.test.annotations.Presubmit;
+import android.provider.DeviceConfig;
+import android.util.Pair;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
-import com.android.server.wm.HighRefreshRateBlacklist.SystemPropertyGetter;
+import com.android.internal.R;
+import com.android.server.wm.HighRefreshRateBlacklist.DeviceConfigInterface;
import org.junit.Test;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+
/**
* Build/Install/Run:
- * atest WmTests:HighRefreshRateBlacklistTest
+ * atest WmTests:HighRefreshRateBlacklistTest
*/
@SmallTest
@Presubmit
-@FlakyTest
public class HighRefreshRateBlacklistTest {
@Test
- public void testBlacklist() {
- HighRefreshRateBlacklist blacklist = new HighRefreshRateBlacklist(
- new SystemPropertyGetter() {
-
- @Override
- public int getInt(String key, int def) {
- if ("ro.window_manager.high_refresh_rate_blacklist_length".equals(key)) {
- return 2;
- }
- return def;
- }
-
- @Override
- public String get(String key) {
- if ("ro.window_manager.high_refresh_rate_blacklist_entry1".equals(key)) {
- return "com.android.sample1";
- }
- if ("ro.window_manager.high_refresh_rate_blacklist_entry2".equals(key)) {
- return "com.android.sample2";
- }
- return "";
- }
- });
+ public void testDefaultBlacklist() {
+ final Resources r = createResources("com.android.sample1", "com.android.sample2");
+ HighRefreshRateBlacklist blacklist =
+ new HighRefreshRateBlacklist(r, new FakeDeviceConfigInterface());
assertTrue(blacklist.isBlacklisted("com.android.sample1"));
assertTrue(blacklist.isBlacklisted("com.android.sample2"));
assertFalse(blacklist.isBlacklisted("com.android.sample3"));
}
@Test
- public void testNoBlacklist() {
- HighRefreshRateBlacklist blacklist = new HighRefreshRateBlacklist(
- new SystemPropertyGetter() {
-
- @Override
- public int getInt(String key, int def) {
- return def;
- }
-
- @Override
- public String get(String key) {
- return "";
- }
- });
+ public void testNoDefaultBlacklist() {
+ final Resources r = createResources();
+ HighRefreshRateBlacklist blacklist =
+ new HighRefreshRateBlacklist(r, new FakeDeviceConfigInterface());
+ assertFalse(blacklist.isBlacklisted("com.android.sample1"));
+ }
+
+ @Test
+ public void testDefaultBlacklistIsOverriddenByDeviceConfig() {
+ final Resources r = createResources("com.android.sample1");
+ final FakeDeviceConfigInterface config = new FakeDeviceConfigInterface();
+ config.setBlacklist("com.android.sample2,com.android.sample3");
+ HighRefreshRateBlacklist blacklist = new HighRefreshRateBlacklist(r, config);
+ assertFalse(blacklist.isBlacklisted("com.android.sample1"));
+ assertTrue(blacklist.isBlacklisted("com.android.sample2"));
+ assertTrue(blacklist.isBlacklisted("com.android.sample3"));
+ }
+
+ @Test
+ public void testDefaultBlacklistIsOverriddenByEmptyDeviceConfig() {
+ final Resources r = createResources("com.android.sample1");
+ final FakeDeviceConfigInterface config = new FakeDeviceConfigInterface();
+ config.setBlacklist("");
+ HighRefreshRateBlacklist blacklist = new HighRefreshRateBlacklist(r, config);
+ assertFalse(blacklist.isBlacklisted("com.android.sample1"));
+ }
+
+ @Test
+ public void testDefaultBlacklistIsOverriddenByDeviceConfigUpdate() {
+ final Resources r = createResources("com.android.sample1");
+ final FakeDeviceConfigInterface config = new FakeDeviceConfigInterface();
+ HighRefreshRateBlacklist blacklist = new HighRefreshRateBlacklist(r, config);
+
+ // First check that the default blacklist is in effect
+ assertTrue(blacklist.isBlacklisted("com.android.sample1"));
+ assertFalse(blacklist.isBlacklisted("com.android.sample2"));
+ assertFalse(blacklist.isBlacklisted("com.android.sample3"));
+
+ // Then confirm that the DeviceConfig list has propagated and taken effect.
+ config.setBlacklist("com.android.sample2,com.android.sample3");
assertFalse(blacklist.isBlacklisted("com.android.sample1"));
+ assertTrue(blacklist.isBlacklisted("com.android.sample2"));
+ assertTrue(blacklist.isBlacklisted("com.android.sample3"));
+
+ // Finally make sure we go back to the default list if the DeviceConfig gets deleted.
+ config.setBlacklist(null);
+ assertTrue(blacklist.isBlacklisted("com.android.sample1"));
+ assertFalse(blacklist.isBlacklisted("com.android.sample2"));
+ assertFalse(blacklist.isBlacklisted("com.android.sample3"));
+ }
+
+ private Resources createResources(String... defaultBlacklist) {
+ Resources r = mock(Resources.class);
+ when(r.getStringArray(R.array.config_highRefreshRateBlacklist))
+ .thenReturn(defaultBlacklist);
+ return r;
+ }
+
+
+ class FakeDeviceConfigInterface implements DeviceConfigInterface {
+ private List<Pair<DeviceConfig.OnPropertiesChangedListener, Executor>> mListeners =
+ new ArrayList<>();
+ private String mBlacklist;
+
+ @Override
+ public String getProperty(String namespace, String name) {
+ if (!DeviceConfig.NAMESPACE_WINDOW_MANAGER.equals(namespace)
+ || !KEY_HIGH_REFRESH_RATE_BLACKLIST.equals(name)) {
+ throw new IllegalArgumentException("Only things in NAMESPACE_WINDOW_MANAGER "
+ + "supported.");
+ }
+ return mBlacklist;
+ }
+
+ @Override
+ public void addOnPropertiesChangedListener(String namespace, Executor executor,
+ DeviceConfig.OnPropertiesChangedListener listener) {
+
+ if (!DeviceConfig.NAMESPACE_WINDOW_MANAGER.equals(namespace)) {
+ throw new IllegalArgumentException("Only things in NAMESPACE_WINDOW_MANAGER "
+ + "supported.");
+ }
+ mListeners.add(new Pair<>(listener, executor));
+ }
+
+ void setBlacklist(String blacklist) {
+ mBlacklist = blacklist;
+ CountDownLatch latch = new CountDownLatch(mListeners.size());
+ for (Pair<DeviceConfig.OnPropertiesChangedListener, Executor> listenerInfo :
+ mListeners) {
+ final Executor executor = listenerInfo.second;
+ final DeviceConfig.OnPropertiesChangedListener listener = listenerInfo.first;
+ DeviceConfig.Properties properties = createBlacklistProperties(blacklist);
+ executor.execute(() -> {
+ listener.onPropertiesChanged(properties);
+ latch.countDown();
+ });
+ }
+ try {
+ latch.await(10, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException("Failed to notify all blacklist listeners in time.", e);
+ }
+ }
+
+ private DeviceConfig.Properties createBlacklistProperties(final String blacklist) {
+ DeviceConfig.Properties properties = mock(DeviceConfig.Properties.class);
+ when(properties.getString(anyString(), any())).thenAnswer(invocation -> {
+ final Object[] args = invocation.getArguments();
+ if (KEY_HIGH_REFRESH_RATE_BLACKLIST.equals(args[0])) {
+ return blacklist;
+ } else {
+ return args[1];
+ }
+ });
+ return properties;
+ }
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index c4b0a802a8d8..29398b6b6e75 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -76,7 +76,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
@Before
public void setUp() throws Exception {
mActivity = new ActivityBuilder(mService).build();
- mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1;
+ mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1;
mActivity.info.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
mTarget = new TaskLaunchParamsModifier(mSupervisor);
@@ -402,7 +402,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
mCurrent.mBounds.set(0, 0, 200, 100);
- mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.CUPCAKE;
+ mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUPCAKE;
assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
mActivity, /* source */ null, options, mCurrent, mResult));
@@ -424,7 +424,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
mCurrent.mBounds.set(0, 0, 200, 100);
- mActivity.appInfo.flags = 0;
+ mActivity.info.applicationInfo.flags = 0;
assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
mActivity, /* source */ null, options, mCurrent, mResult));
@@ -525,7 +525,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchDisplayId(freeformDisplay.mDisplayId);
- mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+ mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
mActivity, /* source */ null, options, mCurrent, mResult));
@@ -539,7 +539,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchDisplayId(DEFAULT_DISPLAY);
- mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+ mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
mActivity, /* source */ null, options, mCurrent, mResult));
@@ -892,7 +892,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchDisplayId(freeformDisplay.mDisplayId);
- mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+ mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
mActivity, /* source */ null, options, mCurrent, mResult));
@@ -916,7 +916,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
final ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchDisplayId(freeformDisplay.mDisplayId);
- mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+ mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
mActivity, /* source */ null, options, mCurrent, mResult));
@@ -941,7 +941,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
final ActivityRecord source = createSourceActivity(freeformDisplay);
source.setBounds(0, 0, 412, 732);
- mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+ mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
mActivity, source, options, mCurrent, mResult));
@@ -968,7 +968,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
final ActivityRecord source = createSourceActivity(freeformDisplay);
source.setBounds(0, 0, 200, 400);
- mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+ mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
mActivity, source, options, mCurrent, mResult));
@@ -990,7 +990,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
final ActivityRecord source = createSourceActivity(freeformDisplay);
source.setBounds(1720, 680, 1920, 1080);
- mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+ mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
mActivity, source, options, mCurrent, mResult));
@@ -1012,7 +1012,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
mCurrent.mBounds.set(100, 200, 2120, 1380);
- mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+ mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
mActivity, /* source */ null, options, mCurrent, mResult));
@@ -1038,7 +1038,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
mCurrent.mWindowingMode = WINDOWING_MODE_FREEFORM;
mCurrent.mBounds.set(100, 200, 2120, 1380);
- mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+ mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, /* layout */ null,
mActivity, /* source */ null, options, mCurrent, mResult));
@@ -1058,7 +1058,7 @@ public class TaskLaunchParamsModifierTests extends ActivityTestsBase {
final ActivityInfo.WindowLayout layout = new WindowLayoutBuilder()
.setMinWidth(500).setMinHeight(800).build();
- mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
+ mActivity.info.applicationInfo.targetSdkVersion = Build.VERSION_CODES.LOLLIPOP;
assertEquals(RESULT_CONTINUE, mTarget.onCalculate(/* task */ null, layout, mActivity,
/* source */ null, options, mCurrent, mResult));
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 1c9e50425841..2e5ce69a8564 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -49,6 +49,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
int mRotationToReport = 0;
boolean mKeyguardShowingAndNotOccluded = false;
+ boolean mOkToAnimate = true;
private Runnable mRunnableWhenAddingSplashScreen;
@@ -222,7 +223,7 @@ class TestWindowManagerPolicy implements WindowManagerPolicy {
@Override
public boolean okToAnimate() {
- return true;
+ return mOkToAnimate;
}
@Override
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 7c4198857b5e..7f7a78bd1d17 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -909,6 +909,8 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
if (!mScreenLocked && mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE) {
// If the screen is unlocked, also set current functions.
setScreenUnlockedFunctions();
+ } else {
+ setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
}
break;
case MSG_UPDATE_SCREEN_LOCK:
diff --git a/startop/apps/ColorChanging/.gitignore b/startop/apps/ColorChanging/.gitignore
new file mode 100644
index 000000000000..2b75303ac58f
--- /dev/null
+++ b/startop/apps/ColorChanging/.gitignore
@@ -0,0 +1,13 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
diff --git a/startop/apps/ColorChanging/.idea/encodings.xml b/startop/apps/ColorChanging/.idea/encodings.xml
new file mode 100644
index 000000000000..15a15b218a29
--- /dev/null
+++ b/startop/apps/ColorChanging/.idea/encodings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="Encoding" addBOMForNewFiles="with NO BOM" />
+</project> \ No newline at end of file
diff --git a/startop/apps/ColorChanging/.idea/gradle.xml b/startop/apps/ColorChanging/.idea/gradle.xml
new file mode 100644
index 000000000000..2996d531255e
--- /dev/null
+++ b/startop/apps/ColorChanging/.idea/gradle.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="GradleSettings">
+ <option name="linkedExternalProjectsSettings">
+ <GradleProjectSettings>
+ <compositeConfiguration>
+ <compositeBuild compositeDefinitionSource="SCRIPT" />
+ </compositeConfiguration>
+ <option name="distributionType" value="DEFAULT_WRAPPED" />
+ <option name="externalProjectPath" value="$PROJECT_DIR$" />
+ <option name="resolveModulePerSourceSet" value="false" />
+ </GradleProjectSettings>
+ </option>
+ </component>
+</project> \ No newline at end of file
diff --git a/startop/apps/ColorChanging/.idea/misc.xml b/startop/apps/ColorChanging/.idea/misc.xml
new file mode 100644
index 000000000000..37a750962da6
--- /dev/null
+++ b/startop/apps/ColorChanging/.idea/misc.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
+ <output url="file://$PROJECT_DIR$/build/classes" />
+ </component>
+ <component name="ProjectType">
+ <option name="id" value="Android" />
+ </component>
+</project> \ No newline at end of file
diff --git a/startop/apps/ColorChanging/.idea/runConfigurations.xml b/startop/apps/ColorChanging/.idea/runConfigurations.xml
new file mode 100644
index 000000000000..7f68460d8b38
--- /dev/null
+++ b/startop/apps/ColorChanging/.idea/runConfigurations.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="RunConfigurationProducerService">
+ <option name="ignoredProducers">
+ <set>
+ <option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
+ <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
+ <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
+ </set>
+ </option>
+ </component>
+</project> \ No newline at end of file
diff --git a/startop/apps/ColorChanging/README.md b/startop/apps/ColorChanging/README.md
new file mode 100644
index 000000000000..eb8b9cc1103b
--- /dev/null
+++ b/startop/apps/ColorChanging/README.md
@@ -0,0 +1,5 @@
+This directory contains a simple Android app that is meant to help in
+syncing a trace along with a video in Perfetto.
+
+This app changes the colors of the screen that has traces to go along
+with the colors.
diff --git a/startop/apps/ColorChanging/app/.gitignore b/startop/apps/ColorChanging/app/.gitignore
new file mode 100644
index 000000000000..796b96d1c402
--- /dev/null
+++ b/startop/apps/ColorChanging/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/startop/apps/ColorChanging/app/build.gradle b/startop/apps/ColorChanging/app/build.gradle
new file mode 100644
index 000000000000..ab955aaf90ee
--- /dev/null
+++ b/startop/apps/ColorChanging/app/build.gradle
@@ -0,0 +1,29 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 29
+ buildToolsVersion "29.0.0"
+ defaultConfig {
+ applicationId "com.android.startop.colorchanging"
+ minSdkVersion 15
+ targetSdkVersion 29
+ versionCode 1
+ versionName "1.0"
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation 'androidx.appcompat:appcompat:1.0.2'
+ implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
+ testImplementation 'junit:junit:4.12'
+ androidTestImplementation 'androidx.test:runner:1.2.0'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+}
diff --git a/startop/apps/ColorChanging/app/proguard-rules.pro b/startop/apps/ColorChanging/app/proguard-rules.pro
new file mode 100644
index 000000000000..f1b424510da5
--- /dev/null
+++ b/startop/apps/ColorChanging/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/startop/apps/ColorChanging/app/src/androidTest/java/com/android/startop/colorchanging/ExampleInstrumentedTest.java b/startop/apps/ColorChanging/app/src/androidTest/java/com/android/startop/colorchanging/ExampleInstrumentedTest.java
new file mode 100644
index 000000000000..31736f3e2862
--- /dev/null
+++ b/startop/apps/ColorChanging/app/src/androidTest/java/com/android/startop/colorchanging/ExampleInstrumentedTest.java
@@ -0,0 +1,27 @@
+package com.android.startop.colorchanging;
+
+import android.content.Context;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getTargetContext();
+
+ assertEquals("com.android.startop.colorchanging", appContext.getPackageName());
+ }
+}
diff --git a/startop/apps/ColorChanging/app/src/main/AndroidManifest.xml b/startop/apps/ColorChanging/app/src/main/AndroidManifest.xml
new file mode 100644
index 000000000000..37193b5ff596
--- /dev/null
+++ b/startop/apps/ColorChanging/app/src/main/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.startop.colorchanging">
+
+ <application
+ android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:roundIcon="@mipmap/ic_launcher_round"
+ android:supportsRtl="true"
+ android:theme="@style/AppTheme">
+ <activity android:name="com.android.startop.colorchanging.MainActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest> \ No newline at end of file
diff --git a/startop/apps/ColorChanging/app/src/main/java/com/android/startop/colorchanging/MainActivity.java b/startop/apps/ColorChanging/app/src/main/java/com/android/startop/colorchanging/MainActivity.java
new file mode 100644
index 000000000000..b8f4faf299a9
--- /dev/null
+++ b/startop/apps/ColorChanging/app/src/main/java/com/android/startop/colorchanging/MainActivity.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.startop.colorchanging;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+import android.os.Bundle;
+import android.os.Trace;
+import android.view.View;
+
+public class MainActivity extends AppCompatActivity {
+ View view;
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ view = this.getWindow().getDecorView();
+ view.setBackgroundResource(R.color.gray);
+ Trace.beginSection("gray");
+ }
+
+ public void goRed(View v) {
+ Trace.endSection();
+ view.setBackgroundResource(R.color.red);
+ Trace.beginSection("red");
+ }
+
+ public void goOrange(View v) {
+ Trace.endSection();
+ view.setBackgroundResource(R.color.orange);
+ Trace.beginSection("orange");
+ }
+
+ public void goYellow(View v) {
+ Trace.endSection();
+ view.setBackgroundResource(R.color.yellow);
+ Trace.beginSection("yellow");
+ }
+
+ public void goGreen(View v) {
+ Trace.endSection();
+ view.setBackgroundResource(R.color.green);
+ Trace.beginSection("green");
+ }
+
+ public void goBlue(View v) {
+ Trace.endSection();
+ view.setBackgroundResource(R.color.blue);
+ Trace.beginSection("blue");
+ }
+
+ public void goIndigo(View v) {
+ Trace.endSection();
+ view.setBackgroundResource(R.color.indigo);
+ Trace.beginSection("indigo");
+ }
+
+ public void goViolet(View v) {
+ Trace.endSection();
+ view.setBackgroundResource(R.color.violet);
+ Trace.beginSection("violet");
+ }
+
+ public void goCyan(View v) {
+ Trace.endSection();
+ view.setBackgroundResource(R.color.cyan);
+ Trace.beginSection("cyan");
+ }
+
+ public void goBlack(View v) {
+ Trace.endSection();
+ view.setBackgroundResource(R.color.black);
+ Trace.beginSection("black");
+ }
+
+}
diff --git a/startop/apps/ColorChanging/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/startop/apps/ColorChanging/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 000000000000..1f6bb290603d
--- /dev/null
+++ b/startop/apps/ColorChanging/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:fillType="evenOdd"
+ android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
+ android:strokeWidth="1"
+ android:strokeColor="#00000000">
+ <aapt:attr name="android:fillColor">
+ <gradient
+ android:endX="78.5885"
+ android:endY="90.9159"
+ android:startX="48.7653"
+ android:startY="61.0927"
+ android:type="linear">
+ <item
+ android:color="#44000000"
+ android:offset="0.0" />
+ <item
+ android:color="#00000000"
+ android:offset="1.0" />
+ </gradient>
+ </aapt:attr>
+ </path>
+ <path
+ android:fillColor="#FFFFFF"
+ android:fillType="nonZero"
+ android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
+ android:strokeWidth="1"
+ android:strokeColor="#00000000" />
+</vector>
diff --git a/startop/apps/ColorChanging/app/src/main/res/drawable/ic_launcher_background.xml b/startop/apps/ColorChanging/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 000000000000..0d025f9bf6b6
--- /dev/null
+++ b/startop/apps/ColorChanging/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108"
+ android:viewportHeight="108">
+ <path
+ android:fillColor="#008577"
+ android:pathData="M0,0h108v108h-108z" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M9,0L9,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,0L19,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M29,0L29,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M39,0L39,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M49,0L49,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M59,0L59,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M69,0L69,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M79,0L79,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M89,0L89,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M99,0L99,108"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,9L108,9"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,19L108,19"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,29L108,29"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,39L108,39"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,49L108,49"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,59L108,59"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,69L108,69"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,79L108,79"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,89L108,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0,99L108,99"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,29L89,29"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,39L89,39"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,49L89,49"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,59L89,59"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,69L89,69"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M19,79L89,79"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M29,19L29,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M39,19L39,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M49,19L49,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M59,19L59,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M69,19L69,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M79,19L79,89"
+ android:strokeWidth="0.8"
+ android:strokeColor="#33FFFFFF" />
+</vector>
diff --git a/startop/apps/ColorChanging/app/src/main/res/layout/activity_main.xml b/startop/apps/ColorChanging/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 000000000000..fb18df79cce2
--- /dev/null
+++ b/startop/apps/ColorChanging/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".MainActivity">
+
+ <Button
+ android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:layout_marginLeft="16dp"
+ android:layout_marginTop="16dp"
+ android:onClick="goRed"
+ android:text="red"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <Button
+ android:id="@+id/button4"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:layout_marginEnd="16dp"
+ android:layout_marginRight="16dp"
+ android:onClick="goYellow"
+ android:text="YELLOW"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <Button
+ android:id="@+id/button6"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:layout_marginLeft="16dp"
+ android:layout_marginTop="32dp"
+ android:onClick="goGreen"
+ android:text="GREEN"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/button" />
+
+ <Button
+ android:id="@+id/button7"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="165dp"
+ android:layout_marginLeft="165dp"
+ android:layout_marginTop="115dp"
+ android:layout_marginEnd="165dp"
+ android:layout_marginRight="165dp"
+ android:onClick="goViolet"
+ android:text="VIOLET"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0.428"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/button8" />
+
+ <Button
+ android:id="@+id/button10"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="165dp"
+ android:layout_marginLeft="165dp"
+ android:layout_marginTop="32dp"
+ android:layout_marginEnd="165dp"
+ android:layout_marginRight="165dp"
+ android:onClick="goBlue"
+ android:text="BLUE"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/button8" />
+
+ <Button
+ android:id="@+id/button8"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="165dp"
+ android:layout_marginLeft="165dp"
+ android:layout_marginTop="16dp"
+ android:layout_marginEnd="165dp"
+ android:layout_marginRight="165dp"
+ android:onClick="goOrange"
+ android:text="ORANGE"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <Button
+ android:id="@+id/button11"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="32dp"
+ android:layout_marginEnd="16dp"
+ android:layout_marginRight="16dp"
+ android:onClick="goIndigo"
+ android:text="INDIGO"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/button4" />
+
+ <Button
+ android:id="@+id/button12"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="162dp"
+ android:layout_marginLeft="162dp"
+ android:layout_marginTop="25dp"
+ android:layout_marginEnd="161dp"
+ android:layout_marginRight="161dp"
+ android:onClick="goCyan"
+ android:text="CYAN"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/button7" />
+
+ <Button
+ android:id="@+id/button13"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="162dp"
+ android:layout_marginLeft="162dp"
+ android:layout_marginTop="25dp"
+ android:layout_marginEnd="161dp"
+ android:layout_marginRight="161dp"
+ android:onClick="goBlack"
+ android:text="BLACK"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/button12" />
+</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
diff --git a/startop/apps/ColorChanging/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/startop/apps/ColorChanging/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 000000000000..eca70cfe52ea
--- /dev/null
+++ b/startop/apps/ColorChanging/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/ic_launcher_background" />
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon> \ No newline at end of file
diff --git a/startop/apps/ColorChanging/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/startop/apps/ColorChanging/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 000000000000..eca70cfe52ea
--- /dev/null
+++ b/startop/apps/ColorChanging/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@drawable/ic_launcher_background" />
+ <foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon> \ No newline at end of file
diff --git a/startop/apps/ColorChanging/app/src/main/res/mipmap-hdpi/ic_launcher.png b/startop/apps/ColorChanging/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000000..898f3ed59ac9
--- /dev/null
+++ b/startop/apps/ColorChanging/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/startop/apps/ColorChanging/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/startop/apps/ColorChanging/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 000000000000..dffca3601eba
--- /dev/null
+++ b/startop/apps/ColorChanging/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/startop/apps/ColorChanging/app/src/main/res/mipmap-mdpi/ic_launcher.png b/startop/apps/ColorChanging/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000000..64ba76f75e9c
--- /dev/null
+++ b/startop/apps/ColorChanging/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/startop/apps/ColorChanging/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/startop/apps/ColorChanging/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 000000000000..dae5e082342f
--- /dev/null
+++ b/startop/apps/ColorChanging/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/startop/apps/ColorChanging/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/startop/apps/ColorChanging/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000000..e5ed46597ea8
--- /dev/null
+++ b/startop/apps/ColorChanging/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/startop/apps/ColorChanging/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/startop/apps/ColorChanging/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 000000000000..14ed0af35023
--- /dev/null
+++ b/startop/apps/ColorChanging/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/startop/apps/ColorChanging/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/startop/apps/ColorChanging/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000000..b0907cac3bfd
--- /dev/null
+++ b/startop/apps/ColorChanging/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/startop/apps/ColorChanging/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/startop/apps/ColorChanging/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 000000000000..d8ae03154975
--- /dev/null
+++ b/startop/apps/ColorChanging/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/startop/apps/ColorChanging/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/startop/apps/ColorChanging/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000000..2c18de9e6610
--- /dev/null
+++ b/startop/apps/ColorChanging/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/startop/apps/ColorChanging/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/startop/apps/ColorChanging/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 000000000000..beed3cdd2c32
--- /dev/null
+++ b/startop/apps/ColorChanging/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/startop/apps/ColorChanging/app/src/main/res/values/colors.xml b/startop/apps/ColorChanging/app/src/main/res/values/colors.xml
new file mode 100644
index 000000000000..209790fed1cd
--- /dev/null
+++ b/startop/apps/ColorChanging/app/src/main/res/values/colors.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <color name="colorPrimary">#008577</color>
+ <color name="colorPrimaryDark">#00574B</color>
+ <color name="colorAccent">#D81B60</color>
+ <color name="black">#000000</color>
+ <color name="red">#F44336</color>
+ <color name="green">#2CF035</color>
+ <color name="blue">#2C70F0</color>
+ <color name="yellow">#F0EA2C</color>
+ <color name="gray">#D3D3D3</color>
+ <color name="orange">#E57E0A</color>
+ <color name="indigo">#4B0082</color>
+ <color name="violet">#EE82EE</color>
+ <color name="cyan">#00E8FF</color>
+</resources>
diff --git a/startop/apps/ColorChanging/app/src/main/res/values/strings.xml b/startop/apps/ColorChanging/app/src/main/res/values/strings.xml
new file mode 100644
index 000000000000..ff062fb274bf
--- /dev/null
+++ b/startop/apps/ColorChanging/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+ <string name="app_name">ColorChanging</string>
+</resources>
diff --git a/startop/apps/ColorChanging/app/src/main/res/values/styles.xml b/startop/apps/ColorChanging/app/src/main/res/values/styles.xml
new file mode 100644
index 000000000000..5885930df6d1
--- /dev/null
+++ b/startop/apps/ColorChanging/app/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+<resources>
+
+ <!-- Base application theme. -->
+ <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+ <!-- Customize your theme here. -->
+ <item name="colorPrimary">@color/colorPrimary</item>
+ <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+ <item name="colorAccent">@color/colorAccent</item>
+ </style>
+
+</resources>
diff --git a/startop/apps/ColorChanging/app/src/test/java/com/android/startop/colorchanging/ExampleUnitTest.java b/startop/apps/ColorChanging/app/src/test/java/com/android/startop/colorchanging/ExampleUnitTest.java
new file mode 100644
index 000000000000..8423674b9d75
--- /dev/null
+++ b/startop/apps/ColorChanging/app/src/test/java/com/android/startop/colorchanging/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.android.startop.colorchanging;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+} \ No newline at end of file
diff --git a/startop/apps/ColorChanging/build.gradle b/startop/apps/ColorChanging/build.gradle
new file mode 100644
index 000000000000..a960ab34dc6e
--- /dev/null
+++ b/startop/apps/ColorChanging/build.gradle
@@ -0,0 +1,24 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.4.1'
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/startop/apps/ColorChanging/gradle.properties b/startop/apps/ColorChanging/gradle.properties
new file mode 100644
index 000000000000..199d16ede38c
--- /dev/null
+++ b/startop/apps/ColorChanging/gradle.properties
@@ -0,0 +1,20 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Automatically convert third-party libraries to use AndroidX
+android.enableJetifier=true
+
diff --git a/startop/apps/ColorChanging/gradle/wrapper/gradle-wrapper.jar b/startop/apps/ColorChanging/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000000..f6b961fd5a86
--- /dev/null
+++ b/startop/apps/ColorChanging/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/startop/apps/ColorChanging/gradle/wrapper/gradle-wrapper.properties b/startop/apps/ColorChanging/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000000..09f2718ae856
--- /dev/null
+++ b/startop/apps/ColorChanging/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Jun 17 13:40:58 PDT 2019
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
diff --git a/startop/apps/ColorChanging/gradlew b/startop/apps/ColorChanging/gradlew
new file mode 100755
index 000000000000..cccdd3d517fc
--- /dev/null
+++ b/startop/apps/ColorChanging/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/startop/apps/ColorChanging/gradlew.bat b/startop/apps/ColorChanging/gradlew.bat
new file mode 100644
index 000000000000..e95643d6a2ca
--- /dev/null
+++ b/startop/apps/ColorChanging/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/startop/apps/ColorChanging/settings.gradle b/startop/apps/ColorChanging/settings.gradle
new file mode 100644
index 000000000000..e7b4def49cb5
--- /dev/null
+++ b/startop/apps/ColorChanging/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/startop/iorap/DISABLED_TEST_MAPPING b/startop/iorap/TEST_MAPPING
index 8c9d4dfb0894..8c9d4dfb0894 100644
--- a/startop/iorap/DISABLED_TEST_MAPPING
+++ b/startop/iorap/TEST_MAPPING
diff --git a/startop/iorap/tests/AndroidTest.xml b/startop/iorap/tests/AndroidTest.xml
index bcd11033bed3..6102c44e61bf 100644
--- a/startop/iorap/tests/AndroidTest.xml
+++ b/startop/iorap/tests/AndroidTest.xml
@@ -33,18 +33,34 @@
<target_preparer class="com.android.tradefed.targetprep.DisableSELinuxTargetPreparer">
</target_preparer>
+ <!-- do not use DeviceSetup#set-property because it reboots the device b/136200738.
+ furthermore the changes in /data/local.prop don't actually seem to get picked up.
+ -->
<target_preparer
class="com.android.tradefed.targetprep.DeviceSetup">
+ <!-- we need this magic flag, otherwise it always reboots and breaks the selinux -->
+ <option name="force-skip-system-props" value="true" />
+
<!-- Crash instead of using Log.wtf within the system_server iorap code. -->
- <option name="set-property" key="iorapd.forwarding_service.wtf_crash" value="true" />
+ <option name="run-command" value="setprop iorapd.forwarding_service.wtf_crash true" />
<!-- IIorapd has fake behavior: it doesn't do anything but reply with 'DONE' status -->
- <option name="set-property" key="iorapd.binder.fake" value="true" />
- <option name="restore-properties" value="true" />
+ <option name="run-command" value="setprop iorapd.binder.fake true" />
+
+ <!-- iorapd does not pick up the above changes until we restart it -->
+ <option name="run-command" value="stop iorapd" />
+ <option name="run-command" value="start iorapd" />
+ <!-- give it some time to restart the service; otherwise the first unit test might fail -->
+ <option name="run-command" value="sleep 1" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.google.android.startop.iorap.tests" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
</test>
+
+ <!-- using DeviceSetup again does not work. we simply leave the device in a semi-bad
+ state. there is no way to clean this up as far as I know.
+ -->
+
</configuration>
diff --git a/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt b/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt
index 883d09490610..460add897f2f 100644
--- a/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt
+++ b/startop/iorap/tests/src/com/google/android/startop/iorap/IIorapIntegrationTest.kt
@@ -14,6 +14,7 @@
package com.google.android.startop.iorap
+import android.net.Uri
import android.os.ServiceManager
import androidx.test.filters.MediumTest
import org.junit.Test
@@ -85,6 +86,9 @@ class IIorapIntegrationTest {
@Test
fun testOnPackageEvent() {
+ // FIXME (b/137134253): implement PackageEvent parsing on the C++ side.
+ // This is currently (silently: b/137135024) failing because IIorap is 'oneway' and the
+ // C++ PackageEvent un-parceling fails since its not implemented fully.
/*
testAnyMethod { requestId : RequestId ->
iorapService.onPackageEvent(requestId,
@@ -92,7 +96,6 @@ class IIorapIntegrationTest {
Uri.parse("https://www.google.com"), "com.fake.package"))
}
*/
- // FIXME: Broken for some reason. C++ side never sees this call.
}
@Test
@@ -107,7 +110,7 @@ class IIorapIntegrationTest {
@Test
fun testOnAppLaunchEvent() {
testAnyMethod { requestId : RequestId ->
- // iorapService.onAppLaunchEvent(requestId, AppLaunchEvent.IntentStarted())
+ iorapService.onAppLaunchEvent(requestId, AppLaunchEvent.IntentFailed(/*sequenceId*/123))
}
}
diff --git a/startop/scripts/app_startup/lib/adb_utils.py b/startop/scripts/app_startup/lib/adb_utils.py
index 00e2e9995863..0e0065defd7f 100644
--- a/startop/scripts/app_startup/lib/adb_utils.py
+++ b/startop/scripts/app_startup/lib/adb_utils.py
@@ -16,12 +16,18 @@
"""Helper util libraries for calling adb command line."""
+import datetime
import os
+import re
import sys
+import time
+from typing import Optional
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(
os.path.abspath(__file__)))))
import lib.cmd_utils as cmd_utils
+import lib.logcat_utils as logcat_utils
+
def logcat_save_timestamp() -> str:
"""Gets the current logcat timestamp.
@@ -54,10 +60,48 @@ def disable_selinux():
cmd_utils.run_shell_command('adb wait-for-device')
def pkill(procname: str):
- """Kills a process in device by its package name."""
+ """Kills a process on device specified by the substring pattern in procname"""
_, pids = cmd_utils.run_shell_command('adb shell ps | grep "{}" | '
'awk \'{{print $2;}}\''.
format(procname))
for pid in pids.split('\n'):
- cmd_utils.run_adb_shell_command('kill {}'.format(pid))
+ pid = pid.strip()
+ if pid:
+ passed,_ = cmd_utils.run_adb_shell_command('kill {}'.format(pid))
+ time.sleep(1)
+
+def parse_time_to_milliseconds(time: str) -> int:
+ """Parses the time string to milliseconds."""
+ # Example: +1s56ms, +56ms
+ regex = r'\+((?P<second>\d+?)s)?(?P<millisecond>\d+?)ms'
+ result = re.search(regex, time)
+ second = 0
+ if result.group('second'):
+ second = int(result.group('second'))
+ ms = int(result.group('millisecond'))
+ return second * 1000 + ms
+
+def blocking_wait_for_logcat_displayed_time(timestamp: datetime.datetime,
+ package: str,
+ timeout: int) -> Optional[int]:
+ """Parses the displayed time in the logcat.
+
+ Returns:
+ the displayed time.
+ """
+ pattern = re.compile('.*ActivityTaskManager: Displayed {}.*'.format(package))
+ # 2019-07-02 22:28:34.469453349 -> 2019-07-02 22:28:34.469453
+ timestamp = datetime.datetime.strptime(timestamp[:-3],
+ '%Y-%m-%d %H:%M:%S.%f')
+ timeout_dt = timestamp + datetime.timedelta(0, timeout)
+ # 2019-07-01 14:54:21.946 27365 27392 I ActivityTaskManager:
+ # Displayed com.android.settings/.Settings: +927ms
+ result = logcat_utils.blocking_wait_for_logcat_pattern(timestamp,
+ pattern,
+ timeout_dt)
+ if not result or not '+' in result:
+ return None
+ displayed_time = result[result.rfind('+'):]
+
+ return parse_time_to_milliseconds(displayed_time) \ No newline at end of file
diff --git a/startop/scripts/app_startup/lib/adb_utils_test.py b/startop/scripts/app_startup/lib/adb_utils_test.py
new file mode 100644
index 000000000000..e590fed568e3
--- /dev/null
+++ b/startop/scripts/app_startup/lib/adb_utils_test.py
@@ -0,0 +1,16 @@
+import adb_utils
+
+# pip imports
+import pytest
+
+def test_parse_time_to_milliseconds():
+ # Act
+ result1 = adb_utils.parse_time_to_milliseconds('+1s7ms')
+ result2 = adb_utils.parse_time_to_milliseconds('+523ms')
+
+ # Assert
+ assert result1 == 1007
+ assert result2 == 523
+
+if __name__ == '__main__':
+ pytest.main()
diff --git a/startop/scripts/app_startup/run_app_with_prefetch.py b/startop/scripts/app_startup/run_app_with_prefetch.py
index c7970f5c4a67..052db9d6f5ea 100644
--- a/startop/scripts/app_startup/run_app_with_prefetch.py
+++ b/startop/scripts/app_startup/run_app_with_prefetch.py
@@ -30,8 +30,7 @@ import argparse
import os
import sys
import time
-from typing import List, Tuple
-from pathlib import Path
+from typing import List, Tuple, Optional
# local imports
import lib.adb_utils as adb_utils
@@ -40,6 +39,8 @@ import lib.adb_utils as adb_utils
DIR = os.path.abspath(os.path.dirname(__file__))
IORAP_COMMON_BASH_SCRIPT = os.path.realpath(os.path.join(DIR,
'../iorap/common'))
+APP_STARTUP_COMMON_BASH_SCRIPT = os.path.realpath(os.path.join(DIR,
+ 'lib/common'))
sys.path.append(os.path.dirname(DIR))
import lib.print_utils as print_utils
@@ -103,7 +104,20 @@ def validate_options(opts: argparse.Namespace) -> bool:
print_utils.error_print('--input not specified!')
return False
- # Install necessary trace file.
+ if opts.simulate:
+ opts.activity = 'act'
+
+ if not opts.activity:
+ _, opts.activity = cmd_utils.run_shell_func(IORAP_COMMON_BASH_SCRIPT,
+ 'get_activity_name',
+ [opts.package])
+
+ if not opts.activity:
+ print_utils.error_print('Activity name could not be found, '
+ 'invalid package name?!')
+ return False
+
+ # Install necessary trace file. This must be after the activity checking.
if needs_trace_file:
passed = iorapd_utils.iorapd_compiler_install_trace_file(
opts.package, opts.activity, opts.input)
@@ -113,18 +127,6 @@ def validate_options(opts: argparse.Namespace) -> bool:
format(opts.package, opts.activity))
return False
- if opts.activity is not None:
- return True
-
- _, opts.activity = cmd_utils.run_shell_func(IORAP_COMMON_BASH_SCRIPT,
- 'get_activity_name',
- [opts.package])
-
- if not opts.activity:
- print_utils.error_print('Activity name could not be found, '
- 'invalid package name?!')
- return False
-
return True
def set_up_adb_env():
@@ -184,9 +186,6 @@ def parse_metrics_output(input: str,
Returns:
A list of tuples that including metric name, metric value and rest info.
"""
- if simulate:
- return [('TotalTime', '123')]
-
all_metrics = []
for line in input.split('\n'):
if not line:
@@ -208,6 +207,33 @@ def parse_metrics_output(input: str,
all_metrics.append((metric_name, metric_value))
return all_metrics
+def _parse_total_time(am_start_output: str) -> Optional[str]:
+ """Parses the total time from 'adb shell am start pkg' output.
+
+ Returns:
+ the total time of app startup.
+ """
+ for line in am_start_output.split('\n'):
+ if 'TotalTime:' in line:
+ return line[len('TotalTime:'):].strip()
+ return None
+
+def blocking_parse_all_metrics(am_start_output: str, package: str,
+ pre_launch_timestamp: str,
+ timeout: int) -> str:
+ """Parses the metric after app startup by reading from logcat in a blocking
+ manner until all metrics have been found".
+
+ Returns:
+ the total time and displayed time of app startup.
+ For example: "TotalTime=123\nDisplayedTime=121
+ """
+ total_time = _parse_total_time(am_start_output)
+ displayed_time = adb_utils.blocking_wait_for_logcat_displayed_time(
+ pre_launch_timestamp, package, timeout)
+
+ return 'TotalTime={}\nDisplayedTime={}'.format(total_time, displayed_time)
+
def run(readahead: str,
package: str,
activity: str,
@@ -223,11 +249,17 @@ def run(readahead: str,
print_utils.debug_print('===== START =====')
print_utils.debug_print('==========================================')
+ # Kill any existing process of this app
+ adb_utils.pkill(package)
+
if readahead != 'warm':
print_utils.debug_print('Drop caches for non-warm start.')
# Drop all caches to get cold starts.
adb_utils.vm_drop_cache()
+ if readahead != 'warm' and readahead != 'cold':
+ iorapd_utils.enable_iorapd_readahead()
+
print_utils.debug_print('Running with timeout {}'.format(timeout))
pre_launch_timestamp = adb_utils.logcat_save_timestamp()
@@ -235,21 +267,22 @@ def run(readahead: str,
passed, output = cmd_utils.run_shell_command('timeout {timeout} '
'"{DIR}/launch_application" '
'"{package}" '
- '"{activity}" | '
- '"{DIR}/parse_metrics" '
- '--package {package} '
- '--activity {activity} '
- '--timestamp "{timestamp}"'
- .format(timeout=timeout,
- DIR=DIR,
- package=package,
- activity=activity,
- timestamp=pre_launch_timestamp))
-
- if not output and not simulate:
+ '"{activity}"'
+ .format(timeout=timeout,
+ DIR=DIR,
+ package=package,
+ activity=activity))
+ if not passed and not simulate:
return None
- results = parse_metrics_output(output, simulate)
+ if simulate:
+ results = [('TotalTime', '123')]
+ else:
+ output = blocking_parse_all_metrics(output,
+ package,
+ pre_launch_timestamp,
+ timeout)
+ results = parse_metrics_output(output, simulate)
passed = perform_post_launch_cleanup(
readahead, package, activity, timeout, debug, pre_launch_timestamp)
@@ -272,12 +305,17 @@ def perform_post_launch_cleanup(readahead: str,
A bool indicates whether the cleanup succeeds or not.
"""
if readahead != 'warm' and readahead != 'cold':
- return iorapd_utils.wait_for_iorapd_finish(package,
+ passed = iorapd_utils.wait_for_iorapd_finish(package,
activity,
timeout,
debug,
logcat_timestamp)
- return passed
+
+ if not passed:
+ return passed
+
+ return iorapd_utils.disable_iorapd_readahead()
+
# Don't need to do anything for warm or cold.
return True
diff --git a/startop/scripts/app_startup/run_app_with_prefetch_test.py b/startop/scripts/app_startup/run_app_with_prefetch_test.py
index 241aea4943ef..a642385b37d7 100644
--- a/startop/scripts/app_startup/run_app_with_prefetch_test.py
+++ b/startop/scripts/app_startup/run_app_with_prefetch_test.py
@@ -200,70 +200,82 @@ def test_parse_metrics_output():
def _mocked_run_shell_command(*args, **kwargs):
if args[0] == 'adb shell "date -u +\'%Y-%m-%d %H:%M:%S.%N\'"':
- return (True, "123:123")
+ return (True, "2019-07-02 23:20:06.972674825")
elif args[0] == 'adb shell ps | grep "music" | awk \'{print $2;}\'':
return (True, '9999')
else:
return (True, 'a1=b1\nc1=d1=d2\ne1=f1')
-def test_run_no_vm_cache_drop():
- with patch('lib.cmd_utils.run_shell_command',
- new_callable=Mock) as mock_run_shell_command:
- mock_run_shell_command.side_effect = _mocked_run_shell_command
- run.run('warm',
- 'music',
- 'MainActivity',
- timeout=10,
- simulate=False,
- debug=False)
-
- calls = [call('adb shell "date -u +\'%Y-%m-%d %H:%M:%S.%N\'"'),
- call(
- 'timeout {timeout} "{DIR}/launch_application" "{package}" "{activity}" | '
- '"{DIR}/parse_metrics" --package {package} --activity {activity} '
- '--timestamp "{timestamp}"'
- .format(timeout=10,
- DIR=run.DIR,
- package='music',
- activity='MainActivity',
- timestamp='123:123')),
- call('adb shell ps | grep "music" | awk \'{print $2;}\''),
- call('adb shell "kill 9999"')]
- mock_run_shell_command.assert_has_calls(calls)
+@patch('lib.adb_utils.blocking_wait_for_logcat_displayed_time')
+@patch('lib.cmd_utils.run_shell_command')
+def test_run_no_vm_cache_drop(mock_run_shell_command,
+ mock_blocking_wait_for_logcat_displayed_time):
+ mock_run_shell_command.side_effect = _mocked_run_shell_command
+ mock_blocking_wait_for_logcat_displayed_time.return_value = 123
+
+ run.run('warm',
+ 'music',
+ 'MainActivity',
+ timeout=10,
+ simulate=False,
+ debug=False)
+
+ calls = [call('adb shell ps | grep "music" | awk \'{print $2;}\''),
+ call('adb shell "kill 9999"'),
+ call('adb shell "date -u +\'%Y-%m-%d %H:%M:%S.%N\'"'),
+ call(
+ 'timeout {timeout} "{DIR}/launch_application" "{package}" "{activity}"'
+ .format(timeout=10,
+ DIR=run.DIR,
+ package='music',
+ activity='MainActivity',
+ timestamp='2019-07-02 23:20:06.972674825')),
+ call('adb shell ps | grep "music" | awk \'{print $2;}\''),
+ call('adb shell "kill 9999"')]
+ mock_run_shell_command.assert_has_calls(calls)
-def test_run_with_vm_cache_drop_and_post_launch_cleanup():
- with patch('lib.cmd_utils.run_shell_command',
- new_callable=Mock) as mock_run_shell_command:
- mock_run_shell_command.side_effect = _mocked_run_shell_command
- run.run('fadvise',
- 'music',
- 'MainActivity',
- timeout=10,
- simulate=False,
- debug=False)
-
- calls = [call('adb shell "echo 3 > /proc/sys/vm/drop_caches"'),
- call('adb shell "date -u +\'%Y-%m-%d %H:%M:%S.%N\'"'),
- call(
- 'timeout {timeout} "{DIR}/launch_application" "{package}" "{activity}" | '
- '"{DIR}/parse_metrics" --package {package} --activity {activity} '
- '--timestamp "{timestamp}"'
- .format(timeout=10,
- DIR=run.DIR,
- package='music',
- activity='MainActivity',
- timestamp='123:123')),
- call(
- 'bash -c "source {script_path}; '
- 'iorapd_readahead_wait_until_finished '
- '\'{package}\' \'{activity}\' \'{timestamp}\' \'{timeout}\'"'.
- format(timeout=10,
- package='music',
- activity='MainActivity',
- timestamp='123:123',
- script_path=run.IORAP_COMMON_BASH_SCRIPT)),
- call('adb shell ps | grep "music" | awk \'{print $2;}\''),
- call('adb shell "kill 9999"')]
+@patch('lib.adb_utils.blocking_wait_for_logcat_displayed_time')
+@patch('lib.cmd_utils.run_shell_command')
+def test_run_with_vm_cache_drop_and_post_launch_cleanup(
+ mock_run_shell_command,
+ mock_blocking_wait_for_logcat_displayed_time):
+ mock_run_shell_command.side_effect = _mocked_run_shell_command
+ mock_blocking_wait_for_logcat_displayed_time.return_value = 123
+
+ run.run('fadvise',
+ 'music',
+ 'MainActivity',
+ timeout=10,
+ simulate=False,
+ debug=False)
+
+ calls = [call('adb shell ps | grep "music" | awk \'{print $2;}\''),
+ call('adb shell "kill 9999"'),
+ call('adb shell "echo 3 > /proc/sys/vm/drop_caches"'),
+ call('bash -c "source {}; iorapd_readahead_enable"'.
+ format(run.IORAP_COMMON_BASH_SCRIPT)),
+ call('adb shell "date -u +\'%Y-%m-%d %H:%M:%S.%N\'"'),
+ call(
+ 'timeout {timeout} "{DIR}/launch_application" '
+ '"{package}" "{activity}"'
+ .format(timeout=10,
+ DIR=run.DIR,
+ package='music',
+ activity='MainActivity',
+ timestamp='2019-07-02 23:20:06.972674825')),
+ call(
+ 'bash -c "source {script_path}; '
+ 'iorapd_readahead_wait_until_finished '
+ '\'{package}\' \'{activity}\' \'{timestamp}\' \'{timeout}\'"'.
+ format(timeout=10,
+ package='music',
+ activity='MainActivity',
+ timestamp='2019-07-02 23:20:06.972674825',
+ script_path=run.IORAP_COMMON_BASH_SCRIPT)),
+ call('bash -c "source {}; iorapd_readahead_disable"'.
+ format(run.IORAP_COMMON_BASH_SCRIPT)),
+ call('adb shell ps | grep "music" | awk \'{print $2;}\''),
+ call('adb shell "kill 9999"')]
mock_run_shell_command.assert_has_calls(calls)
if __name__ == '__main__':
diff --git a/startop/scripts/iorap/lib/iorapd_utils.py b/startop/scripts/iorap/lib/iorapd_utils.py
index f907305f5c61..c03e9b0ae04d 100644
--- a/startop/scripts/iorap/lib/iorapd_utils.py
+++ b/startop/scripts/iorap/lib/iorapd_utils.py
@@ -86,3 +86,28 @@ def wait_for_iorapd_finish(package: str,
[package, activity, logcat_timestamp,
str(timeout)])
return passed
+
+
+def enable_iorapd_readahead() -> bool:
+ """
+ Disable readahead. Subsequent launches of an application will be sped up
+ by iorapd readahead prefetching.
+
+ Returns:
+ A bool indicates whether the enabling is done successfully or not.
+ """
+ passed, _ = cmd_utils.run_shell_func(IORAP_COMMON_BASH_SCRIPT,
+ 'iorapd_readahead_enable', [])
+ return passed
+
+def disable_iorapd_readahead() -> bool:
+ """
+ Disable readahead. Subsequent launches of an application will be not be sped
+ up by iorapd readahead prefetching.
+
+ Returns:
+ A bool indicates whether the disabling is done successfully or not.
+ """
+ passed, _ = cmd_utils.run_shell_func(IORAP_COMMON_BASH_SCRIPT,
+ 'iorapd_readahead_disable', [])
+ return passed
diff --git a/startop/scripts/lib/cmd_utils.py b/startop/scripts/lib/cmd_utils.py
index c3d96059c91c..bc5ca3140d3d 100644
--- a/startop/scripts/lib/cmd_utils.py
+++ b/startop/scripts/lib/cmd_utils.py
@@ -44,10 +44,16 @@ def run_shell_func(script_path: str,
A tuple of running status (True=succeeded, False=failed or timed out) and
std output (string contents of stdout with trailing whitespace removed) .
"""
- cmd = 'bash -c "source {script_path}; {func} {args}"'.format(
- script_path=script_path,
- func=func,
- args=' '.join("'{}'".format(arg) for arg in args))
+ if args:
+ cmd = 'bash -c "source {script_path}; {func} {args}"'.format(
+ script_path=script_path,
+ func=func,
+ args=' '.join("'{}'".format(arg) for arg in args))
+ else:
+ cmd = 'bash -c "source {script_path}; {func}"'.format(
+ script_path=script_path,
+ func=func)
+
print_utils.debug_print(cmd)
return run_shell_command(cmd)
diff --git a/startop/scripts/lib/logcat_utils.py b/startop/scripts/lib/logcat_utils.py
new file mode 100644
index 000000000000..13b1c3a5cff7
--- /dev/null
+++ b/startop/scripts/lib/logcat_utils.py
@@ -0,0 +1,104 @@
+#!/usr/bin/env python3
+#
+# Copyright 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.
+
+"""Helper util libraries for parsing logcat logs."""
+
+import asyncio
+import re
+from datetime import datetime
+from typing import Optional, Pattern
+
+# local import
+import print_utils
+
+def parse_logcat_datetime(timestamp: str) -> Optional[datetime]:
+ """Parses the timestamp of logcat.
+
+ Params:
+ timestamp: for example "2019-07-01 16:13:55.221".
+
+ Returns:
+ a datetime of timestamp with the year now.
+ """
+ try:
+ # Match the format of logcat. For example: "2019-07-01 16:13:55.221",
+ # because it doesn't have year, set current year to it.
+ timestamp = datetime.strptime(timestamp,
+ '%Y-%m-%d %H:%M:%S.%f')
+ return timestamp
+ except ValueError as ve:
+ print_utils.debug_print('Invalid line: ' + timestamp)
+ return None
+
+def _is_time_out(timeout: datetime, line: str) -> bool:
+ """Checks if the timestamp of this line exceeds the timeout.
+
+ Returns:
+ true if the timestamp exceeds the timeout.
+ """
+ # Get the timestampe string.
+ cur_timestamp_str = ' '.join(re.split(r'\s+', line)[0:2])
+ timestamp = parse_logcat_datetime(cur_timestamp_str)
+ if not timestamp:
+ return False
+
+ return timestamp > timeout
+
+async def _blocking_wait_for_logcat_pattern(timestamp: datetime,
+ pattern: Pattern,
+ timeout: datetime) -> Optional[str]:
+ # Show the year in the timestampe.
+ logcat_cmd = 'adb logcat -v year -v threadtime -T'.split()
+ logcat_cmd.append(str(timestamp))
+ print_utils.debug_print('[LOGCAT]:' + ' '.join(logcat_cmd))
+
+ # Create subprocess
+ process = await asyncio.create_subprocess_exec(
+ *logcat_cmd,
+ # stdout must a pipe to be accessible as process.stdout
+ stdout=asyncio.subprocess.PIPE)
+
+ while (True):
+ # Read one line of output.
+ data = await process.stdout.readline()
+ line = data.decode('utf-8').rstrip()
+
+ # 2019-07-01 14:54:21.946 27365 27392 I ActivityTaskManager: Displayed
+ # com.android.settings/.Settings: +927ms
+ # TODO: Detect timeouts even when there is no logcat output.
+ if _is_time_out(timeout, line):
+ print_utils.debug_print('DID TIMEOUT BEFORE SEEING ANYTHING ('
+ 'timeout={timeout} seconds << {pattern} '
+ '>>'.format(timeout=timeout, pattern=pattern))
+ return None
+
+ if pattern.match(line):
+ print_utils.debug_print(
+ 'WE DID SEE PATTERN << "{}" >>.'.format(pattern))
+ return line
+
+def blocking_wait_for_logcat_pattern(timestamp: datetime,
+ pattern: Pattern,
+ timeout: datetime) -> Optional[str]:
+ """Selects the line that matches the pattern and within the timeout.
+
+ Returns:
+ the line that matches the pattern and within the timeout.
+ """
+ loop = asyncio.get_event_loop()
+ result = loop.run_until_complete(
+ _blocking_wait_for_logcat_pattern(timestamp, pattern, timeout))
+ return result
diff --git a/startop/scripts/lib/logcat_utils_test.py b/startop/scripts/lib/logcat_utils_test.py
new file mode 100644
index 000000000000..ab82515bc4fa
--- /dev/null
+++ b/startop/scripts/lib/logcat_utils_test.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python3
+#
+# Copyright 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.
+#
+"""Unit tests for the logcat_utils.py script."""
+
+import asyncio
+import datetime
+import re
+
+import logcat_utils
+from mock import MagicMock, patch
+
+def test_parse_logcat_datatime():
+ # Act
+ result = logcat_utils.parse_logcat_datetime('2019-07-01 16:13:55.221')
+
+ # Assert
+ assert result == datetime.datetime(2019, 7, 1, 16, 13, 55, 221000)
+
+class AsyncMock(MagicMock):
+ async def __call__(self, *args, **kwargs):
+ return super(AsyncMock, self).__call__(*args, **kwargs)
+
+def _async_return():
+ f = asyncio.Future()
+ f.set_result(
+ b'2019-07-01 15:51:53.290 27365 27392 I ActivityTaskManager: '
+ b'Displayed com.google.android.music/com.android.music.activitymanagement.'
+ b'TopLevelActivity: +1s7ms')
+ return f
+
+def test_parse_displayed_time_succeed():
+ # Act
+ with patch('asyncio.create_subprocess_exec',
+ new_callable=AsyncMock) as asyncio_mock:
+ asyncio_mock.return_value.stdout.readline = _async_return
+ timestamp = datetime.datetime(datetime.datetime.now().year, 7, 1, 16, 13,
+ 55, 221000)
+ timeout_dt = timestamp + datetime.timedelta(0, 10)
+ pattern = re.compile('.*ActivityTaskManager: Displayed '
+ 'com.google.android.music/com.android.music.*')
+ result = logcat_utils.blocking_wait_for_logcat_pattern(timestamp,
+ pattern,
+ timeout_dt)
+
+ # Assert
+ assert result == '2019-07-01 15:51:53.290 27365 27392 I ' \
+ 'ActivityTaskManager: ' \
+ 'Displayed com.google.android.music/com.android.music.' \
+ 'activitymanagement.TopLevelActivity: +1s7ms'
+
+def _async_timeout_return():
+ f = asyncio.Future()
+ f.set_result(
+ b'2019-07-01 17:51:53.290 27365 27392 I ActivityTaskManager: '
+ b'Displayed com.google.android.music/com.android.music.activitymanagement.'
+ b'TopLevelActivity: +1s7ms')
+ return f
+
+def test_parse_displayed_time_timeout():
+ # Act
+ with patch('asyncio.create_subprocess_exec',
+ new_callable=AsyncMock) as asyncio_mock:
+ asyncio_mock.return_value.stdout.readline = _async_timeout_return
+ timestamp = datetime.datetime(datetime.datetime.now().year,
+ 7, 1, 16, 13, 55, 221000)
+ timeout_dt = timestamp + datetime.timedelta(0, 10)
+ pattern = re.compile('.*ActivityTaskManager: Displayed '
+ 'com.google.android.music/com.android.music.*')
+ result = logcat_utils.blocking_wait_for_logcat_pattern(timestamp,
+ pattern,
+ timeout_dt)
+
+ # Assert
+ assert result == None
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 22a8232d1a0b..ed70a81e01d6 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -10834,7 +10834,6 @@ public class TelephonyManager {
* @param callback Callback will be triggered once it succeeds or failed.
* See {@link TelephonyManager.SetOpportunisticSubscriptionResult}
* for more details. Pass null if don't care about the result.
- *
*/
public void setPreferredOpportunisticDataSubscription(int subId, boolean needValidation,
@Nullable @CallbackExecutor Executor executor, @Nullable Consumer<Integer> callback) {
@@ -10842,6 +10841,12 @@ public class TelephonyManager {
try {
IOns iOpportunisticNetworkService = getIOns();
if (iOpportunisticNetworkService == null) {
+ if (executor == null || callback == null) {
+ return;
+ }
+ Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
+ callback.accept(SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION);
+ }));
return;
}
ISetOpportunisticDataCallback callbackStub = new ISetOpportunisticDataCallback.Stub() {
@@ -10923,9 +10928,16 @@ public class TelephonyManager {
if (executor == null || callback == null) {
return;
}
- Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
- callback.accept(UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS);
- }));
+ if (iOpportunisticNetworkService == null) {
+ /* Todo<b/130595455> passing unknown due to lack of good error codes */
+ Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
+ callback.accept(UPDATE_AVAILABLE_NETWORKS_UNKNOWN_FAILURE);
+ }));
+ } else {
+ Binder.withCleanCallingIdentity(() -> executor.execute(() -> {
+ callback.accept(UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS);
+ }));
+ }
return;
}
IUpdateAvailableNetworksCallback callbackStub =
diff --git a/telephony/java/com/android/internal/telephony/SmsApplication.java b/telephony/java/com/android/internal/telephony/SmsApplication.java
index 44dc24bf716e..98f52cbf93da 100644
--- a/telephony/java/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/java/com/android/internal/telephony/SmsApplication.java
@@ -17,6 +17,7 @@
package com.android.internal.telephony;
import android.Manifest.permission;
+import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.app.role.RoleManager;
import android.content.ComponentName;
@@ -662,49 +663,69 @@ public final class SmsApplication {
}
defaultSmsAppChanged(context);
+ }
+ }
+
+ /**
+ * Sends broadcasts on sms app change:
+ * {@link Intent#ACTION_DEFAULT_SMS_PACKAGE_CHANGED}
+ * {@link Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL}
+ */
+ public static void broadcastSmsAppChange(Context context,
+ UserHandle userHandle, @Nullable String oldPackage, @Nullable String newPackage) {
+ Collection<SmsApplicationData> apps = getApplicationCollection(context);
+ broadcastSmsAppChange(context, userHandle,
+ getApplicationForPackage(apps, oldPackage),
+ getApplicationForPackage(apps, newPackage));
+ }
+
+ private static void broadcastSmsAppChange(Context context, UserHandle userHandle,
+ @Nullable SmsApplicationData oldAppData,
+ @Nullable SmsApplicationData applicationData) {
+ if (DEBUG_MULTIUSER) {
+ Log.i(LOG_TAG, "setDefaultApplicationInternal oldAppData=" + oldAppData);
+ }
+ if (oldAppData != null && oldAppData.mSmsAppChangedReceiverClass != null) {
+ // Notify the old sms app that it's no longer the default
+ final Intent oldAppIntent =
+ new Intent(Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED);
+ final ComponentName component = new ComponentName(oldAppData.mPackageName,
+ oldAppData.mSmsAppChangedReceiverClass);
+ oldAppIntent.setComponent(component);
+ oldAppIntent.putExtra(Intents.EXTRA_IS_DEFAULT_SMS_APP, false);
if (DEBUG_MULTIUSER) {
- Log.i(LOG_TAG, "setDefaultApplicationInternal oldAppData=" + oldAppData);
- }
- if (oldAppData != null && oldAppData.mSmsAppChangedReceiverClass != null) {
- // Notify the old sms app that it's no longer the default
- final Intent oldAppIntent =
- new Intent(Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED);
- final ComponentName component = new ComponentName(oldAppData.mPackageName,
- oldAppData.mSmsAppChangedReceiverClass);
- oldAppIntent.setComponent(component);
- oldAppIntent.putExtra(Telephony.Sms.Intents.EXTRA_IS_DEFAULT_SMS_APP, false);
- if (DEBUG_MULTIUSER) {
- Log.i(LOG_TAG, "setDefaultApplicationInternal old=" + oldAppData.mPackageName);
- }
- context.sendBroadcastAsUser(oldAppIntent, userHandle);
+ Log.i(LOG_TAG, "setDefaultApplicationInternal old=" + oldAppData.mPackageName);
}
- // Notify the new sms app that it's now the default (if the new sms app has a receiver
- // to handle the changed default sms intent).
+ context.sendBroadcastAsUser(oldAppIntent, userHandle);
+ }
+ // Notify the new sms app that it's now the default (if the new sms app has a receiver
+ // to handle the changed default sms intent).
+ if (DEBUG_MULTIUSER) {
+ Log.i(LOG_TAG, "setDefaultApplicationInternal new applicationData=" +
+ applicationData);
+ }
+ if (applicationData != null && applicationData.mSmsAppChangedReceiverClass != null) {
+ final Intent intent =
+ new Intent(Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED);
+ final ComponentName component = new ComponentName(applicationData.mPackageName,
+ applicationData.mSmsAppChangedReceiverClass);
+ intent.setComponent(component);
+ intent.putExtra(Intents.EXTRA_IS_DEFAULT_SMS_APP, true);
if (DEBUG_MULTIUSER) {
- Log.i(LOG_TAG, "setDefaultApplicationInternal new applicationData=" +
- applicationData);
- }
- if (applicationData.mSmsAppChangedReceiverClass != null) {
- final Intent intent =
- new Intent(Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED);
- final ComponentName component = new ComponentName(applicationData.mPackageName,
- applicationData.mSmsAppChangedReceiverClass);
- intent.setComponent(component);
- intent.putExtra(Telephony.Sms.Intents.EXTRA_IS_DEFAULT_SMS_APP, true);
- if (DEBUG_MULTIUSER) {
- Log.i(LOG_TAG, "setDefaultApplicationInternal new=" + packageName);
- }
- context.sendBroadcastAsUser(intent, userHandle);
+ Log.i(LOG_TAG, "setDefaultApplicationInternal new=" + applicationData.mPackageName);
}
+ context.sendBroadcastAsUser(intent, userHandle);
+ }
- // Send an implicit broadcast for the system server.
- // (or anyone with MONITOR_DEFAULT_SMS_PACKAGE, really.)
- final Intent intent =
- new Intent(Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL);
- context.sendBroadcastAsUser(intent, userHandle,
- permission.MONITOR_DEFAULT_SMS_PACKAGE);
+ // Send an implicit broadcast for the system server.
+ // (or anyone with MONITOR_DEFAULT_SMS_PACKAGE, really.)
+ final Intent intent =
+ new Intent(Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL);
+ context.sendBroadcastAsUser(intent, userHandle,
+ permission.MONITOR_DEFAULT_SMS_PACKAGE);
+ if (applicationData != null) {
MetricsLogger.action(context, MetricsEvent.ACTION_DEFAULT_SMS_APP_CHANGED,
applicationData.mPackageName);
}
diff --git a/test-mock/api/test-current.txt b/test-mock/api/test-current.txt
index a87e2f57bb5f..cc260ac14147 100644
--- a/test-mock/api/test-current.txt
+++ b/test-mock/api/test-current.txt
@@ -7,6 +7,7 @@ package android.test.mock {
}
@Deprecated public class MockPackageManager extends android.content.pm.PackageManager {
+ method public void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
method public boolean arePermissionsIndividuallyControlled();
method public String getDefaultBrowserPackageNameAsUser(int);
method public int getInstallReason(String, android.os.UserHandle);
@@ -18,6 +19,7 @@ package android.test.mock {
method @NonNull public String getServicesSystemSharedLibraryPackageName();
method @NonNull public String getSharedSystemSharedLibraryPackageName();
method public void grantRuntimePermission(String, String, android.os.UserHandle);
+ method public void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
method public void revokeRuntimePermission(String, String, android.os.UserHandle);
method public void updatePermissionFlags(String, String, int, int, android.os.UserHandle);
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 1b2a12887aa5..5cc95d9f2bc3 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -208,6 +208,8 @@ import com.android.server.net.NetworkPinner;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.testutils.ExceptionUtils;
import com.android.testutils.HandlerUtilsKt;
+import com.android.testutils.RecorderCallback.CallbackRecord;
+import com.android.testutils.TestableNetworkCallback;
import org.junit.After;
import org.junit.Before;
@@ -234,7 +236,6 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
-import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
@@ -243,7 +244,8 @@ import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Predicate;
+
+import kotlin.reflect.KClass;
/**
* Tests for {@link ConnectivityService}.
@@ -467,7 +469,7 @@ public class ConnectivityServiceTest {
fail("expected race condition at least once in " + attempts + " attempts");
}
- private class MockNetworkAgent {
+ private class MockNetworkAgent implements TestableNetworkCallback.HasNetwork {
private static final int VALIDATION_RESULT_BASE = NETWORK_VALIDATION_PROBE_DNS
| NETWORK_VALIDATION_PROBE_HTTP
| NETWORK_VALIDATION_PROBE_HTTPS;
@@ -1703,281 +1705,33 @@ public class ConnectivityServiceTest {
mCm.getDefaultRequest().networkCapabilities));
}
- enum CallbackState {
- NONE,
- AVAILABLE,
- NETWORK_CAPABILITIES,
- LINK_PROPERTIES,
- SUSPENDED,
- RESUMED,
- LOSING,
- LOST,
- UNAVAILABLE,
- BLOCKED_STATUS
- }
-
- private static class CallbackInfo {
- public final CallbackState state;
- public final Network network;
- public final Object arg;
- public CallbackInfo(CallbackState s, Network n, Object o) {
- state = s; network = n; arg = o;
- }
- public String toString() {
- return String.format("%s (%s) (%s)", state, network, arg);
- }
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof CallbackInfo)) return false;
- // Ignore timeMs, since it's unpredictable.
- CallbackInfo other = (CallbackInfo) o;
- return (state == other.state) && Objects.equals(network, other.network);
- }
- @Override
- public int hashCode() {
- return Objects.hash(state, network);
- }
- }
-
/**
* Utility NetworkCallback for testing. The caller must explicitly test for all the callbacks
* this class receives, by calling expectCallback() exactly once each time a callback is
* received. assertNoCallback may be called at any time.
*/
- private class TestNetworkCallback extends NetworkCallback {
- private final LinkedBlockingQueue<CallbackInfo> mCallbacks = new LinkedBlockingQueue<>();
- private Network mLastAvailableNetwork;
-
- protected void setLastCallback(CallbackState state, Network network, Object o) {
- mCallbacks.offer(new CallbackInfo(state, network, o));
- }
-
- @Override
- public void onAvailable(Network network) {
- mLastAvailableNetwork = network;
- setLastCallback(CallbackState.AVAILABLE, network, null);
- }
-
- @Override
- public void onCapabilitiesChanged(Network network, NetworkCapabilities netCap) {
- setLastCallback(CallbackState.NETWORK_CAPABILITIES, network, netCap);
- }
-
- @Override
- public void onLinkPropertiesChanged(Network network, LinkProperties linkProp) {
- setLastCallback(CallbackState.LINK_PROPERTIES, network, linkProp);
- }
-
+ private class TestNetworkCallback extends TestableNetworkCallback {
@Override
- public void onUnavailable() {
- setLastCallback(CallbackState.UNAVAILABLE, null, null);
- }
-
- @Override
- public void onNetworkSuspended(Network network) {
- setLastCallback(CallbackState.SUSPENDED, network, null);
- }
-
- @Override
- public void onNetworkResumed(Network network) {
- setLastCallback(CallbackState.RESUMED, network, null);
- }
-
- @Override
- public void onLosing(Network network, int maxMsToLive) {
- setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */);
- }
-
- @Override
- public void onLost(Network network) {
- mLastAvailableNetwork = null;
- setLastCallback(CallbackState.LOST, network, null);
+ public void assertNoCallback() {
+ // TODO: better support this use case in TestableNetworkCallback
+ waitForIdle();
+ assertNoCallback(0 /* timeout */);
}
@Override
- public void onBlockedStatusChanged(Network network, boolean blocked) {
- setLastCallback(CallbackState.BLOCKED_STATUS, network, blocked);
- }
-
- public Network getLastAvailableNetwork() {
- return mLastAvailableNetwork;
- }
-
- CallbackInfo nextCallback(int timeoutMs) throws InterruptedException {
- CallbackInfo cb = null;
- cb = mCallbacks.poll(timeoutMs, TimeUnit.MILLISECONDS);
- if (cb == null) {
- // LinkedBlockingQueue.poll() returns null if it timeouts.
- fail("Did not receive callback after " + timeoutMs + "ms");
- }
- return cb;
- }
-
- CallbackInfo expectCallback(CallbackState state, MockNetworkAgent agent, int timeoutMs)
- throws Exception {
- final Network expectedNetwork = (agent != null) ? agent.getNetwork() : null;
- CallbackInfo expected = new CallbackInfo(state, expectedNetwork, 0);
- CallbackInfo actual = nextCallback(timeoutMs);
- assertEquals("Unexpected callback:", expected, actual);
-
- if (state == CallbackState.LOSING) {
+ public <T extends CallbackRecord> T expectCallback(final KClass<T> type, final HasNetwork n,
+ final long timeoutMs) {
+ final T callback = super.expectCallback(type, n, timeoutMs);
+ if (callback instanceof CallbackRecord.Losing) {
+ // TODO : move this to the specific test(s) needing this rather than here.
+ final CallbackRecord.Losing losing = (CallbackRecord.Losing) callback;
+ final int maxMsToLive = losing.getMaxMsToLive();
String msg = String.format(
"Invalid linger time value %d, must be between %d and %d",
- actual.arg, 0, mService.mLingerDelayMs);
- int maxMsToLive = (Integer) actual.arg;
+ maxMsToLive, 0, mService.mLingerDelayMs);
assertTrue(msg, 0 <= maxMsToLive && maxMsToLive <= mService.mLingerDelayMs);
}
-
- return actual;
- }
-
- CallbackInfo expectCallback(CallbackState state, MockNetworkAgent agent) throws Exception {
- return expectCallback(state, agent, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- CallbackInfo expectCallbackLike(Predicate<CallbackInfo> fn) throws Exception {
- return expectCallbackLike(fn, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- CallbackInfo expectCallbackLike(Predicate<CallbackInfo> fn, int timeoutMs)
- throws Exception {
- int timeLeft = timeoutMs;
- while (timeLeft > 0) {
- long start = SystemClock.elapsedRealtime();
- CallbackInfo info = nextCallback(timeLeft);
- if (fn.test(info)) {
- return info;
- }
- timeLeft -= (SystemClock.elapsedRealtime() - start);
- }
- fail("Did not receive expected callback after " + timeoutMs + "ms");
- return null;
- }
-
- // Expects onAvailable and the callbacks that follow it. These are:
- // - onSuspended, iff the network was suspended when the callbacks fire.
- // - onCapabilitiesChanged.
- // - onLinkPropertiesChanged.
- // - onBlockedStatusChanged.
- //
- // @param agent the network to expect the callbacks on.
- // @param expectSuspended whether to expect a SUSPENDED callback.
- // @param expectValidated the expected value of the VALIDATED capability in the
- // onCapabilitiesChanged callback.
- // @param timeoutMs how long to wait for the callbacks.
- void expectAvailableCallbacks(MockNetworkAgent agent, boolean expectSuspended,
- boolean expectValidated, boolean expectBlocked, int timeoutMs) throws Exception {
- expectCallback(CallbackState.AVAILABLE, agent, timeoutMs);
- if (expectSuspended) {
- expectCallback(CallbackState.SUSPENDED, agent, timeoutMs);
- }
- if (expectValidated) {
- expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent, timeoutMs);
- } else {
- expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, agent, timeoutMs);
- }
- expectCallback(CallbackState.LINK_PROPERTIES, agent, timeoutMs);
- expectBlockedStatusCallback(expectBlocked, agent);
- }
-
- // Expects the available callbacks (validated), plus onSuspended.
- void expectAvailableAndSuspendedCallbacks(MockNetworkAgent agent, boolean expectValidated)
- throws Exception {
- expectAvailableCallbacks(agent, true, expectValidated, false, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- void expectAvailableCallbacksValidated(MockNetworkAgent agent)
- throws Exception {
- expectAvailableCallbacks(agent, false, true, false, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- void expectAvailableCallbacksValidatedAndBlocked(MockNetworkAgent agent) throws Exception {
- expectAvailableCallbacks(agent, false, true, true, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- void expectAvailableCallbacksUnvalidated(MockNetworkAgent agent) throws Exception {
- expectAvailableCallbacks(agent, false, false, false, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- void expectAvailableCallbacksUnvalidatedAndBlocked(MockNetworkAgent agent)
- throws Exception {
- expectAvailableCallbacks(agent, false, false, true, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- // Expects the available callbacks (where the onCapabilitiesChanged must contain the
- // VALIDATED capability), plus another onCapabilitiesChanged which is identical to the
- // one we just sent.
- // TODO: this is likely a bug. Fix it and remove this method.
- void expectAvailableDoubleValidatedCallbacks(MockNetworkAgent agent) throws Exception {
- expectCallback(CallbackState.AVAILABLE, agent, TEST_CALLBACK_TIMEOUT_MS);
- NetworkCapabilities nc1 = expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
- expectCallback(CallbackState.LINK_PROPERTIES, agent, TEST_CALLBACK_TIMEOUT_MS);
- // Implicitly check the network is allowed to use.
- // TODO: should we need to consider if network is in blocked status in this case?
- expectBlockedStatusCallback(false, agent);
- NetworkCapabilities nc2 = expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
- assertEquals(nc1, nc2);
- }
-
- // Expects the available callbacks where the onCapabilitiesChanged must not have validated,
- // then expects another onCapabilitiesChanged that has the validated bit set. This is used
- // when a network connects and satisfies a callback, and then immediately validates.
- void expectAvailableThenValidatedCallbacks(MockNetworkAgent agent) throws Exception {
- expectAvailableCallbacksUnvalidated(agent);
- expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
- }
-
- NetworkCapabilities expectCapabilitiesWith(int capability, MockNetworkAgent agent)
- throws Exception {
- return expectCapabilitiesWith(capability, agent, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- NetworkCapabilities expectCapabilitiesWith(int capability, MockNetworkAgent agent,
- int timeoutMs) throws Exception {
- CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent, timeoutMs);
- NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
- assertTrue(nc.hasCapability(capability));
- return nc;
- }
-
- NetworkCapabilities expectCapabilitiesWithout(int capability, MockNetworkAgent agent)
- throws Exception {
- return expectCapabilitiesWithout(capability, agent, TEST_CALLBACK_TIMEOUT_MS);
- }
-
- NetworkCapabilities expectCapabilitiesWithout(int capability, MockNetworkAgent agent,
- int timeoutMs) throws Exception {
- CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent, timeoutMs);
- NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
- assertFalse(nc.hasCapability(capability));
- return nc;
- }
-
- void expectCapabilitiesLike(Predicate<NetworkCapabilities> fn, MockNetworkAgent agent)
- throws Exception {
- CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
- assertTrue("Received capabilities don't match expectations : " + cbi.arg,
- fn.test((NetworkCapabilities) cbi.arg));
- }
-
- void expectLinkPropertiesLike(Predicate<LinkProperties> fn, MockNetworkAgent agent)
- throws Exception {
- CallbackInfo cbi = expectCallback(CallbackState.LINK_PROPERTIES, agent);
- assertTrue("Received LinkProperties don't match expectations : " + cbi.arg,
- fn.test((LinkProperties) cbi.arg));
- }
-
- void expectBlockedStatusCallback(boolean expectBlocked, MockNetworkAgent agent)
- throws Exception {
- CallbackInfo cbi = expectCallback(CallbackState.BLOCKED_STATUS, agent);
- boolean actualBlocked = (boolean) cbi.arg;
- assertEquals(expectBlocked, actualBlocked);
- }
-
- void assertNoCallback() {
- waitForIdle();
- CallbackInfo c = mCallbacks.peek();
- assertNull("Unexpected callback: " + c, c);
+ return callback;
}
}
@@ -2031,16 +1785,16 @@ public class ConnectivityServiceTest {
cv = waitForConnectivityBroadcasts(2);
mWiFiNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ wifiNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
cellNetworkCallback.assertNoCallback();
waitFor(cv);
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
cv = waitForConnectivityBroadcasts(1);
mCellNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
waitFor(cv);
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -2061,21 +1815,21 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- genericNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
genericNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
wifiNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
mWiFiNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ wifiNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
mCellNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
}
@@ -2115,7 +1869,7 @@ public class ConnectivityServiceTest {
// We then get LOSING when wifi validates and cell is outscored.
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
// TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
@@ -2124,15 +1878,15 @@ public class ConnectivityServiceTest {
mEthernetNetworkAgent.connect(true);
callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
// TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackState.LOSING, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mWiFiNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mEthernetNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mEthernetNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mEthernetNetworkAgent);
defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -2148,7 +1902,7 @@ public class ConnectivityServiceTest {
newNetwork = mWiFiNetworkAgent;
}
- callback.expectCallback(CallbackState.LOSING, oldNetwork);
+ callback.expectCallback(CallbackRecord.LOSING, oldNetwork);
// TODO: should we send an AVAILABLE callback to newNetwork, to indicate that it is no
// longer lingering?
defaultCallback.expectAvailableCallbacksValidated(newNetwork);
@@ -2162,7 +1916,7 @@ public class ConnectivityServiceTest {
// We expect a notification about the capabilities change, and nothing else.
defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mWiFiNetworkAgent);
defaultCallback.assertNoCallback();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Wifi no longer satisfies our listen, which is for an unmetered network.
@@ -2171,11 +1925,11 @@ public class ConnectivityServiceTest {
// Disconnect our test networks.
mWiFiNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mCellNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
waitForIdle();
assertEquals(null, mCm.getActiveNetwork());
@@ -2206,8 +1960,8 @@ public class ConnectivityServiceTest {
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -2218,15 +1972,15 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent.adjustScore(50);
mWiFiNetworkAgent.connect(false); // Score: 70
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Tear down wifi.
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -2237,19 +1991,19 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent.connect(true);
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
// TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
mCellNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
waitForIdle();
assertEquals(null, mCm.getActiveNetwork());
@@ -2264,7 +2018,7 @@ public class ConnectivityServiceTest {
defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
// TODO: Investigate sending validated before losing.
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -2275,13 +2029,13 @@ public class ConnectivityServiceTest {
// TODO: should this cause an AVAILABLE callback, to indicate that the network is no longer
// lingering?
mCm.unregisterNetworkCallback(noopCallback);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
// Similar to the above: lingering can start even after the lingered request is removed.
// Disconnect wifi and switch to cell.
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -2300,12 +2054,12 @@ public class ConnectivityServiceTest {
callback.assertNoCallback();
// Now unregister cellRequest and expect cell to start lingering.
mCm.unregisterNetworkCallback(noopCallback);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
// Let linger run its course.
callback.assertNoCallback();
final int lingerTimeoutMs = mService.mLingerDelayMs + mService.mLingerDelayMs / 4;
- callback.expectCallback(CallbackState.LOST, mCellNetworkAgent, lingerTimeoutMs);
+ callback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent, lingerTimeoutMs);
// Register a TRACK_DEFAULT request and check that it does not affect lingering.
TestNetworkCallback trackDefaultCallback = new TestNetworkCallback();
@@ -2314,20 +2068,20 @@ public class ConnectivityServiceTest {
mEthernetNetworkAgent = new MockNetworkAgent(TRANSPORT_ETHERNET);
mEthernetNetworkAgent.connect(true);
callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mWiFiNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
trackDefaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Let linger run its course.
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent, lingerTimeoutMs);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent, lingerTimeoutMs);
// Clean up.
mEthernetNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
- trackDefaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mEthernetNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mEthernetNetworkAgent);
+ trackDefaultCallback.expectCallback(CallbackRecord.LOST, mEthernetNetworkAgent);
mCm.unregisterNetworkCallback(callback);
mCm.unregisterNetworkCallback(defaultCallback);
@@ -2357,7 +2111,7 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent.connect(true);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
// File a request for cellular, then release it.
@@ -2366,7 +2120,7 @@ public class ConnectivityServiceTest {
NetworkCallback noopCallback = new NetworkCallback();
mCm.requestNetwork(cellRequest, noopCallback);
mCm.unregisterNetworkCallback(noopCallback);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
// Let linger run its course.
callback.assertNoCallback();
@@ -2410,12 +2164,12 @@ public class ConnectivityServiceTest {
// If the user chooses yes on the "No Internet access, stay connected?" dialog, we switch to
// wifi even though it's unvalidated.
mCm.setAcceptUnvalidated(mWiFiNetworkAgent.getNetwork(), true, false);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Disconnect wifi, and then reconnect, again with explicitlySelected=true.
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.explicitlySelected(true, false);
mWiFiNetworkAgent.connect(false);
@@ -2424,14 +2178,14 @@ public class ConnectivityServiceTest {
// If the user chooses no on the "No Internet access, stay connected?" dialog, we ask the
// network to disconnect.
mCm.setAcceptUnvalidated(mWiFiNetworkAgent.getNetwork(), false, false);
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// Reconnect, again with explicitlySelected=true, but this time validate.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.explicitlySelected(true, false);
mWiFiNetworkAgent.connect(true);
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
@@ -2447,20 +2201,20 @@ public class ConnectivityServiceTest {
// (i.e., with explicitlySelected=true and acceptUnvalidated=true). Expect to switch to
// wifi immediately.
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.explicitlySelected(true, true);
mWiFiNetworkAgent.connect(false);
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mEthernetNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mEthernetNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mEthernetNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mEthernetNetworkAgent);
// Disconnect and reconnect with explicitlySelected=false and acceptUnvalidated=true.
// Check that the network is not scored specially and that the device prefers cell data.
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.explicitlySelected(false, true);
mWiFiNetworkAgent.connect(false);
@@ -2471,8 +2225,8 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent.disconnect();
mCellNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
}
private int[] makeIntArray(final int size, final int value) {
@@ -2721,7 +2475,7 @@ public class ConnectivityServiceTest {
// Need a trigger point to let NetworkMonitor tell ConnectivityService that network is
// validated.
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
NetworkCapabilities nc = callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED,
mWiFiNetworkAgent);
assertTrue(nc.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
@@ -2729,7 +2483,7 @@ public class ConnectivityServiceTest {
// Disconnect and reconnect wifi with partial connectivity again.
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connectWithPartialConnectivity();
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
@@ -2741,7 +2495,7 @@ public class ConnectivityServiceTest {
// If the user chooses no, disconnect wifi immediately.
mCm.setAcceptPartialConnectivity(mWiFiNetworkAgent.getNetwork(), false/* accept */,
false /* always */);
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// If user accepted partial connectivity before, and device reconnects to that network
// again, but now the network has full connectivity. The network shouldn't contain
@@ -2758,14 +2512,14 @@ public class ConnectivityServiceTest {
waitForIdle();
verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
nc = callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
assertFalse(nc.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY));
// Wifi should be the default network.
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// The user accepted partial connectivity and selected "don't ask again". Now the user
// reconnects to the partial connectivity network. Switch to wifi as soon as partial
@@ -2780,7 +2534,7 @@ public class ConnectivityServiceTest {
waitForIdle();
verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
callback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY, mWiFiNetworkAgent);
mWiFiNetworkAgent.setNetworkValid();
@@ -2790,7 +2544,7 @@ public class ConnectivityServiceTest {
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// If the user accepted partial connectivity, and the device auto-reconnects to the partial
// connectivity network, it should contain both PARTIAL_CONNECTIVITY and VALIDATED.
@@ -2805,11 +2559,11 @@ public class ConnectivityServiceTest {
waitForIdle();
verify(mWiFiNetworkAgent.mNetworkMonitor, times(1)).setAcceptPartialConnectivity();
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(
NET_CAPABILITY_PARTIAL_CONNECTIVITY | NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
}
@Test
@@ -2851,7 +2605,7 @@ public class ConnectivityServiceTest {
false /* always */);
waitForIdle();
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ captivePortalCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
NetworkCapabilities nc =
validatedCallback.expectCapabilitiesWith(NET_CAPABILITY_PARTIAL_CONNECTIVITY,
@@ -2884,7 +2638,7 @@ public class ConnectivityServiceTest {
// Take down network.
// Expect onLost callback.
mWiFiNetworkAgent.disconnect();
- captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ captivePortalCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// Bring up a network with a captive portal.
// Expect onAvailable callback of listen for NET_CAPABILITY_CAPTIVE_PORTAL.
@@ -2898,7 +2652,7 @@ public class ConnectivityServiceTest {
// Expect onLost callback because network no longer provides NET_CAPABILITY_CAPTIVE_PORTAL.
mWiFiNetworkAgent.setNetworkValid();
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), true);
- captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ captivePortalCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// Expect NET_CAPABILITY_VALIDATED onAvailable callback.
validatedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
@@ -2910,7 +2664,7 @@ public class ConnectivityServiceTest {
// Expect NET_CAPABILITY_VALIDATED onLost callback.
mWiFiNetworkAgent.setNetworkInvalid();
mCm.reportNetworkConnectivity(mWiFiNetworkAgent.getNetwork(), false);
- validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ validatedCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
}
@Test
@@ -2942,7 +2696,7 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent.setNetworkPortal("http://example.com");
mCm.reportNetworkConnectivity(wifiNetwork, false);
captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- validatedCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ validatedCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// Check that startCaptivePortalApp sends the expected command to NetworkMonitor.
mCm.startCaptivePortalApp(wifiNetwork);
@@ -2963,7 +2717,7 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent.setNetworkValid();
mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
validatedCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
- captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ captivePortalCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
verify(mNotificationManager, times(1)).notifyAsUser(anyString(),
eq(NotificationType.LOGGED_IN.eventId), any(), eq(UserHandle.ALL));
@@ -3103,24 +2857,24 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent.setNetworkSpecifier(nsFoo);
cFoo.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
for (TestNetworkCallback c: emptyCallbacks) {
- c.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier().equals(nsFoo),
- mWiFiNetworkAgent);
+ c.expectCapabilitiesThat(mWiFiNetworkAgent,
+ (caps) -> caps.getNetworkSpecifier().equals(nsFoo));
}
- cFoo.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier().equals(nsFoo),
- mWiFiNetworkAgent);
+ cFoo.expectCapabilitiesThat(mWiFiNetworkAgent,
+ (caps) -> caps.getNetworkSpecifier().equals(nsFoo));
assertEquals(nsFoo,
mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
cFoo.assertNoCallback();
mWiFiNetworkAgent.setNetworkSpecifier(nsBar);
- cFoo.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ cFoo.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
cBar.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
for (TestNetworkCallback c: emptyCallbacks) {
- c.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier().equals(nsBar),
- mWiFiNetworkAgent);
+ c.expectCapabilitiesThat(mWiFiNetworkAgent,
+ (caps) -> caps.getNetworkSpecifier().equals(nsBar));
}
- cBar.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier().equals(nsBar),
- mWiFiNetworkAgent);
+ cBar.expectCapabilitiesThat(mWiFiNetworkAgent,
+ (caps) -> caps.getNetworkSpecifier().equals(nsBar));
assertEquals(nsBar,
mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
cBar.assertNoCallback();
@@ -3128,23 +2882,23 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent.setNetworkSpecifier(new ConfidentialMatchAllNetworkSpecifier());
cFoo.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
for (TestNetworkCallback c : emptyCallbacks) {
- c.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier() == null,
- mWiFiNetworkAgent);
+ c.expectCapabilitiesThat(mWiFiNetworkAgent,
+ (caps) -> caps.getNetworkSpecifier() == null);
}
- cFoo.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier() == null,
- mWiFiNetworkAgent);
- cBar.expectCapabilitiesLike((caps) -> caps.getNetworkSpecifier() == null,
- mWiFiNetworkAgent);
+ cFoo.expectCapabilitiesThat(mWiFiNetworkAgent,
+ (caps) -> caps.getNetworkSpecifier() == null);
+ cBar.expectCapabilitiesThat(mWiFiNetworkAgent,
+ (caps) -> caps.getNetworkSpecifier() == null);
assertNull(
mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()).getNetworkSpecifier());
cFoo.assertNoCallback();
cBar.assertNoCallback();
mWiFiNetworkAgent.setNetworkSpecifier(null);
- cFoo.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- cBar.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ cFoo.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ cBar.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
for (TestNetworkCallback c: emptyCallbacks) {
- c.expectCallback(CallbackState.NETWORK_CAPABILITIES, mWiFiNetworkAgent);
+ c.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, mWiFiNetworkAgent);
}
assertNoCallbacks(cEmpty1, cEmpty2, cEmpty3, cEmpty4, cFoo, cBar);
@@ -3287,7 +3041,7 @@ public class ConnectivityServiceTest {
// Bring down cell. Expect no default network callback, since it wasn't the default.
mCellNetworkAgent.disconnect();
- cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
defaultNetworkCallback.assertNoCallback();
assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -3302,11 +3056,11 @@ public class ConnectivityServiceTest {
// followed by AVAILABLE cell.
mWiFiNetworkAgent.disconnect();
cellNetworkCallback.assertNoCallback();
- defaultNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ defaultNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
defaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
mCellNetworkAgent.disconnect();
- cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
- defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
+ defaultNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
waitForIdle();
assertEquals(null, mCm.getActiveNetwork());
@@ -3322,7 +3076,7 @@ public class ConnectivityServiceTest {
assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
vpnNetworkAgent.disconnect();
- defaultNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ defaultNetworkCallback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
waitForIdle();
assertEquals(null, mCm.getActiveNetwork());
}
@@ -3350,14 +3104,15 @@ public class ConnectivityServiceTest {
lp.setInterfaceName("foonet_data0");
mCellNetworkAgent.sendLinkProperties(lp);
// We should get onLinkPropertiesChanged().
- cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED,
+ mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
// Suspend the network.
mCellNetworkAgent.suspend();
cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_SUSPENDED,
mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.SUSPENDED, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.SUSPENDED, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
// Register a garden variety default network request.
@@ -3372,7 +3127,7 @@ public class ConnectivityServiceTest {
mCellNetworkAgent.resume();
cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_SUSPENDED,
mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.RESUMED, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.RESUMED, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
dfltNetworkCallback = new TestNetworkCallback();
@@ -3435,10 +3190,10 @@ public class ConnectivityServiceTest {
// When wifi connects, cell lingers.
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
fgCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- fgCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ fgCallback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
fgCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
@@ -3446,7 +3201,7 @@ public class ConnectivityServiceTest {
// When lingering is complete, cell is still there but is now in the background.
waitForIdle();
int timeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
- fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent, timeoutMs);
+ fgCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent, timeoutMs);
// Expect a network capabilities update sans FOREGROUND.
callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
assertFalse(isForegroundNetwork(mCellNetworkAgent));
@@ -3472,7 +3227,7 @@ public class ConnectivityServiceTest {
// Release the request. The network immediately goes into the background, since it was not
// lingering.
mCm.unregisterNetworkCallback(cellCallback);
- fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ fgCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
// Expect a network capabilities update sans FOREGROUND.
callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
assertFalse(isForegroundNetwork(mCellNetworkAgent));
@@ -3480,8 +3235,8 @@ public class ConnectivityServiceTest {
// Disconnect wifi and check that cell is foreground again.
mWiFiNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- fgCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ fgCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
fgCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
@@ -3618,7 +3373,7 @@ public class ConnectivityServiceTest {
testFactory.waitForNetworkRequests(1);
// ... and cell data to be torn down.
- cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
assertLength(1, mCm.getAllNetworks());
testFactory.unregister();
@@ -3709,7 +3464,7 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent.setNetworkInvalid();
mCm.reportNetworkConnectivity(wifiNetwork, false);
defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ validatedWifiCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// Because avoid bad wifi is off, we don't switch to cellular.
defaultCallback.assertNoCallback();
@@ -3753,7 +3508,7 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent.setNetworkInvalid();
mCm.reportNetworkConnectivity(wifiNetwork, false);
defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
- validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ validatedWifiCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// Simulate the user selecting "switch" and checking the don't ask again checkbox.
Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
@@ -3780,7 +3535,7 @@ public class ConnectivityServiceTest {
// If cell goes down, we switch to wifi.
mCellNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
validatedWifiCallback.assertNoCallback();
@@ -3845,7 +3600,7 @@ public class ConnectivityServiceTest {
networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, false,
TEST_CALLBACK_TIMEOUT_MS);
mWiFiNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
// Validate that UNAVAILABLE is not called
networkCallback.assertNoCallback();
@@ -3865,7 +3620,7 @@ public class ConnectivityServiceTest {
mCm.requestNetwork(nr, networkCallback, timeoutMs);
// pass timeout and validate that UNAVAILABLE is called
- networkCallback.expectCallback(CallbackState.UNAVAILABLE, null);
+ networkCallback.expectCallback(CallbackRecord.UNAVAILABLE, null);
// create a network satisfying request - validate that request not triggered
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
@@ -3956,7 +3711,7 @@ public class ConnectivityServiceTest {
// Simulate the factory releasing the request as unfulfillable and expect onUnavailable!
testFactory.triggerUnfulfillable(requests.get(newRequestId));
- networkCallback.expectCallback(CallbackState.UNAVAILABLE, null);
+ networkCallback.expectCallback(CallbackRecord.UNAVAILABLE, null);
testFactory.waitForRequests();
// unregister network callback - a no-op (since already freed by the
@@ -4797,7 +4552,7 @@ public class ConnectivityServiceTest {
// Disconnect wifi aware network.
wifiAware.disconnect();
- callback.expectCallbackLike((info) -> info.state == CallbackState.LOST, TIMEOUT_MS);
+ callback.expectCallbackThat(TIMEOUT_MS, (info) -> info instanceof CallbackRecord.Lost);
mCm.unregisterNetworkCallback(callback);
verifyNoNetwork();
@@ -4846,14 +4601,15 @@ public class ConnectivityServiceTest {
// ConnectivityService.
MockNetworkAgent networkAgent = new MockNetworkAgent(TRANSPORT_WIFI, lp);
networkAgent.connect(true);
- networkCallback.expectCallback(CallbackState.AVAILABLE, networkAgent);
- networkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, networkAgent);
- CallbackInfo cbi = networkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ networkCallback.expectCallback(CallbackRecord.AVAILABLE, networkAgent);
+ networkCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, networkAgent);
+ CallbackRecord.LinkPropertiesChanged cbi =
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED,
networkAgent);
- networkCallback.expectCallback(CallbackState.BLOCKED_STATUS, networkAgent);
+ networkCallback.expectCallback(CallbackRecord.BLOCKED_STATUS, networkAgent);
networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, networkAgent);
networkCallback.assertNoCallback();
- checkDirectlyConnectedRoutes(cbi.arg, Arrays.asList(myIpv4Address),
+ checkDirectlyConnectedRoutes(cbi.getLp(), Arrays.asList(myIpv4Address),
Arrays.asList(myIpv4DefaultRoute));
checkDirectlyConnectedRoutes(mCm.getLinkProperties(networkAgent.getNetwork()),
Arrays.asList(myIpv4Address), Arrays.asList(myIpv4DefaultRoute));
@@ -4865,9 +4621,9 @@ public class ConnectivityServiceTest {
newLp.addLinkAddress(myIpv6Address1);
newLp.addLinkAddress(myIpv6Address2);
networkAgent.sendLinkProperties(newLp);
- cbi = networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, networkAgent);
+ cbi = networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, networkAgent);
networkCallback.assertNoCallback();
- checkDirectlyConnectedRoutes(cbi.arg,
+ checkDirectlyConnectedRoutes(cbi.getLp(),
Arrays.asList(myIpv4Address, myIpv6Address1, myIpv6Address2),
Arrays.asList(myIpv4DefaultRoute));
mCm.unregisterNetworkCallback(networkCallback);
@@ -5071,15 +4827,15 @@ public class ConnectivityServiceTest {
assertTrue(ArrayUtils.containsAll(resolvrParams.tlsServers,
new String[] { "2001:db8::1", "192.0.2.1" }));
reset(mMockDnsResolver);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES,
+ cellNetworkCallback.expectCallback(CallbackRecord.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED,
mCellNetworkAgent);
- CallbackInfo cbi = cellNetworkCallback.expectCallback(
- CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.BLOCKED_STATUS, mCellNetworkAgent);
+ CallbackRecord.LinkPropertiesChanged cbi = cellNetworkCallback.expectCallback(
+ CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.BLOCKED_STATUS, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
- assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive());
- assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
+ assertFalse(cbi.getLp().isPrivateDnsActive());
+ assertNull(cbi.getLp().getPrivateDnsServerName());
setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
verify(mMockDnsResolver, times(1)).setResolverConfiguration(
@@ -5107,11 +4863,11 @@ public class ConnectivityServiceTest {
setPrivateDnsSettings(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, "strict.example.com");
// Can't test dns configuration for strict mode without properly mocking
// out the DNS lookups, but can test that LinkProperties is updated.
- cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ cbi = cellNetworkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED,
mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
- assertTrue(((LinkProperties)cbi.arg).isPrivateDnsActive());
- assertEquals("strict.example.com", ((LinkProperties)cbi.arg).getPrivateDnsServerName());
+ assertTrue(cbi.getLp().isPrivateDnsActive());
+ assertEquals("strict.example.com", cbi.getLp().getPrivateDnsServerName());
}
@Test
@@ -5130,17 +4886,17 @@ public class ConnectivityServiceTest {
mCellNetworkAgent.sendLinkProperties(lp);
mCellNetworkAgent.connect(false);
waitForIdle();
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES,
+ cellNetworkCallback.expectCallback(CallbackRecord.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED,
mCellNetworkAgent);
- CallbackInfo cbi = cellNetworkCallback.expectCallback(
- CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.BLOCKED_STATUS, mCellNetworkAgent);
+ CallbackRecord.LinkPropertiesChanged cbi = cellNetworkCallback.expectCallback(
+ CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackRecord.BLOCKED_STATUS, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
- assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive());
- assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
+ assertFalse(cbi.getLp().isPrivateDnsActive());
+ assertNull(cbi.getLp().getPrivateDnsServerName());
Set<InetAddress> dnsServers = new HashSet<>();
- checkDnsServers(cbi.arg, dnsServers);
+ checkDnsServers(cbi.getLp(), dnsServers);
// Send a validation event for a server that is not part of the current
// resolver config. The validation event should be ignored.
@@ -5152,13 +4908,13 @@ public class ConnectivityServiceTest {
LinkProperties lp2 = new LinkProperties(lp);
lp2.addDnsServer(InetAddress.getByName("145.100.185.16"));
mCellNetworkAgent.sendLinkProperties(lp2);
- cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ cbi = cellNetworkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED,
mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
- assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive());
- assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
+ assertFalse(cbi.getLp().isPrivateDnsActive());
+ assertNull(cbi.getLp().getPrivateDnsServerName());
dnsServers.add(InetAddress.getByName("145.100.185.16"));
- checkDnsServers(cbi.arg, dnsServers);
+ checkDnsServers(cbi.getLp(), dnsServers);
// Send a validation event containing a hostname that is not part of
// the current resolver config. The validation event should be ignored.
@@ -5176,39 +4932,39 @@ public class ConnectivityServiceTest {
// private dns fields should be sent.
mService.mNetdEventCallback.onPrivateDnsValidationEvent(
mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "", true);
- cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ cbi = cellNetworkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED,
mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
- assertTrue(((LinkProperties)cbi.arg).isPrivateDnsActive());
- assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
- checkDnsServers(cbi.arg, dnsServers);
+ assertTrue(cbi.getLp().isPrivateDnsActive());
+ assertNull(cbi.getLp().getPrivateDnsServerName());
+ checkDnsServers(cbi.getLp(), dnsServers);
// The private dns fields in LinkProperties should be preserved when
// the network agent sends unrelated changes.
LinkProperties lp3 = new LinkProperties(lp2);
lp3.setMtu(1300);
mCellNetworkAgent.sendLinkProperties(lp3);
- cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ cbi = cellNetworkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED,
mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
- assertTrue(((LinkProperties)cbi.arg).isPrivateDnsActive());
- assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
- checkDnsServers(cbi.arg, dnsServers);
- assertEquals(1300, ((LinkProperties)cbi.arg).getMtu());
+ assertTrue(cbi.getLp().isPrivateDnsActive());
+ assertNull(cbi.getLp().getPrivateDnsServerName());
+ checkDnsServers(cbi.getLp(), dnsServers);
+ assertEquals(1300, cbi.getLp().getMtu());
// Removing the only validated server should affect the private dns
// fields in LinkProperties.
LinkProperties lp4 = new LinkProperties(lp3);
lp4.removeDnsServer(InetAddress.getByName("145.100.185.16"));
mCellNetworkAgent.sendLinkProperties(lp4);
- cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ cbi = cellNetworkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED,
mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
- assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive());
- assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
+ assertFalse(cbi.getLp().isPrivateDnsActive());
+ assertNull(cbi.getLp().getPrivateDnsServerName());
dnsServers.remove(InetAddress.getByName("145.100.185.16"));
- checkDnsServers(cbi.arg, dnsServers);
- assertEquals(1300, ((LinkProperties)cbi.arg).getMtu());
+ checkDnsServers(cbi.getLp(), dnsServers);
+ assertEquals(1300, cbi.getLp().getMtu());
}
private void checkDirectlyConnectedRoutes(Object callbackObj,
@@ -5290,19 +5046,19 @@ public class ConnectivityServiceTest {
defaultCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- genericNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, vpnNetworkAgent);
genericNotVpnNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectCapabilitiesLike(nc -> null == nc.getUids(), vpnNetworkAgent);
- defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent, nc -> null == nc.getUids());
+ defaultCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, vpnNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
ranges.clear();
vpnNetworkAgent.setUids(ranges);
- genericNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ vpnNetworkCallback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
// TODO : The default network callback should actually get a LOST call here (also see the
// comment below for AVAILABLE). This is because ConnectivityService does not look at UID
@@ -5310,7 +5066,7 @@ public class ConnectivityServiceTest {
// can't currently update their UIDs without disconnecting, so this does not matter too
// much, but that is the reason the test here has to check for an update to the
// capabilities instead of the expected LOST then AVAILABLE.
- defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, vpnNetworkAgent);
ranges.add(new UidRange(uid, uid));
mMockVpn.setUids(ranges);
@@ -5322,23 +5078,23 @@ public class ConnectivityServiceTest {
vpnNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
// TODO : Here like above, AVAILABLE would be correct, but because this can't actually
// happen outside of the test, ConnectivityService does not rematch callbacks.
- defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, vpnNetworkAgent);
mWiFiNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- genericNotVpnNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ genericNotVpnNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
+ wifiNetworkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
vpnNetworkCallback.assertNoCallback();
defaultCallback.assertNoCallback();
vpnNetworkAgent.disconnect();
- genericNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
- defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ vpnNetworkCallback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
assertEquals(null, mCm.getActiveNetwork());
mCm.unregisterNetworkCallback(genericNetworkCallback);
@@ -5402,7 +5158,7 @@ public class ConnectivityServiceTest {
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
vpnNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
mCm.unregisterNetworkCallback(defaultCallback);
@@ -5432,7 +5188,7 @@ public class ConnectivityServiceTest {
// Even though the VPN is unvalidated, it becomes the default network for our app.
callback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
// TODO: this looks like a spurious callback.
- callback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+ callback.expectCallback(CallbackRecord.NETWORK_CAPS_UPDATED, vpnNetworkAgent);
callback.assertNoCallback();
assertTrue(vpnNetworkAgent.getScore() > mEthernetNetworkAgent.getScore());
@@ -5456,7 +5212,7 @@ public class ConnectivityServiceTest {
callback.assertNoCallback();
vpnNetworkAgent.disconnect();
- callback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ callback.expectCallback(CallbackRecord.LOST, vpnNetworkAgent);
callback.expectAvailableCallbacksValidated(mEthernetNetworkAgent);
}
@@ -5496,10 +5252,10 @@ public class ConnectivityServiceTest {
mService.setUnderlyingNetworksForVpn(
new Network[] { mCellNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
@@ -5508,52 +5264,52 @@ public class ConnectivityServiceTest {
mService.setUnderlyingNetworksForVpn(
new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
// Don't disconnect, but note the VPN is not using wifi any more.
mService.setUnderlyingNetworksForVpn(
new Network[] { mCellNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
// Use Wifi but not cell. Note the VPN is now unmetered.
mService.setUnderlyingNetworksForVpn(
new Network[] { mWiFiNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && caps.hasCapability(NET_CAPABILITY_NOT_METERED));
// Use both again.
mService.setUnderlyingNetworksForVpn(
new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
// Disconnect cell. Receive update without even removing the dead network from the
// underlying networks – it's dead anyway. Not metered any more.
mCellNetworkAgent.disconnect();
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && caps.hasCapability(NET_CAPABILITY_NOT_METERED));
// Disconnect wifi too. No underlying networks means this is now metered.
mWiFiNetworkAgent.disconnect();
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
mMockVpn.disconnect();
}
@@ -5592,20 +5348,20 @@ public class ConnectivityServiceTest {
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
// Connect to WiFi; WiFi is the new default.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
mWiFiNetworkAgent.connect(true);
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
- && caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && caps.hasCapability(NET_CAPABILITY_NOT_METERED));
// Disconnect Cell. The default network did not change, so there shouldn't be any changes in
// the capabilities.
@@ -5614,10 +5370,10 @@ public class ConnectivityServiceTest {
// Disconnect wifi too. Now we have no default network.
mWiFiNetworkAgent.disconnect();
- vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ (caps) -> caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
- && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
- vpnNetworkAgent);
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
mMockVpn.disconnect();
}
@@ -5893,7 +5649,7 @@ public class ConnectivityServiceTest {
// Switch to METERED network. Restrict the use of the network.
mWiFiNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksValidatedAndBlocked(mCellNetworkAgent);
// Network becomes NOT_METERED.
@@ -5907,7 +5663,7 @@ public class ConnectivityServiceTest {
defaultCallback.assertNoCallback();
mCellNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ defaultCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
defaultCallback.assertNoCallback();
mCm.unregisterNetworkCallback(defaultCallback);
@@ -5983,7 +5739,7 @@ public class ConnectivityServiceTest {
// the NAT64 prefix was removed because one was never discovered.
cellLp.addLinkAddress(myIpv4);
mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(any());
@@ -5996,7 +5752,7 @@ public class ConnectivityServiceTest {
cellLp.removeLinkAddress(myIpv4);
cellLp.removeRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
// When NAT64 prefix discovery succeeds, LinkProperties are updated and clatd is started.
@@ -6004,15 +5760,15 @@ public class ConnectivityServiceTest {
assertNull(mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getNat64Prefix());
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
kNat64PrefixString, 96);
- LinkProperties lpBeforeClat = (LinkProperties) networkCallback.expectCallback(
- CallbackState.LINK_PROPERTIES, mCellNetworkAgent).arg;
+ LinkProperties lpBeforeClat = networkCallback.expectCallback(
+ CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent).getLp();
assertEquals(0, lpBeforeClat.getStackedLinks().size());
assertEquals(kNat64Prefix, lpBeforeClat.getNat64Prefix());
verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kNat64Prefix.toString());
// Clat iface comes up. Expect stacked link to be added.
clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
List<LinkProperties> stackedLps = mCm.getLinkProperties(mCellNetworkAgent.getNetwork())
.getStackedLinks();
assertEquals(makeClatLinkProperties(myIpv4), stackedLps.get(0));
@@ -6020,7 +5776,7 @@ public class ConnectivityServiceTest {
// Change trivial linkproperties and see if stacked link is preserved.
cellLp.addDnsServer(InetAddress.getByName("8.8.8.8"));
mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
List<LinkProperties> stackedLpsAfterChange =
mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getStackedLinks();
@@ -6038,12 +5794,12 @@ public class ConnectivityServiceTest {
cellLp.addLinkAddress(myIpv4);
cellLp.addRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
// As soon as stop is called, the linkproperties lose the stacked interface.
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
LinkProperties actualLpAfterIpv4 = mCm.getLinkProperties(mCellNetworkAgent.getNetwork());
LinkProperties expected = new LinkProperties(cellLp);
expected.setNat64Prefix(kNat64Prefix);
@@ -6062,41 +5818,39 @@ public class ConnectivityServiceTest {
// Stopping prefix discovery causes netd to tell us that the NAT64 prefix is gone.
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
kNat64PrefixString, 96);
- networkCallback.expectLinkPropertiesLike((lp) -> lp.getNat64Prefix() == null,
- mCellNetworkAgent);
+ networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
+ (lp) -> lp.getNat64Prefix() == null);
// Remove IPv4 address and expect prefix discovery and clatd to be started again.
cellLp.removeLinkAddress(myIpv4);
cellLp.removeRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
cellLp.removeDnsServer(InetAddress.getByName("8.8.8.8"));
mCellNetworkAgent.sendLinkProperties(cellLp);
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
kNat64PrefixString, 96);
- networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kNat64Prefix.toString());
// Clat iface comes up. Expect stacked link to be added.
clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
- networkCallback.expectLinkPropertiesLike(
- (lp) -> lp.getStackedLinks().size() == 1 && lp.getNat64Prefix() != null,
- mCellNetworkAgent);
+ networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
+ (lp) -> lp.getStackedLinks().size() == 1 && lp.getNat64Prefix() != null);
// NAT64 prefix is removed. Expect that clat is stopped.
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
kNat64PrefixString, 96);
- networkCallback.expectLinkPropertiesLike(
- (lp) -> lp.getStackedLinks().size() == 0 && lp.getNat64Prefix() == null,
- mCellNetworkAgent);
+ networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
+ (lp) -> lp.getStackedLinks().size() == 0 && lp.getNat64Prefix() == null);
verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
- networkCallback.expectLinkPropertiesLike((lp) -> lp.getStackedLinks().size() == 0,
- mCellNetworkAgent);
+ networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
+ (lp) -> lp.getStackedLinks().size() == 0);
// Clean up.
mCellNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
networkCallback.assertNoCallback();
mCm.unregisterNetworkCallback(networkCallback);
}
@@ -6128,7 +5882,7 @@ public class ConnectivityServiceTest {
reset(mNetworkManagementService);
mWiFiNetworkAgent.connect(true);
networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- networkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
verify(mNetworkManagementService, times(1)).addIdleTimer(eq(WIFI_IFNAME), anyInt(),
eq(ConnectivityManager.TYPE_WIFI));
@@ -6137,7 +5891,7 @@ public class ConnectivityServiceTest {
// Disconnect wifi and switch back to cell
reset(mNetworkManagementService);
mWiFiNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LOST, mWiFiNetworkAgent);
assertNoCallbacks(networkCallback);
verify(mNetworkManagementService, times(1)).removeIdleTimer(eq(WIFI_IFNAME));
verify(mNetworkManagementService, times(1)).addIdleTimer(eq(MOBILE_IFNAME), anyInt(),
@@ -6149,14 +5903,14 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent.sendLinkProperties(wifiLp);
mWiFiNetworkAgent.connect(true);
networkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- networkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LOSING, mCellNetworkAgent);
networkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
// Disconnect cell
reset(mNetworkManagementService);
reset(mMockNetd);
mCellNetworkAgent.disconnect();
- networkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ networkCallback.expectCallback(CallbackRecord.LOST, mCellNetworkAgent);
// LOST callback is triggered earlier than removing idle timer. Broadcast should also be
// sent as network being switched. Ensure rule removal for cell will not be triggered
// unexpectedly before network being removed.
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index 6c42ac398b47..8c522f48cfd2 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -100,6 +100,8 @@ import android.os.UserManager;
import android.os.test.TestLooper;
import android.provider.Settings;
import android.telephony.CarrierConfigManager;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
import android.test.mock.MockContentResolver;
import androidx.test.filters.SmallTest;
@@ -111,6 +113,7 @@ import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
import com.android.server.connectivity.tethering.OffloadHardwareInterface;
+import com.android.server.connectivity.tethering.TetheringConfiguration;
import com.android.server.connectivity.tethering.TetheringDependencies;
import com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
@@ -118,6 +121,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -147,6 +151,7 @@ public class TetheringTest {
@Mock private MockableSystemProperties mSystemProperties;
@Mock private OffloadHardwareInterface mOffloadHardwareInterface;
@Mock private Resources mResources;
+ @Mock private TelephonyManager mTelephonyManager;
@Mock private UsbManager mUsbManager;
@Mock private WifiManager mWifiManager;
@Mock private CarrierConfigManager mCarrierConfigManager;
@@ -171,6 +176,7 @@ public class TetheringTest {
private MockContentResolver mContentResolver;
private BroadcastReceiver mBroadcastReceiver;
private Tethering mTethering;
+ private PhoneStateListener mPhoneStateListener;
private class MockContext extends BroadcastInterceptingContext {
MockContext(Context base) {
@@ -193,6 +199,7 @@ public class TetheringTest {
public Object getSystemService(String name) {
if (Context.WIFI_SERVICE.equals(name)) return mWifiManager;
if (Context.USB_SERVICE.equals(name)) return mUsbManager;
+ if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager;
return super.getSystemService(name);
}
}
@@ -234,6 +241,17 @@ public class TetheringTest {
}
}
+ private class MockTetheringConfiguration extends TetheringConfiguration {
+ MockTetheringConfiguration(Context ctx, SharedLog log, int id) {
+ super(ctx, log, id);
+ }
+
+ @Override
+ protected Resources getResourcesForSubIdWrapper(Context ctx, int subId) {
+ return mResources;
+ }
+ }
+
public class MockTetheringDependencies extends TetheringDependencies {
StateMachine upstreamNetworkMonitorMasterSM;
ArrayList<IpServer> ipv6CoordinatorNotifyList;
@@ -276,8 +294,9 @@ public class TetheringTest {
}
@Override
- public int getDefaultDataSubscriptionId() {
- return INVALID_SUBSCRIPTION_ID;
+ public TetheringConfiguration generateTetheringConfiguration(Context ctx, SharedLog log,
+ int subId) {
+ return new MockTetheringConfiguration(ctx, log, subId);
}
}
@@ -372,6 +391,11 @@ public class TetheringTest {
mTetheringDependencies.reset();
mTethering = makeTethering();
verify(mNMService).registerTetheringStatsProvider(any(), anyString());
+ final ArgumentCaptor<PhoneStateListener> phoneListenerCaptor =
+ ArgumentCaptor.forClass(PhoneStateListener.class);
+ verify(mTelephonyManager).listen(phoneListenerCaptor.capture(),
+ eq(PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE));
+ mPhoneStateListener = phoneListenerCaptor.getValue();
}
private Tethering makeTethering() {
@@ -982,6 +1006,17 @@ public class TetheringTest {
callback2.expectUpstreamChanged(upstreamState.network);
}
+ @Test
+ public void testMultiSimAware() throws Exception {
+ final TetheringConfiguration initailConfig = mTethering.getTetheringConfiguration();
+ assertEquals(INVALID_SUBSCRIPTION_ID, initailConfig.subId);
+
+ final int fakeSubId = 1234;
+ mPhoneStateListener.onActiveDataSubscriptionIdChanged(fakeSubId);
+ final TetheringConfiguration newConfig = mTethering.getTetheringConfiguration();
+ assertEquals(fakeSubId, newConfig.subId);
+ }
+
// TODO: Test that a request for hotspot mode doesn't interfere with an
// already operating tethering mode interface.
}
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
index 21403225c600..e28296354d2a 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
@@ -29,6 +29,7 @@ import static com.android.internal.R.array.config_tether_upstream_types;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.when;
import android.content.ContentResolver;
@@ -141,7 +142,7 @@ public class TetheringConfigurationTest {
@Test
public void testDunFromTelephonyManagerMeansDun() {
- when(mTelephonyManager.getTetherApnRequired()).thenReturn(true);
+ when(mTelephonyManager.getTetherApnRequired(anyInt())).thenReturn(true);
final TetheringConfiguration cfgWifi = getTetheringConfiguration(TYPE_WIFI);
final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration(
@@ -165,7 +166,7 @@ public class TetheringConfigurationTest {
@Test
public void testDunNotRequiredFromTelephonyManagerMeansNoDun() {
- when(mTelephonyManager.getTetherApnRequired()).thenReturn(false);
+ when(mTelephonyManager.getTetherApnRequired(anyInt())).thenReturn(false);
final TetheringConfiguration cfgWifi = getTetheringConfiguration(TYPE_WIFI);
final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration(
@@ -208,7 +209,7 @@ public class TetheringConfigurationTest {
@Test
public void testNoDefinedUpstreamTypesAddsEthernet() {
when(mResources.getIntArray(config_tether_upstream_types)).thenReturn(new int[]{});
- when(mTelephonyManager.getTetherApnRequired()).thenReturn(false);
+ when(mTelephonyManager.getTetherApnRequired(anyInt())).thenReturn(false);
final TetheringConfiguration cfg = new TetheringConfiguration(
mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
@@ -231,7 +232,7 @@ public class TetheringConfigurationTest {
public void testDefinedUpstreamTypesSansEthernetAddsEthernet() {
when(mResources.getIntArray(config_tether_upstream_types)).thenReturn(
new int[]{TYPE_WIFI, TYPE_MOBILE_HIPRI});
- when(mTelephonyManager.getTetherApnRequired()).thenReturn(false);
+ when(mTelephonyManager.getTetherApnRequired(anyInt())).thenReturn(false);
final TetheringConfiguration cfg = new TetheringConfiguration(
mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
@@ -249,7 +250,7 @@ public class TetheringConfigurationTest {
public void testDefinedUpstreamTypesWithEthernetDoesNotAddEthernet() {
when(mResources.getIntArray(config_tether_upstream_types))
.thenReturn(new int[]{TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_HIPRI});
- when(mTelephonyManager.getTetherApnRequired()).thenReturn(false);
+ when(mTelephonyManager.getTetherApnRequired(anyInt())).thenReturn(false);
final TetheringConfiguration cfg = new TetheringConfiguration(
mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
diff --git a/tools/aapt2/optimize/ResourcePathShortener.cpp b/tools/aapt2/optimize/ResourcePathShortener.cpp
index 845262bcb0d9..6b11de759d2d 100644
--- a/tools/aapt2/optimize/ResourcePathShortener.cpp
+++ b/tools/aapt2/optimize/ResourcePathShortener.cpp
@@ -23,6 +23,7 @@
#include "ResourceTable.h"
#include "ValueVisitor.h"
+#include "util/Util.h"
static const std::string base64_chars =
@@ -95,8 +96,8 @@ bool ResourcePathShortener::Consume(IAaptContext* context, ResourceTable* table)
android::StringPiece res_subdir, actual_filename, extension;
util::ExtractResFilePathParts(*file_ref->path, &res_subdir, &actual_filename, &extension);
- // Android detects ColorStateLists via pathname, skip res/color/*
- if (res_subdir == android::StringPiece("res/color/"))
+ // Android detects ColorStateLists via pathname, skip res/color*
+ if (util::StartsWith(res_subdir, "res/color"))
continue;
std::string shortened_filename = ShortenFileName(*file_ref->path, num_chars);
diff --git a/tools/aapt2/optimize/ResourcePathShortener_test.cpp b/tools/aapt2/optimize/ResourcePathShortener_test.cpp
index efbef8f40722..1f4569495186 100644
--- a/tools/aapt2/optimize/ResourcePathShortener_test.cpp
+++ b/tools/aapt2/optimize/ResourcePathShortener_test.cpp
@@ -75,6 +75,9 @@ TEST(ResourcePathShortenerTest, SkipColorFileRefPaths) {
std::unique_ptr<ResourceTable> table =
test::ResourceTableBuilder()
.AddFileReference("android:color/colorlist", "res/color/colorlist.xml")
+ .AddFileReference("android:color/colorlist",
+ "res/color-mdp-v21/colorlist.xml",
+ test::ParseConfigOrDie("mdp-v21"))
.Build();
std::map<std::string, std::string> path_map;
@@ -82,6 +85,7 @@ TEST(ResourcePathShortenerTest, SkipColorFileRefPaths) {
// Expect that the path map to not contain the ColorStateList
ASSERT_THAT(path_map.find("res/color/colorlist.xml"), Eq(path_map.end()));
+ ASSERT_THAT(path_map.find("res/color-mdp-v21/colorlist.xml"), Eq(path_map.end()));
}
TEST(ResourcePathShortenerTest, KeepExtensions) {