summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp14
-rw-r--r--StubLibraries.bp28
-rw-r--r--apex/media/framework/Android.bp5
-rw-r--r--apex/media/framework/java/android/media/MediaParser.java3
-rw-r--r--apex/permission/framework/Android.bp5
-rw-r--r--apex/permission/service/java/com/android/permission/persistence/IoUtils.java2
-rw-r--r--apex/statsd/framework/Android.bp11
-rw-r--r--apex/statsd/framework/java/android/app/StatsManager.java10
-rw-r--r--apex/statsd/framework/java/android/util/StatsEvent.java50
-rw-r--r--apex/statsd/framework/java/android/util/StatsLog.java2
-rw-r--r--apex/statsd/framework/test/src/android/util/StatsEventTest.java160
-rw-r--r--api/test-current.txt124
-rw-r--r--cmds/bootanimation/BootAnimation.cpp30
-rw-r--r--cmds/bootanimation/BootAnimation.h3
-rw-r--r--cmds/idmap2/Android.bp2
-rw-r--r--cmds/idmap2/idmap2/CommandUtils.cpp (renamed from cmds/idmap2/idmap2/Verify.cpp)22
-rw-r--r--cmds/idmap2/idmap2/CommandUtils.h28
-rw-r--r--cmds/idmap2/idmap2/Commands.h1
-rw-r--r--cmds/idmap2/idmap2/CreateMultiple.cpp4
-rw-r--r--cmds/idmap2/idmap2/Main.cpp5
-rw-r--r--cmds/idmap2/idmap2/Scan.cpp14
-rw-r--r--cmds/idmap2/idmap2d/Idmap2Service.cpp75
-rw-r--r--cmds/idmap2/include/idmap2/Idmap.h17
-rw-r--r--cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp2
-rw-r--r--cmds/idmap2/libidmap2/Idmap.cpp64
-rw-r--r--cmds/idmap2/libidmap2/RawPrintVisitor.cpp8
-rw-r--r--cmds/idmap2/libidmap2/ResourceMapping.cpp10
-rw-r--r--cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h26
-rw-r--r--cmds/idmap2/tests/BinaryStreamVisitorTests.cpp5
-rw-r--r--cmds/idmap2/tests/IdmapTests.cpp74
-rw-r--r--cmds/idmap2/tests/RawPrintVisitorTests.cpp41
-rw-r--r--cmds/idmap2/tests/ResourceMappingTests.cpp70
-rw-r--r--cmds/idmap2/tests/TestHelpers.h52
-rw-r--r--cmds/statsd/src/atoms.proto94
-rw-r--r--cmds/statsd/src/condition/CombinationConditionTracker.cpp14
-rw-r--r--cmds/statsd/src/condition/CombinationConditionTracker.h4
-rw-r--r--cmds/statsd/src/condition/ConditionTracker.h4
-rw-r--r--cmds/statsd/src/condition/SimpleConditionTracker.cpp4
-rw-r--r--cmds/statsd/src/condition/SimpleConditionTracker.h4
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.cpp8
-rw-r--r--cmds/statsd/src/metrics/CountMetricProducer.h3
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.cpp11
-rw-r--r--cmds/statsd/src/metrics/DurationMetricProducer.h8
-rw-r--r--cmds/statsd/src/metrics/EventMetricProducer.cpp7
-rw-r--r--cmds/statsd/src/metrics/EventMetricProducer.h3
-rw-r--r--cmds/statsd/src/metrics/GaugeMetricProducer.cpp13
-rw-r--r--cmds/statsd/src/metrics/GaugeMetricProducer.h1
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.cpp5
-rw-r--r--cmds/statsd/src/metrics/MetricProducer.h10
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.cpp6
-rw-r--r--cmds/statsd/src/metrics/ValueMetricProducer.h5
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.cpp55
-rw-r--r--cmds/statsd/src/metrics/metrics_manager_util.h5
-rw-r--r--cmds/statsd/tests/MetricsManager_test.cpp146
-rw-r--r--cmds/statsd/tests/condition/CombinationConditionTracker_test.cpp1
-rw-r--r--cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp108
-rw-r--r--cmds/statsd/tests/metrics/CountMetricProducer_test.cpp33
-rw-r--r--cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp44
-rw-r--r--cmds/statsd/tests/metrics/EventMetricProducer_test.cpp10
-rw-r--r--cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp63
-rw-r--r--cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp264
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java6
-rw-r--r--core/java/android/app/Activity.java6
-rw-r--r--core/java/android/app/ActivityThread.java73
-rw-r--r--core/java/android/app/ApplicationPackageManager.java7
-rw-r--r--core/java/android/app/ContextImpl.java2
-rw-r--r--core/java/android/app/ITaskStackListener.aidl10
-rw-r--r--core/java/android/app/Instrumentation.java12
-rw-r--r--core/java/android/app/LoadedApk.java28
-rw-r--r--core/java/android/app/Notification.java7
-rw-r--r--core/java/android/app/PendingIntent.java8
-rw-r--r--core/java/android/app/TaskStackListener.java4
-rw-r--r--core/java/android/content/Intent.java43
-rw-r--r--core/java/android/content/pm/ActivityInfo.java13
-rw-r--r--core/java/android/content/pm/PackageInstaller.java12
-rw-r--r--core/java/android/content/pm/PackageItemInfo.java12
-rw-r--r--core/java/android/content/pm/PackageParser.java15
-rw-r--r--core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java1
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageUtils.java18
-rw-r--r--core/java/android/content/pm/parsing/component/ParsedActivity.java15
-rw-r--r--core/java/android/content/pm/parsing/component/ParsedActivityUtils.java9
-rw-r--r--core/java/android/content/pm/parsing/component/ParsedComponentUtils.java29
-rw-r--r--core/java/android/hardware/biometrics/BiometricManager.java11
-rw-r--r--core/java/android/hardware/hdmi/HdmiClient.java4
-rw-r--r--core/java/android/hardware/hdmi/HdmiControlManager.java120
-rw-r--r--core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java469
-rw-r--r--core/java/android/hardware/hdmi/HdmiPortInfo.java9
-rw-r--r--core/java/android/hardware/hdmi/HdmiSwitchClient.java5
-rw-r--r--core/java/android/hardware/hdmi/IHdmiCecVolumeControlFeatureListener.aidl32
-rw-r--r--core/java/android/hardware/hdmi/IHdmiControlService.aidl3
-rw-r--r--core/java/android/inputmethodservice/AbstractInputMethodService.java6
-rw-r--r--core/java/android/net/NetworkCapabilities.java12
-rw-r--r--core/java/android/os/AppZygote.java5
-rw-r--r--core/java/android/os/GraphicsEnvironment.java166
-rw-r--r--core/java/android/os/StrictMode.java7
-rw-r--r--core/java/android/os/UserManager.java7
-rw-r--r--core/java/android/os/storage/StorageManager.java2
-rwxr-xr-xcore/java/android/provider/Settings.java18
-rw-r--r--core/java/android/provider/Telephony.java40
-rw-r--r--core/java/android/service/autofill/InlineSuggestionRoot.java4
-rw-r--r--core/java/android/service/controls/Control.java20
-rw-r--r--core/java/android/service/voice/VoiceInteractionSession.java4
-rw-r--r--core/java/android/telephony/PhoneStateListener.java4
-rw-r--r--core/java/android/view/GestureDetector.java26
-rw-r--r--core/java/android/view/Surface.java7
-rw-r--r--core/java/android/view/SurfaceControl.java37
-rw-r--r--core/java/android/view/SurfaceView.java6
-rw-r--r--core/java/android/view/WindowlessWindowManager.java6
-rw-r--r--core/java/android/view/autofill/AutofillId.java5
-rw-r--r--core/java/android/webkit/WebChromeClient.java8
-rw-r--r--core/java/android/window/VirtualDisplayTaskEmbedder.java4
-rw-r--r--core/java/android/window/WindowContainerTransaction.java64
-rw-r--r--core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java31
-rw-r--r--core/java/com/android/internal/accessibility/util/AccessibilityUtils.java12
-rw-r--r--core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java18
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java97
-rw-r--r--core/java/com/android/internal/app/ChooserGridLayoutManager.java11
-rw-r--r--core/java/com/android/internal/app/ChooserListAdapter.java9
-rw-r--r--core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java11
-rw-r--r--core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl12
-rw-r--r--core/java/com/android/internal/app/IntentForwarderActivity.java2
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java87
-rw-r--r--core/java/com/android/internal/app/ResolverListAdapter.java1
-rw-r--r--core/java/com/android/internal/app/ResolverViewPager.java12
-rw-r--r--core/java/com/android/internal/app/chooser/MultiDisplayResolveInfo.java7
-rw-r--r--core/java/com/android/internal/logging/UiEventLogger.java24
-rw-r--r--core/java/com/android/internal/logging/UiEventLoggerImpl.java27
-rw-r--r--core/java/com/android/internal/logging/testing/UiEventLoggerFake.java30
-rw-r--r--core/java/com/android/internal/util/ScreenshotHelper.java49
-rw-r--r--core/java/com/android/internal/widget/ConversationLayout.java24
-rw-r--r--core/jni/android_media_AudioEffectDescriptor.cpp6
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp16
-rw-r--r--core/proto/android/server/connectivity/data_stall_event.proto1
-rw-r--r--core/proto/android/stats/mediametrics/mediametrics.proto5
-rw-r--r--core/res/AndroidManifest.xml3
-rw-r--r--core/res/res/layout/notification_material_action_list.xml3
-rw-r--r--core/res/res/values-el/strings.xml2
-rw-r--r--core/res/res/values-en-rXC/strings.xml6
-rw-r--r--core/res/res/values-gl/strings.xml2
-rw-r--r--core/res/res/values-km/strings.xml2
-rw-r--r--core/res/res/values-kn/strings.xml4
-rw-r--r--core/res/res/values-mr/strings.xml2
-rw-r--r--core/res/res/values-nl/strings.xml2
-rw-r--r--core/res/res/values-or/strings.xml4
-rw-r--r--core/res/res/values-television/themes_device_defaults.xml3
-rw-r--r--core/res/res/values/attrs_manifest.xml25
-rw-r--r--core/res/res/values/config.xml7
-rw-r--r--core/res/res/values/dimens.xml6
-rw-r--r--core/res/res/values/strings.xml6
-rw-r--r--core/res/res/values/symbols.xml7
-rw-r--r--core/res/res/values/themes_leanback.xml4
-rw-r--r--core/tests/PackageInstallerSessions/Android.bp42
-rw-r--r--core/tests/PackageInstallerSessions/AndroidManifest.xml29
-rw-r--r--core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt188
-rw-r--r--core/tests/coretests/src/android/content/ContextTest.java9
-rw-r--r--core/tests/coretests/src/android/view/autofill/AutofillIdTest.java26
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java48
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java21
-rw-r--r--core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java7
-rw-r--r--core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java10
-rw-r--r--core/tests/overlaytests/remount/Android.bp1
-rw-r--r--core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/RegenerateIdmapTest.java (renamed from core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/PackagedUpgradedTest.java)32
-rw-r--r--core/tests/overlaytests/remount/test-apps/Overlay/Android.bp6
-rw-r--r--core/tests/overlaytests/remount/test-apps/Overlay/res/values/values.xml1
-rw-r--r--core/tests/overlaytests/remount/test-apps/Target/Android.bp2
-rw-r--r--core/tests/overlaytests/remount/test-apps/Target/res/values/overlayable.xml3
-rw-r--r--core/tests/overlaytests/remount/test-apps/Target/res/values/values.xml2
-rw-r--r--core/tests/overlaytests/remount/test-apps/certs/Android.bp19
-rw-r--r--core/tests/overlaytests/remount/test-apps/certs/rro-remounted-test-a.pk8bin0 -> 1218 bytes
-rw-r--r--core/tests/overlaytests/remount/test-apps/certs/rro-remounted-test-a.x509.pem19
-rw-r--r--core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java6
-rw-r--r--data/etc/privapp-permissions-platform.xml5
-rw-r--r--data/keyboards/Vendor_045e_Product_0b12.kl59
-rw-r--r--libs/androidfw/include/androidfw/ResourceTypes.h5
-rw-r--r--libs/androidfw/tests/data/overlay/overlay.apkbin2988 -> 2992 bytes
-rw-r--r--libs/androidfw/tests/data/overlay/overlay.idmapbin1137 -> 1090 bytes
-rw-r--r--media/java/android/media/MediaCas.java23
-rw-r--r--media/java/android/media/MediaRoute2ProviderService.java173
-rw-r--r--media/java/android/media/MediaRouter2.java8
-rw-r--r--media/java/android/media/MediaRouter2Manager.java6
-rw-r--r--media/java/android/media/projection/MediaProjectionManager.java11
-rw-r--r--media/java/android/media/tv/TvRecordingClient.java2
-rw-r--r--media/java/android/media/tv/tuner/dvr/DvrPlayback.java28
-rw-r--r--media/java/android/media/tv/tuner/dvr/DvrRecorder.java28
-rw-r--r--media/jni/soundpool/Sound.cpp2
-rw-r--r--media/jni/soundpool/SoundDecoder.cpp3
-rw-r--r--media/jni/soundpool/Stream.cpp10
-rw-r--r--media/jni/soundpool/Stream.h2
-rw-r--r--media/jni/soundpool/StreamManager.cpp6
-rw-r--r--media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java3
-rw-r--r--packages/CarSystemUI/Android.bp2
-rw-r--r--packages/CarSystemUI/res/layout/car_left_navigation_bar.xml2
-rw-r--r--packages/CarSystemUI/res/layout/car_navigation_bar.xml10
-rw-r--r--packages/CarSystemUI/res/layout/car_navigation_button.xml4
-rw-r--r--packages/CarSystemUI/res/layout/car_right_navigation_bar.xml2
-rw-r--r--packages/CarSystemUI/res/layout/car_top_navigation_bar.xml3
-rw-r--r--packages/CarSystemUI/res/layout/headsup_container_bottom.xml9
-rw-r--r--packages/CarSystemUI/res/values/styles.xml2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java13
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java4
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java6
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/navigationbar/NavigationBarViewFactory.java7
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java3
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java7
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java56
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java13
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java22
-rw-r--r--packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java75
-rw-r--r--packages/SettingsLib/AdaptiveIcon/res/values/colors.xml4
-rw-r--r--packages/SettingsLib/AdaptiveIcon/res/values/dimens.xml2
-rw-r--r--packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java80
-rw-r--r--packages/SettingsLib/SearchWidget/res/values-fa/strings.xml2
-rw-r--r--packages/SettingsLib/SearchWidget/res/values-tl/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-bn/arrays.xml2
-rw-r--r--packages/SettingsLib/res/values-el/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-et/strings.xml2
-rw-r--r--packages/SettingsLib/res/values-in/arrays.xml2
-rw-r--r--packages/SettingsLib/res/values/dimens.xml3
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java30
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java43
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java13
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java13
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java7
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java6
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--packages/Shell/AndroidManifest.xml6
-rw-r--r--packages/Shell/res/layout/dialog_bugreport_info.xml107
-rw-r--r--packages/SystemUI/res-product/values-en-rXC/strings.xml9
-rw-r--r--packages/SystemUI/res/drawable/dismiss_circle_background.xml4
-rw-r--r--packages/SystemUI/res/drawable/floating_dismiss_gradient.xml24
-rw-r--r--packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml19
-rw-r--r--packages/SystemUI/res/drawable/ic_create_bubble.xml8
-rw-r--r--packages/SystemUI/res/drawable/ic_music_note.xml (renamed from packages/SystemUI/res/drawable/dismiss_target_x.xml)18
-rw-r--r--packages/SystemUI/res/drawable/ic_stop_bubble.xml6
-rw-r--r--packages/SystemUI/res/layout/controls_detail_dialog.xml1
-rw-r--r--packages/SystemUI/res/layout/notification_conversation_info.xml40
-rw-r--r--packages/SystemUI/res/layout/notification_info.xml41
-rw-r--r--packages/SystemUI/res/layout/partial_conversation_info.xml68
-rw-r--r--packages/SystemUI/res/layout/priority_onboarding_half_shell.xml176
-rw-r--r--packages/SystemUI/res/layout/quick_qs_status_icons.xml2
-rw-r--r--packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml2
-rw-r--r--packages/SystemUI/res/layout/quick_settings_footer.xml6
-rw-r--r--packages/SystemUI/res/layout/quick_settings_header_info.xml2
-rw-r--r--packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml1
-rw-r--r--packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml2
-rw-r--r--packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml9
-rw-r--r--packages/SystemUI/res/values-af/strings.xml6
-rw-r--r--packages/SystemUI/res/values-am/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml30
-rw-r--r--packages/SystemUI/res/values-as/strings.xml30
-rw-r--r--packages/SystemUI/res/values-az/strings.xml30
-rw-r--r--packages/SystemUI/res/values-b+sr+Latn/strings.xml6
-rw-r--r--packages/SystemUI/res/values-be/strings.xml6
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml30
-rw-r--r--packages/SystemUI/res/values-bn/strings.xml6
-rw-r--r--packages/SystemUI/res/values-bs/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml6
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml6
-rw-r--r--packages/SystemUI/res/values-da/strings.xml30
-rw-r--r--packages/SystemUI/res/values-de/strings.xml30
-rw-r--r--packages/SystemUI/res/values-el/strings.xml6
-rw-r--r--packages/SystemUI/res/values-en-rAU/strings.xml6
-rw-r--r--packages/SystemUI/res/values-en-rCA/strings.xml6
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml6
-rw-r--r--packages/SystemUI/res/values-en-rIN/strings.xml6
-rw-r--r--packages/SystemUI/res/values-en-rXC/strings.xml2
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml6
-rw-r--r--packages/SystemUI/res/values-es/strings.xml6
-rw-r--r--packages/SystemUI/res/values-et/strings.xml30
-rw-r--r--packages/SystemUI/res/values-eu/strings.xml6
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml6
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml30
-rw-r--r--packages/SystemUI/res/values-fr-rCA/strings.xml30
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml6
-rw-r--r--packages/SystemUI/res/values-gl/strings.xml6
-rw-r--r--packages/SystemUI/res/values-gu/strings.xml6
-rw-r--r--packages/SystemUI/res/values-hi/strings.xml30
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml6
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml6
-rw-r--r--packages/SystemUI/res/values-hy/strings.xml30
-rw-r--r--packages/SystemUI/res/values-in/strings.xml8
-rw-r--r--packages/SystemUI/res/values-is/strings.xml6
-rw-r--r--packages/SystemUI/res/values-it/strings.xml6
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml30
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml12
-rw-r--r--packages/SystemUI/res/values-ka/strings.xml30
-rw-r--r--packages/SystemUI/res/values-kk/strings.xml30
-rw-r--r--packages/SystemUI/res/values-km/strings.xml30
-rw-r--r--packages/SystemUI/res/values-kn/strings.xml8
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml30
-rw-r--r--packages/SystemUI/res/values-ky/strings.xml30
-rw-r--r--packages/SystemUI/res/values-lo/strings.xml6
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml30
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml6
-rw-r--r--packages/SystemUI/res/values-mk/strings.xml30
-rw-r--r--packages/SystemUI/res/values-ml/strings.xml6
-rw-r--r--packages/SystemUI/res/values-mn/strings.xml30
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ms/strings.xml30
-rw-r--r--packages/SystemUI/res/values-my/strings.xml10
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml30
-rw-r--r--packages/SystemUI/res/values-ne/strings.xml6
-rw-r--r--packages/SystemUI/res/values-night/styles.xml5
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml6
-rw-r--r--packages/SystemUI/res/values-or/strings.xml34
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml6
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml30
-rw-r--r--packages/SystemUI/res/values-pt-rBR/strings.xml6
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml6
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml6
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml30
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml6
-rw-r--r--packages/SystemUI/res/values-si/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml30
-rw-r--r--packages/SystemUI/res/values-sq/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sw/strings.xml30
-rw-r--r--packages/SystemUI/res/values-sw320dp/dimens.xml36
-rw-r--r--packages/SystemUI/res/values-sw372dp/dimens.xml1
-rw-r--r--packages/SystemUI/res/values-ta/strings.xml30
-rw-r--r--packages/SystemUI/res/values-te/strings.xml30
-rw-r--r--packages/SystemUI/res/values-th/strings.xml30
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml30
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml30
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml30
-rw-r--r--packages/SystemUI/res/values-ur/strings.xml30
-rw-r--r--packages/SystemUI/res/values-uz/strings.xml27
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml30
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml30
-rw-r--r--packages/SystemUI/res/values-zh-rHK/strings.xml30
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml30
-rw-r--r--packages/SystemUI/res/values-zu/strings.xml6
-rw-r--r--packages/SystemUI/res/values/dimens.xml29
-rw-r--r--packages/SystemUI/res/values/strings.xml17
-rw-r--r--packages/SystemUI/res/values/styles.xml5
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl12
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.aidl19
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java50
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java86
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java3
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java12
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java9
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt26
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java75
-rw-r--r--packages/SystemUI/src/com/android/systemui/Prefs.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/SystemUIService.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java75
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java40
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java138
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/StatusBehavior.kt56
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/controls/ui/Vibrations.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/dump/LogBufferFreezer.kt69
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java229
-rw-r--r--packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt79
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java264
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaData.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt192
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaHost.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt252
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt19
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaViewManager.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java (renamed from packages/SystemUI/src/com/android/systemui/qs/QSMediaBrowser.java)66
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt60
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java63
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java75
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java86
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/TileLayout.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java71
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java57
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java30
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java54
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java71
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java177
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java89
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java63
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt65
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt45
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/util/Utils.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferFreezerTest.kt116
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java129
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt38
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt49
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java32
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java33
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java73
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java126
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/AppOpsInfoTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java41
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java97
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeRepeatableExecutor.java34
-rw-r--r--packages/Tethering/Android.bp2
-rw-r--r--packages/Tethering/common/TetheringLib/Android.bp5
-rw-r--r--packages/Tethering/src/android/net/ip/IpServer.java7
-rw-r--r--packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java17
-rw-r--r--packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java4
-rw-r--r--packages/Tethering/tests/unit/Android.bp2
-rw-r--r--packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java23
-rw-r--r--samples/demo/haptic-assessment/Android.bp34
-rw-r--r--samples/demo/haptic-assessment/AndroidManifest.xml38
-rw-r--r--samples/demo/haptic-assessment/README.txt13
-rw-r--r--samples/demo/haptic-assessment/res/drawable-v24/ic_launcher_foreground.xml46
-rw-r--r--samples/demo/haptic-assessment/res/drawable/bluebar.pngbin0 -> 3883 bytes
-rw-r--r--samples/demo/haptic-assessment/res/drawable/cross_60x60.gifbin0 -> 1252 bytes
-rw-r--r--samples/demo/haptic-assessment/res/drawable/ic_launcher_background.xml185
-rw-r--r--samples/demo/haptic-assessment/res/layout/activity_main.xml93
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-anydpi-v26/ic_launcher.xml (renamed from packages/CarSystemUI/res/drawable/nav_button_background.xml)18
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-anydpi-v26/ic_launcher_round.xml20
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-hdpi/ic_launcher.pngbin0 -> 3593 bytes
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-hdpi/ic_launcher_round.pngbin0 -> 5339 bytes
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-mdpi/ic_launcher.pngbin0 -> 2636 bytes
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-mdpi/ic_launcher_round.pngbin0 -> 3388 bytes
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-xhdpi/ic_launcher.pngbin0 -> 4926 bytes
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-xhdpi/ic_launcher_round.pngbin0 -> 7472 bytes
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 7909 bytes
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-xxhdpi/ic_launcher_round.pngbin0 -> 11873 bytes
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-xxxhdpi/ic_launcher.pngbin0 -> 10652 bytes
-rw-r--r--samples/demo/haptic-assessment/res/mipmap-xxxhdpi/ic_launcher_round.pngbin0 -> 16570 bytes
-rw-r--r--samples/demo/haptic-assessment/res/values/colors.xml21
-rw-r--r--samples/demo/haptic-assessment/res/values/dimen.xml25
-rw-r--r--samples/demo/haptic-assessment/res/values/strings.xml24
-rw-r--r--samples/demo/haptic-assessment/res/values/styles.xml28
-rw-r--r--samples/demo/haptic-assessment/src/com/example/android/hapticassessment/MainActivity.kt71
-rw-r--r--services/Android.bp2
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java3
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java4
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java14
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerService.java2
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java1
-rw-r--r--services/core/Android.bp2
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java12
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java7
-rw-r--r--services/core/java/com/android/server/PackageWatchdog.java9
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java13
-rw-r--r--services/core/java/com/android/server/SystemServiceManager.java6
-rw-r--r--services/core/java/com/android/server/VibratorService.java60
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java24
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java26
-rwxr-xr-xservices/core/java/com/android/server/audio/AudioService.java64
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java63
-rw-r--r--services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java6
-rw-r--r--services/core/java/com/android/server/location/LocationManagerService.java83
-rw-r--r--services/core/java/com/android/server/location/UserInfoHelper.java213
-rw-r--r--services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java3
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java12
-rw-r--r--services/core/java/com/android/server/notification/BadgeExtractor.java5
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java20
-rw-r--r--services/core/java/com/android/server/notification/PreferencesHelper.java11
-rw-r--r--services/core/java/com/android/server/notification/SysUiStatsEvent.java68
-rw-r--r--services/core/java/com/android/server/om/IdmapManager.java9
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerService.java27
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerServiceImpl.java30
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerSettings.java76
-rw-r--r--services/core/java/com/android/server/pm/DataLoaderManagerService.java15
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java33
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java135
-rw-r--r--services/core/java/com/android/server/pm/PersistentPreferredActivity.java19
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java3
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java48
-rw-r--r--services/core/java/com/android/server/pm/UserManagerService.java4
-rw-r--r--services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java2
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerService.java20
-rw-r--r--services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java7
-rw-r--r--services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java44
-rw-r--r--services/core/java/com/android/server/stats/pull/StatsPullAtomService.java65
-rw-r--r--services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java60
-rw-r--r--services/core/java/com/android/server/uri/UriGrantsManagerService.java237
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java6
-rw-r--r--services/core/java/com/android/server/wm/ActivityStack.java66
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java7
-rw-r--r--services/core/java/com/android/server/wm/PinnedStackController.java21
-rw-r--r--services/core/java/com/android/server/wm/SurfaceAnimator.java19
-rw-r--r--services/core/java/com/android/server/wm/Task.java15
-rw-r--r--services/core/java/com/android/server/wm/TaskChangeNotificationController.java15
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotSurface.java1
-rw-r--r--services/core/java/com/android/server/wm/WallpaperController.java14
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java11
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java11
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java42
-rw-r--r--services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java3
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/location/UserInfoHelperTest.java145
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java26
-rw-r--r--services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java86
-rw-r--r--services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java135
-rw-r--r--services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java15
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt85
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt174
-rw-r--r--services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java74
-rw-r--r--services/tests/uiservicestests/Android.bp1
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java49
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java220
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java133
-rw-r--r--services/tests/wmtests/AndroidManifest.xml1
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityLeakTests.java184
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java22
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java56
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java5
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java40
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java15
-rw-r--r--telephony/java/android/telephony/SmsCbMessage.java8
-rw-r--r--tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java1
-rw-r--r--tests/RollbackTest/MultiUserRollbackTest.xml6
-rw-r--r--tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java9
-rw-r--r--tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java2
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java12
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java20
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java17
-rw-r--r--tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java5
-rw-r--r--tests/RollbackTest/StagedRollbackTest.xml6
-rw-r--r--tools/aapt2/Debug.cpp25
-rw-r--r--wifi/Android.bp6
-rw-r--r--wifi/java/android/net/wifi/WifiInfo.java9
591 files changed, 11410 insertions, 4669 deletions
diff --git a/Android.bp b/Android.bp
index 557c3209248d..632f49da5df9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -292,13 +292,13 @@ filegroup {
java_library {
name: "framework-updatable-stubs-module_libs_api",
static_libs: [
- "framework-media-stubs-module_libs_api",
- "framework-mediaprovider-stubs-module_libs_api",
- "framework-permission-stubs-module_libs_api",
- "framework-sdkextensions-stubs-module_libs_api",
- "framework-statsd-stubs-module_libs_api",
- "framework-tethering-stubs-module_libs_api",
- "framework-wifi-stubs-module_libs_api",
+ "framework-media.stubs.module_lib",
+ "framework-mediaprovider.stubs.module_lib",
+ "framework-permission.stubs.module_lib",
+ "framework-sdkextensions.stubs.module_lib",
+ "framework-statsd.stubs.module_lib",
+ "framework-tethering.stubs.module_lib",
+ "framework-wifi.stubs.module_lib",
],
sdk_version: "module_current",
visibility: [":__pkg__"],
diff --git a/StubLibraries.bp b/StubLibraries.bp
index c0197c4b2acf..ef4e202fdfe2 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -329,13 +329,13 @@ java_library_static {
srcs: [ ":api-stubs-docs-non-updatable" ],
static_libs: [
"conscrypt.module.public.api.stubs",
- "framework-media-stubs-publicapi",
- "framework-mediaprovider-stubs-publicapi",
- "framework-permission-stubs-publicapi",
- "framework-sdkextensions-stubs-publicapi",
- "framework-statsd-stubs-publicapi",
- "framework-tethering-stubs-publicapi",
- "framework-wifi-stubs-publicapi",
+ "framework-media.stubs",
+ "framework-mediaprovider.stubs",
+ "framework-permission.stubs",
+ "framework-sdkextensions.stubs",
+ "framework-statsd.stubs",
+ "framework-tethering.stubs",
+ "framework-wifi.stubs",
"private-stub-annotations-jar",
],
defaults: ["android_defaults_stubs_current"],
@@ -359,13 +359,13 @@ java_library_static {
srcs: [ ":system-api-stubs-docs-non-updatable" ],
static_libs: [
"conscrypt.module.public.api.stubs",
- "framework-media-stubs-systemapi",
- "framework-mediaprovider-stubs-systemapi",
- "framework-permission-stubs-systemapi",
- "framework-sdkextensions-stubs-systemapi",
- "framework-statsd-stubs-systemapi",
- "framework-tethering-stubs-systemapi",
- "framework-wifi-stubs-systemapi",
+ "framework-media.stubs.system",
+ "framework-mediaprovider.stubs.system",
+ "framework-permission.stubs.system",
+ "framework-sdkextensions.stubs.system",
+ "framework-statsd.stubs.system",
+ "framework-tethering.stubs.system",
+ "framework-wifi.stubs.system",
"private-stub-annotations-jar",
],
defaults: ["android_defaults_stubs_current"],
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index ac501a510e80..4417b681efc3 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -96,11 +96,6 @@ java_sdk_library {
":updatable-media-srcs",
],
- // TODO(b/155480189) - Remove naming_scheme once references have been resolved.
- // Temporary java_sdk_library component naming scheme to use to ease the transition from separate
- // modules to java_sdk_library.
- naming_scheme: "framework-modules",
-
libs: [
"framework_media_annotation",
],
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index 070b13b9e592..7cbb98e1bb4e 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -219,7 +219,8 @@ public final class MediaParser {
* duration is unknown.
*/
public long getDurationMicros() {
- return mExoPlayerSeekMap.getDurationUs();
+ long durationUs = mExoPlayerSeekMap.getDurationUs();
+ return durationUs != C.TIME_UNSET ? durationUs : UNKNOWN_DURATION;
}
/**
diff --git a/apex/permission/framework/Android.bp b/apex/permission/framework/Android.bp
index 732caecbd4a7..be553feb1d34 100644
--- a/apex/permission/framework/Android.bp
+++ b/apex/permission/framework/Android.bp
@@ -38,11 +38,6 @@ java_sdk_library {
":framework-permission-sources",
],
- // TODO(b/155480189) - Remove naming_scheme once references have been resolved.
- // Temporary java_sdk_library component naming scheme to use to ease the transition from separate
- // modules to java_sdk_library.
- naming_scheme: "framework-modules",
-
apex_available: [
"com.android.permission",
"test_com.android.permission",
diff --git a/apex/permission/service/java/com/android/permission/persistence/IoUtils.java b/apex/permission/service/java/com/android/permission/persistence/IoUtils.java
index 0ae44603516e..569a78c0ab41 100644
--- a/apex/permission/service/java/com/android/permission/persistence/IoUtils.java
+++ b/apex/permission/service/java/com/android/permission/persistence/IoUtils.java
@@ -20,6 +20,8 @@ import android.annotation.NonNull;
/**
* Utility class for IO.
+ *
+ * @hide
*/
public class IoUtils {
diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp
index 78496c4074f8..15a2f22e0fea 100644
--- a/apex/statsd/framework/Android.bp
+++ b/apex/statsd/framework/Android.bp
@@ -20,8 +20,8 @@ genrule {
name: "statslog-statsd-java-gen",
tools: ["stats-log-api-gen"],
cmd: "$(location stats-log-api-gen) --java $(out) --module statsd" +
- " --javaPackage com.android.internal.util --javaClass StatsdStatsLog",
- out: ["com/android/internal/util/StatsdStatsLog.java"],
+ " --javaPackage com.android.internal.statsd --javaClass StatsdStatsLog",
+ out: ["com/android/internal/statsd/StatsdStatsLog.java"],
}
java_library_static {
@@ -51,11 +51,6 @@ java_sdk_library {
defaults: ["framework-module-defaults"],
installable: true,
- // TODO(b/155480189) - Remove naming_scheme once references have been resolved.
- // Temporary java_sdk_library component naming scheme to use to ease the transition from separate
- // modules to java_sdk_library.
- naming_scheme: "framework-modules",
-
srcs: [
":framework-statsd-sources",
],
@@ -65,7 +60,7 @@ java_sdk_library {
"android.os",
"android.util",
// From :statslog-statsd-java-gen
- "com.android.internal.util",
+ "com.android.internal.statsd",
],
api_packages: [
diff --git a/apex/statsd/framework/java/android/app/StatsManager.java b/apex/statsd/framework/java/android/app/StatsManager.java
index d2c6c095b81f..a7d20572ca96 100644
--- a/apex/statsd/framework/java/android/app/StatsManager.java
+++ b/apex/statsd/framework/java/android/app/StatsManager.java
@@ -561,7 +561,15 @@ public final class StatsManager {
try {
resultReceiver.pullFinished(atomTag, success, parcels);
} catch (RemoteException e) {
- Log.w(TAG, "StatsPullResultReceiver failed for tag " + mAtomId);
+ Log.w(TAG, "StatsPullResultReceiver failed for tag " + mAtomId
+ + " due to TransactionTooLarge. Calling pullFinish with no data");
+ StatsEventParcel[] emptyData = new StatsEventParcel[0];
+ try {
+ resultReceiver.pullFinished(atomTag, /*success=*/false, emptyData);
+ } catch (RemoteException nestedException) {
+ Log.w(TAG, "StatsPullResultReceiver failed for tag " + mAtomId
+ + " with empty payload");
+ }
}
});
} finally {
diff --git a/apex/statsd/framework/java/android/util/StatsEvent.java b/apex/statsd/framework/java/android/util/StatsEvent.java
index 8bd36a516b12..8be5c63f31e3 100644
--- a/apex/statsd/framework/java/android/util/StatsEvent.java
+++ b/apex/statsd/framework/java/android/util/StatsEvent.java
@@ -26,6 +26,8 @@ import android.os.SystemClock;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import java.util.Arrays;
+
/**
* StatsEvent builds and stores the buffer sent over the statsd socket.
* This class defines and encapsulates the socket protocol.
@@ -224,7 +226,9 @@ public final class StatsEvent {
// Max payload size is 4 bytes less as 4 bytes are reserved for statsEventTag.
// See android_util_StatsLog.cpp.
- private static final int MAX_PAYLOAD_SIZE = LOGGER_ENTRY_MAX_PAYLOAD - 4;
+ private static final int MAX_PUSH_PAYLOAD_SIZE = LOGGER_ENTRY_MAX_PAYLOAD - 4;
+
+ private static final int MAX_PULL_PAYLOAD_SIZE = 50 * 1024; // 50 KB
private final int mAtomId;
private final byte[] mPayload;
@@ -619,6 +623,7 @@ public final class StatsEvent {
@NonNull
public Builder usePooledBuffer() {
mUsePooledBuffer = true;
+ mBuffer.setMaxSize(MAX_PUSH_PAYLOAD_SIZE, mPos);
return this;
}
@@ -694,8 +699,9 @@ public final class StatsEvent {
@GuardedBy("sLock")
private static Buffer sPool;
- private final byte[] mBytes = new byte[MAX_PAYLOAD_SIZE];
+ private byte[] mBytes = new byte[MAX_PUSH_PAYLOAD_SIZE];
private boolean mOverflow = false;
+ private int mMaxSize = MAX_PULL_PAYLOAD_SIZE;
@NonNull
private static Buffer obtain() {
@@ -717,15 +723,26 @@ public final class StatsEvent {
}
private void release() {
- synchronized (sLock) {
- if (null == sPool) {
- sPool = this;
+ // Recycle this Buffer if its size is MAX_PUSH_PAYLOAD_SIZE or under.
+ if (mBytes.length <= MAX_PUSH_PAYLOAD_SIZE) {
+ synchronized (sLock) {
+ if (null == sPool) {
+ sPool = this;
+ }
}
}
}
private void reset() {
mOverflow = false;
+ mMaxSize = MAX_PULL_PAYLOAD_SIZE;
+ }
+
+ private void setMaxSize(final int maxSize, final int numBytesWritten) {
+ mMaxSize = maxSize;
+ if (numBytesWritten > maxSize) {
+ mOverflow = true;
+ }
}
private boolean hasOverflowed() {
@@ -740,11 +757,28 @@ public final class StatsEvent {
* @return true if space is available, false otherwise.
**/
private boolean hasEnoughSpace(final int index, final int numBytes) {
- final boolean result = index + numBytes < MAX_PAYLOAD_SIZE;
- if (!result) {
+ final int totalBytesNeeded = index + numBytes;
+
+ if (totalBytesNeeded > mMaxSize) {
mOverflow = true;
+ return false;
}
- return result;
+
+ // Expand buffer if needed.
+ if (mBytes.length < mMaxSize && totalBytesNeeded > mBytes.length) {
+ int newSize = mBytes.length;
+ do {
+ newSize *= 2;
+ } while (newSize <= totalBytesNeeded);
+
+ if (newSize > mMaxSize) {
+ newSize = mMaxSize;
+ }
+
+ mBytes = Arrays.copyOf(mBytes, newSize);
+ }
+
+ return true;
}
/**
diff --git a/apex/statsd/framework/java/android/util/StatsLog.java b/apex/statsd/framework/java/android/util/StatsLog.java
index 4eeae57fe195..0a9f4ebabdf0 100644
--- a/apex/statsd/framework/java/android/util/StatsLog.java
+++ b/apex/statsd/framework/java/android/util/StatsLog.java
@@ -28,7 +28,7 @@ import android.os.IStatsd;
import android.os.Process;
import android.util.proto.ProtoOutputStream;
-import com.android.internal.util.StatsdStatsLog;
+import com.android.internal.statsd.StatsdStatsLog;
/**
* StatsLog provides an API for developers to send events to statsd. The events can be used to
diff --git a/apex/statsd/framework/test/src/android/util/StatsEventTest.java b/apex/statsd/framework/test/src/android/util/StatsEventTest.java
index 7b511553a26f..8d263699d9c8 100644
--- a/apex/statsd/framework/test/src/android/util/StatsEventTest.java
+++ b/apex/statsd/framework/test/src/android/util/StatsEventTest.java
@@ -33,6 +33,7 @@ import org.junit.runner.RunWith;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.util.Random;
/**
* Internal tests for {@link StatsEvent}.
@@ -644,6 +645,165 @@ public class StatsEventTest {
statsEvent.release();
}
+ @Test
+ public void testLargePulledEvent() {
+ final int expectedAtomId = 10_020;
+ byte[] field1 = new byte[10 * 1024];
+ new Random().nextBytes(field1);
+
+ final long minTimestamp = SystemClock.elapsedRealtimeNanos();
+ final StatsEvent statsEvent =
+ StatsEvent.newBuilder().setAtomId(expectedAtomId).writeByteArray(field1).build();
+ final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
+
+ assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId);
+
+ final ByteBuffer buffer =
+ ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN);
+
+ assertWithMessage("Root element in buffer is not TYPE_OBJECT")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_OBJECT);
+
+ assertWithMessage("Incorrect number of elements in root object")
+ .that(buffer.get())
+ .isEqualTo(3);
+
+ assertWithMessage("First element is not timestamp")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_LONG);
+
+ assertWithMessage("Incorrect timestamp")
+ .that(buffer.getLong())
+ .isIn(Range.closed(minTimestamp, maxTimestamp));
+
+ assertWithMessage("Second element is not atom id")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_INT);
+
+ assertWithMessage("Incorrect atom id").that(buffer.getInt()).isEqualTo(expectedAtomId);
+
+ assertWithMessage("Third element is not byte array")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_BYTE_ARRAY);
+
+ final byte[] field1Actual = getByteArrayFromByteBuffer(buffer);
+ assertWithMessage("Incorrect field 1").that(field1Actual).isEqualTo(field1);
+
+ assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position());
+
+ statsEvent.release();
+ }
+
+ @Test
+ public void testPulledEventOverflow() {
+ final int expectedAtomId = 10_020;
+ byte[] field1 = new byte[50 * 1024];
+ new Random().nextBytes(field1);
+
+ final long minTimestamp = SystemClock.elapsedRealtimeNanos();
+ final StatsEvent statsEvent =
+ StatsEvent.newBuilder().setAtomId(expectedAtomId).writeByteArray(field1).build();
+ final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
+
+ assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId);
+
+ final ByteBuffer buffer =
+ ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN);
+
+ assertWithMessage("Root element in buffer is not TYPE_OBJECT")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_OBJECT);
+
+ assertWithMessage("Incorrect number of elements in root object")
+ .that(buffer.get())
+ .isEqualTo(3);
+
+ assertWithMessage("First element is not timestamp")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_LONG);
+
+ assertWithMessage("Incorrect timestamp")
+ .that(buffer.getLong())
+ .isIn(Range.closed(minTimestamp, maxTimestamp));
+
+ assertWithMessage("Second element is not atom id")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_INT);
+
+ assertWithMessage("Incorrect atom id").that(buffer.getInt()).isEqualTo(expectedAtomId);
+
+ assertWithMessage("Third element is not errors type")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_ERRORS);
+
+ final int errorMask = buffer.getInt();
+
+ assertWithMessage("ERROR_OVERFLOW should be the only error in the error mask")
+ .that(errorMask)
+ .isEqualTo(StatsEvent.ERROR_OVERFLOW);
+
+ assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position());
+
+ statsEvent.release();
+ }
+
+ @Test
+ public void testPushedEventOverflow() {
+ final int expectedAtomId = 10_020;
+ byte[] field1 = new byte[10 * 1024];
+ new Random().nextBytes(field1);
+
+ final long minTimestamp = SystemClock.elapsedRealtimeNanos();
+ final StatsEvent statsEvent = StatsEvent.newBuilder()
+ .setAtomId(expectedAtomId)
+ .writeByteArray(field1)
+ .usePooledBuffer()
+ .build();
+ final long maxTimestamp = SystemClock.elapsedRealtimeNanos();
+
+ assertThat(statsEvent.getAtomId()).isEqualTo(expectedAtomId);
+
+ final ByteBuffer buffer =
+ ByteBuffer.wrap(statsEvent.getBytes()).order(ByteOrder.LITTLE_ENDIAN);
+
+ assertWithMessage("Root element in buffer is not TYPE_OBJECT")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_OBJECT);
+
+ assertWithMessage("Incorrect number of elements in root object")
+ .that(buffer.get())
+ .isEqualTo(3);
+
+ assertWithMessage("First element is not timestamp")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_LONG);
+
+ assertWithMessage("Incorrect timestamp")
+ .that(buffer.getLong())
+ .isIn(Range.closed(minTimestamp, maxTimestamp));
+
+ assertWithMessage("Second element is not atom id")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_INT);
+
+ assertWithMessage("Incorrect atom id").that(buffer.getInt()).isEqualTo(expectedAtomId);
+
+ assertWithMessage("Third element is not errors type")
+ .that(buffer.get())
+ .isEqualTo(StatsEvent.TYPE_ERRORS);
+
+ final int errorMask = buffer.getInt();
+
+ assertWithMessage("ERROR_OVERFLOW should be the only error in the error mask")
+ .that(errorMask)
+ .isEqualTo(StatsEvent.ERROR_OVERFLOW);
+
+ assertThat(statsEvent.getNumBytes()).isEqualTo(buffer.position());
+
+ statsEvent.release();
+ }
+
private static byte[] getByteArrayFromByteBuffer(final ByteBuffer buffer) {
final int numBytes = buffer.getInt();
byte[] bytes = new byte[numBytes];
diff --git a/api/test-current.txt b/api/test-current.txt
index ed4c9b13dacd..66b5015902f0 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1298,6 +1298,130 @@ package android.hardware.display {
}
+package android.hardware.hdmi {
+
+ public final class HdmiControlManager {
+ method @Nullable public android.hardware.hdmi.HdmiSwitchClient getSwitchClient();
+ method @RequiresPermission("android.permission.HDMI_CEC") public void setStandbyMode(boolean);
+ field public static final String ACTION_OSD_MESSAGE = "android.hardware.hdmi.action.OSD_MESSAGE";
+ field public static final int AVR_VOLUME_MUTED = 101; // 0x65
+ field public static final int CLEAR_TIMER_STATUS_CEC_DISABLE = 162; // 0xa2
+ field public static final int CLEAR_TIMER_STATUS_CHECK_RECORDER_CONNECTION = 160; // 0xa0
+ field public static final int CLEAR_TIMER_STATUS_FAIL_TO_CLEAR_SELECTED_SOURCE = 161; // 0xa1
+ field public static final int CLEAR_TIMER_STATUS_TIMER_CLEARED = 128; // 0x80
+ field public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_NO_INFO_AVAILABLE = 2; // 0x2
+ field public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_NO_MATCHING = 1; // 0x1
+ field public static final int CLEAR_TIMER_STATUS_TIMER_NOT_CLEARED_RECORDING = 0; // 0x0
+ field public static final int CONTROL_STATE_CHANGED_REASON_SETTING = 1; // 0x1
+ field public static final int CONTROL_STATE_CHANGED_REASON_STANDBY = 3; // 0x3
+ field public static final int CONTROL_STATE_CHANGED_REASON_START = 0; // 0x0
+ field public static final int CONTROL_STATE_CHANGED_REASON_WAKEUP = 2; // 0x2
+ field public static final int DEVICE_EVENT_ADD_DEVICE = 1; // 0x1
+ field public static final int DEVICE_EVENT_REMOVE_DEVICE = 2; // 0x2
+ field public static final int DEVICE_EVENT_UPDATE_DEVICE = 3; // 0x3
+ field public static final String EXTRA_MESSAGE_EXTRA_PARAM1 = "android.hardware.hdmi.extra.MESSAGE_EXTRA_PARAM1";
+ field public static final String EXTRA_MESSAGE_ID = "android.hardware.hdmi.extra.MESSAGE_ID";
+ field public static final int ONE_TOUCH_RECORD_ALREADY_RECORDING = 18; // 0x12
+ field public static final int ONE_TOUCH_RECORD_CEC_DISABLED = 51; // 0x33
+ field public static final int ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION = 49; // 0x31
+ field public static final int ONE_TOUCH_RECORD_DISALLOW_TO_COPY = 13; // 0xd
+ field public static final int ONE_TOUCH_RECORD_DISALLOW_TO_FUTHER_COPIES = 14; // 0xe
+ field public static final int ONE_TOUCH_RECORD_FAIL_TO_RECORD_DISPLAYED_SCREEN = 50; // 0x32
+ field public static final int ONE_TOUCH_RECORD_INVALID_EXTERNAL_PHYSICAL_ADDRESS = 10; // 0xa
+ field public static final int ONE_TOUCH_RECORD_INVALID_EXTERNAL_PLUG_NUMBER = 9; // 0x9
+ field public static final int ONE_TOUCH_RECORD_MEDIA_PROBLEM = 21; // 0x15
+ field public static final int ONE_TOUCH_RECORD_MEDIA_PROTECTED = 19; // 0x13
+ field public static final int ONE_TOUCH_RECORD_NOT_ENOUGH_SPACE = 22; // 0x16
+ field public static final int ONE_TOUCH_RECORD_NO_MEDIA = 16; // 0x10
+ field public static final int ONE_TOUCH_RECORD_NO_OR_INSUFFICIENT_CA_ENTITLEMENTS = 12; // 0xc
+ field public static final int ONE_TOUCH_RECORD_NO_SOURCE_SIGNAL = 20; // 0x14
+ field public static final int ONE_TOUCH_RECORD_OTHER_REASON = 31; // 0x1f
+ field public static final int ONE_TOUCH_RECORD_PARENT_LOCK_ON = 23; // 0x17
+ field public static final int ONE_TOUCH_RECORD_PLAYING = 17; // 0x11
+ field public static final int ONE_TOUCH_RECORD_PREVIOUS_RECORDING_IN_PROGRESS = 48; // 0x30
+ field public static final int ONE_TOUCH_RECORD_RECORDING_ALREADY_TERMINATED = 27; // 0x1b
+ field public static final int ONE_TOUCH_RECORD_RECORDING_ANALOGUE_SERVICE = 3; // 0x3
+ field public static final int ONE_TOUCH_RECORD_RECORDING_CURRENTLY_SELECTED_SOURCE = 1; // 0x1
+ field public static final int ONE_TOUCH_RECORD_RECORDING_DIGITAL_SERVICE = 2; // 0x2
+ field public static final int ONE_TOUCH_RECORD_RECORDING_EXTERNAL_INPUT = 4; // 0x4
+ field public static final int ONE_TOUCH_RECORD_RECORDING_TERMINATED_NORMALLY = 26; // 0x1a
+ field public static final int ONE_TOUCH_RECORD_UNABLE_ANALOGUE_SERVICE = 6; // 0x6
+ field public static final int ONE_TOUCH_RECORD_UNABLE_DIGITAL_SERVICE = 5; // 0x5
+ field public static final int ONE_TOUCH_RECORD_UNABLE_SELECTED_SERVICE = 7; // 0x7
+ field public static final int ONE_TOUCH_RECORD_UNSUPPORTED_CA = 11; // 0xb
+ field public static final int OSD_MESSAGE_ARC_CONNECTED_INVALID_PORT = 1; // 0x1
+ field public static final int OSD_MESSAGE_AVR_VOLUME_CHANGED = 2; // 0x2
+ field public static final int POWER_STATUS_ON = 0; // 0x0
+ field public static final int POWER_STATUS_STANDBY = 1; // 0x1
+ field public static final int POWER_STATUS_TRANSIENT_TO_ON = 2; // 0x2
+ field public static final int POWER_STATUS_TRANSIENT_TO_STANDBY = 3; // 0x3
+ field public static final int POWER_STATUS_UNKNOWN = -1; // 0xffffffff
+ field @Deprecated public static final int RESULT_ALREADY_IN_PROGRESS = 4; // 0x4
+ field public static final int RESULT_COMMUNICATION_FAILED = 7; // 0x7
+ field public static final int RESULT_EXCEPTION = 5; // 0x5
+ field public static final int RESULT_INCORRECT_MODE = 6; // 0x6
+ field public static final int RESULT_SOURCE_NOT_AVAILABLE = 2; // 0x2
+ field public static final int RESULT_SUCCESS = 0; // 0x0
+ field public static final int RESULT_TARGET_NOT_AVAILABLE = 3; // 0x3
+ field public static final int RESULT_TIMEOUT = 1; // 0x1
+ field public static final int TIMER_RECORDING_RESULT_EXTRA_CEC_DISABLED = 3; // 0x3
+ field public static final int TIMER_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION = 1; // 0x1
+ field public static final int TIMER_RECORDING_RESULT_EXTRA_FAIL_TO_RECORD_SELECTED_SOURCE = 2; // 0x2
+ field public static final int TIMER_RECORDING_RESULT_EXTRA_NO_ERROR = 0; // 0x0
+ field public static final int TIMER_RECORDING_TYPE_ANALOGUE = 2; // 0x2
+ field public static final int TIMER_RECORDING_TYPE_DIGITAL = 1; // 0x1
+ field public static final int TIMER_RECORDING_TYPE_EXTERNAL = 3; // 0x3
+ field public static final int TIMER_STATUS_MEDIA_INFO_NOT_PRESENT = 2; // 0x2
+ field public static final int TIMER_STATUS_MEDIA_INFO_PRESENT_NOT_PROTECTED = 0; // 0x0
+ field public static final int TIMER_STATUS_MEDIA_INFO_PRESENT_PROTECTED = 1; // 0x1
+ field public static final int TIMER_STATUS_NOT_PROGRAMMED_CA_NOT_SUPPORTED = 6; // 0x6
+ field public static final int TIMER_STATUS_NOT_PROGRAMMED_CLOCK_FAILURE = 10; // 0xa
+ field public static final int TIMER_STATUS_NOT_PROGRAMMED_DATE_OUT_OF_RANGE = 2; // 0x2
+ field public static final int TIMER_STATUS_NOT_PROGRAMMED_DUPLICATED = 14; // 0xe
+ field public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_EXTERNAL_PHYSICAL_NUMBER = 5; // 0x5
+ field public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_EXTERNAL_PLUG_NUMBER = 4; // 0x4
+ field public static final int TIMER_STATUS_NOT_PROGRAMMED_INVALID_SEQUENCE = 3; // 0x3
+ field public static final int TIMER_STATUS_NOT_PROGRAMMED_NO_CA_ENTITLEMENTS = 7; // 0x7
+ field public static final int TIMER_STATUS_NOT_PROGRAMMED_NO_FREE_TIME = 1; // 0x1
+ field public static final int TIMER_STATUS_NOT_PROGRAMMED_PARENTAL_LOCK_ON = 9; // 0x9
+ field public static final int TIMER_STATUS_NOT_PROGRAMMED_UNSUPPORTED_RESOLUTION = 8; // 0x8
+ field public static final int TIMER_STATUS_PROGRAMMED_INFO_ENOUGH_SPACE = 8; // 0x8
+ field public static final int TIMER_STATUS_PROGRAMMED_INFO_MIGHT_NOT_ENOUGH_SPACE = 11; // 0xb
+ field public static final int TIMER_STATUS_PROGRAMMED_INFO_NOT_ENOUGH_SPACE = 9; // 0x9
+ field public static final int TIMER_STATUS_PROGRAMMED_INFO_NO_MEDIA_INFO = 10; // 0xa
+ }
+
+ public final class HdmiControlServiceWrapper {
+ ctor public HdmiControlServiceWrapper();
+ method @NonNull public android.hardware.hdmi.HdmiControlManager createHdmiControlManager();
+ method @BinderThread public void setDeviceTypes(@NonNull int[]);
+ method @BinderThread public void setPortInfo(@NonNull java.util.List<android.hardware.hdmi.HdmiPortInfo>);
+ field public static final int DEVICE_PURE_CEC_SWITCH = 6; // 0x6
+ }
+
+ public final class HdmiPortInfo implements android.os.Parcelable {
+ ctor public HdmiPortInfo(int, int, int, boolean, boolean, boolean);
+ method public int describeContents();
+ method public int getAddress();
+ method public int getId();
+ method public int getType();
+ method public boolean isArcSupported();
+ method public boolean isCecSupported();
+ method public boolean isMhlSupported();
+ field @NonNull public static final android.os.Parcelable.Creator<android.hardware.hdmi.HdmiPortInfo> CREATOR;
+ field public static final int PORT_INPUT = 0; // 0x0
+ field public static final int PORT_OUTPUT = 1; // 0x1
+ }
+
+ public class HdmiSwitchClient {
+ method public int getDeviceType();
+ method @NonNull public java.util.List<android.hardware.hdmi.HdmiPortInfo> getPortInfo();
+ method public void sendKeyEvent(int, boolean);
+ method public void sendVendorCommand(int, byte[], boolean);
+ }
+
+}
+
package android.hardware.lights {
public final class Light implements android.os.Parcelable {
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 3bcabe56f89e..bb2de17b42f3 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -349,6 +349,25 @@ EGLConfig BootAnimation::getEglConfig(const EGLDisplay& display) {
return config;
}
+ui::Size BootAnimation::limitSurfaceSize(int width, int height) const {
+ ui::Size limited(width, height);
+ bool wasLimited = false;
+ const float aspectRatio = float(width) / float(height);
+ if (mMaxWidth != 0 && width > mMaxWidth) {
+ limited.height = mMaxWidth / aspectRatio;
+ limited.width = mMaxWidth;
+ wasLimited = true;
+ }
+ if (mMaxHeight != 0 && limited.height > mMaxHeight) {
+ limited.height = mMaxHeight;
+ limited.width = mMaxHeight * aspectRatio;
+ wasLimited = true;
+ }
+ SLOGV_IF(wasLimited, "Surface size has been limited to [%dx%d] from [%dx%d]",
+ limited.width, limited.height, width, height);
+ return limited;
+}
+
status_t BootAnimation::readyToRun() {
mAssets.addDefaultAssets();
@@ -362,8 +381,10 @@ status_t BootAnimation::readyToRun() {
if (error != NO_ERROR)
return error;
- const ui::Size& resolution = displayConfig.resolution;
-
+ mMaxWidth = android::base::GetIntProperty("ro.surface_flinger.max_graphics_width", 0);
+ mMaxHeight = android::base::GetIntProperty("ro.surface_flinger.max_graphics_height", 0);
+ ui::Size resolution = displayConfig.resolution;
+ resolution = limitSurfaceSize(resolution.width, resolution.height);
// create the native surface
sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
resolution.getWidth(), resolution.getHeight(), PIXEL_FORMAT_RGB_565);
@@ -459,8 +480,9 @@ void BootAnimation::resizeSurface(int newWidth, int newHeight) {
eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
eglDestroySurface(mDisplay, mSurface);
- mWidth = newWidth;
- mHeight = newHeight;
+ const auto limitedSize = limitSurfaceSize(newWidth, newHeight);
+ mWidth = limitedSize.width;
+ mHeight = limitedSize.height;
SurfaceComposerClient::Transaction t;
t.setSize(mFlingerSurfaceControl, mWidth, mHeight);
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 36cd91bdee0d..6ba7fd450fbb 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -170,6 +170,7 @@ private:
bool findBootAnimationFileInternal(const std::vector<std::string>& files);
bool preloadAnimation();
EGLConfig getEglConfig(const EGLDisplay&);
+ ui::Size limitSurfaceSize(int width, int height) const;
void resizeSurface(int newWidth, int newHeight);
void checkExit();
@@ -181,6 +182,8 @@ private:
Texture mAndroid[2];
int mWidth;
int mHeight;
+ int mMaxWidth = 0;
+ int mMaxHeight = 0;
int mCurrentInset;
int mTargetInset;
bool mUseNpotTextures = false;
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index ef5c4cec9166..fb5830506925 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -168,13 +168,13 @@ cc_binary {
],
host_supported: true,
srcs: [
+ "idmap2/CommandUtils.cpp",
"idmap2/Create.cpp",
"idmap2/CreateMultiple.cpp",
"idmap2/Dump.cpp",
"idmap2/Lookup.cpp",
"idmap2/Main.cpp",
"idmap2/Scan.cpp",
- "idmap2/Verify.cpp",
],
target: {
android: {
diff --git a/cmds/idmap2/idmap2/Verify.cpp b/cmds/idmap2/idmap2/CommandUtils.cpp
index 9cb67b33e6cf..e058cd6e7e70 100644
--- a/cmds/idmap2/idmap2/Verify.cpp
+++ b/cmds/idmap2/idmap2/CommandUtils.cpp
@@ -19,30 +19,19 @@
#include <string>
#include <vector>
-#include "idmap2/CommandLineOptions.h"
#include "idmap2/Idmap.h"
#include "idmap2/Result.h"
#include "idmap2/SysTrace.h"
-using android::idmap2::CommandLineOptions;
using android::idmap2::Error;
using android::idmap2::IdmapHeader;
using android::idmap2::Result;
using android::idmap2::Unit;
-Result<Unit> Verify(const std::vector<std::string>& args) {
- SYSTRACE << "Verify " << args;
- std::string idmap_path;
-
- const CommandLineOptions opts =
- CommandLineOptions("idmap2 verify")
- .MandatoryOption("--idmap-path", "input: path to idmap file to verify", &idmap_path);
-
- const auto opts_ok = opts.Parse(args);
- if (!opts_ok) {
- return opts_ok.GetError();
- }
-
+Result<Unit> Verify(const std::string& idmap_path, const std::string& target_path,
+ const std::string& overlay_path, uint32_t fulfilled_policies,
+ bool enforce_overlayable) {
+ SYSTRACE << "Verify " << idmap_path;
std::ifstream fin(idmap_path);
const std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(fin);
fin.close();
@@ -50,7 +39,8 @@ Result<Unit> Verify(const std::vector<std::string>& args) {
return Error("failed to parse idmap header");
}
- const auto header_ok = header->IsUpToDate();
+ const auto header_ok = header->IsUpToDate(target_path.c_str(), overlay_path.c_str(),
+ fulfilled_policies, enforce_overlayable);
if (!header_ok) {
return Error(header_ok.GetError(), "idmap not up to date");
}
diff --git a/cmds/idmap2/idmap2/CommandUtils.h b/cmds/idmap2/idmap2/CommandUtils.h
new file mode 100644
index 000000000000..99605de30988
--- /dev/null
+++ b/cmds/idmap2/idmap2/CommandUtils.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IDMAP2_IDMAP2_COMMAND_UTILS_H_
+#define IDMAP2_IDMAP2_COMMAND_UTILS_H_
+
+#include "idmap2/Result.h"
+
+android::idmap2::Result<android::idmap2::Unit> Verify(const std::string& idmap_path,
+ const std::string& target_path,
+ const std::string& overlay_path,
+ uint32_t fulfilled_policies,
+ bool enforce_overlayable);
+
+#endif // IDMAP2_IDMAP2_COMMAND_UTILS_H_
diff --git a/cmds/idmap2/idmap2/Commands.h b/cmds/idmap2/idmap2/Commands.h
index e626738a2895..69eea8d262d2 100644
--- a/cmds/idmap2/idmap2/Commands.h
+++ b/cmds/idmap2/idmap2/Commands.h
@@ -27,6 +27,5 @@ android::idmap2::Result<android::idmap2::Unit> CreateMultiple(const std::vector<
android::idmap2::Result<android::idmap2::Unit> Dump(const std::vector<std::string>& args);
android::idmap2::Result<android::idmap2::Unit> Lookup(const std::vector<std::string>& args);
android::idmap2::Result<android::idmap2::Unit> Scan(const std::vector<std::string>& args);
-android::idmap2::Result<android::idmap2::Unit> Verify(const std::vector<std::string>& args);
#endif // IDMAP2_IDMAP2_COMMANDS_H_
diff --git a/cmds/idmap2/idmap2/CreateMultiple.cpp b/cmds/idmap2/idmap2/CreateMultiple.cpp
index 4b70acc2969c..abdfaf4dccab 100644
--- a/cmds/idmap2/idmap2/CreateMultiple.cpp
+++ b/cmds/idmap2/idmap2/CreateMultiple.cpp
@@ -26,6 +26,7 @@
#include "android-base/stringprintf.h"
#include "idmap2/BinaryStreamVisitor.h"
#include "idmap2/CommandLineOptions.h"
+#include "idmap2/CommandUtils.h"
#include "idmap2/FileUtils.h"
#include "idmap2/Idmap.h"
#include "idmap2/Policies.h"
@@ -103,7 +104,8 @@ Result<Unit> CreateMultiple(const std::vector<std::string>& args) {
continue;
}
- if (!Verify(std::vector<std::string>({"--idmap-path", idmap_path}))) {
+ if (!Verify(idmap_path, target_apk_path, overlay_apk_path, fulfilled_policies,
+ !ignore_overlayable)) {
const std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
if (!overlay_apk) {
LOG(WARNING) << "failed to load apk " << overlay_apk_path.c_str();
diff --git a/cmds/idmap2/idmap2/Main.cpp b/cmds/idmap2/idmap2/Main.cpp
index a07e793d9f47..fb093f0f22a4 100644
--- a/cmds/idmap2/idmap2/Main.cpp
+++ b/cmds/idmap2/idmap2/Main.cpp
@@ -53,9 +53,8 @@ void PrintUsage(const NameToFunctionMap& commands, std::ostream& out) {
int main(int argc, char** argv) {
SYSTRACE << "main";
const NameToFunctionMap commands = {
- {"create", Create}, {"create-multiple", CreateMultiple},
- {"dump", Dump}, {"lookup", Lookup},
- {"scan", Scan}, {"verify", Verify},
+ {"create", Create}, {"create-multiple", CreateMultiple}, {"dump", Dump}, {"lookup", Lookup},
+ {"scan", Scan},
};
if (argc <= 1) {
PrintUsage(commands, std::cerr);
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index da0453216f03..36250450cc74 100644
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ b/cmds/idmap2/idmap2/Scan.cpp
@@ -27,8 +27,11 @@
#include "Commands.h"
#include "android-base/properties.h"
#include "idmap2/CommandLineOptions.h"
+#include "idmap2/CommandUtils.h"
#include "idmap2/FileUtils.h"
#include "idmap2/Idmap.h"
+#include "idmap2/Policies.h"
+#include "idmap2/PolicyUtils.h"
#include "idmap2/ResourceUtils.h"
#include "idmap2/Result.h"
#include "idmap2/SysTrace.h"
@@ -48,6 +51,7 @@ using android::idmap2::policy::kPolicyVendor;
using android::idmap2::utils::ExtractOverlayManifestInfo;
using android::idmap2::utils::FindFiles;
using android::idmap2::utils::OverlayManifestInfo;
+using android::idmap2::utils::PoliciesToBitmaskResult;
using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
@@ -215,7 +219,15 @@ Result<Unit> Scan(const std::vector<std::string>& args) {
std::stringstream stream;
for (const auto& overlay : interesting_apks) {
- if (!Verify(std::vector<std::string>({"--idmap-path", overlay.idmap_path}))) {
+ const auto policy_bitmask = PoliciesToBitmaskResult(overlay.policies);
+ if (!policy_bitmask) {
+ LOG(WARNING) << "failed to create idmap for overlay apk path \"" << overlay.apk_path
+ << "\": " << policy_bitmask.GetErrorMessage();
+ continue;
+ }
+
+ if (!Verify(overlay.idmap_path, target_apk_path, overlay.apk_path, *policy_bitmask,
+ !overlay.ignore_overlayable)) {
std::vector<std::string> create_args = {"--target-apk-path", target_apk_path,
"--overlay-apk-path", overlay.apk_path,
"--idmap-path", overlay.idmap_path};
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index a93184ff4787..908d96612269 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -33,16 +33,19 @@
#include "idmap2/BinaryStreamVisitor.h"
#include "idmap2/FileUtils.h"
#include "idmap2/Idmap.h"
+#include "idmap2/Result.h"
#include "idmap2/SysTrace.h"
#include "idmap2/ZipFile.h"
#include "utils/String8.h"
using android::IPCThreadState;
+using android::base::StringPrintf;
using android::binder::Status;
using android::idmap2::BinaryStreamVisitor;
using android::idmap2::GetPackageCrc;
using android::idmap2::Idmap;
using android::idmap2::IdmapHeader;
+using android::idmap2::ZipFile;
using android::idmap2::utils::kIdmapCacheDir;
using android::idmap2::utils::kIdmapFilePermissionMask;
using android::idmap2::utils::UidHasWriteAccessToPath;
@@ -66,6 +69,21 @@ PolicyBitmask ConvertAidlArgToPolicyBitmask(int32_t arg) {
return static_cast<PolicyBitmask>(arg);
}
+Status GetCrc(const std::string& apk_path, uint32_t* out_crc) {
+ const auto overlay_zip = ZipFile::Open(apk_path);
+ if (!overlay_zip) {
+ return error(StringPrintf("failed to open apk %s", apk_path.c_str()));
+ }
+
+ const auto crc = GetPackageCrc(*overlay_zip);
+ if (!crc) {
+ return error(crc.GetErrorMessage());
+ }
+
+ *out_crc = *crc;
+ return ok();
+}
+
} // namespace
namespace android::os {
@@ -98,10 +116,9 @@ Status Idmap2Service::removeIdmap(const std::string& overlay_apk_path,
}
Status Idmap2Service::verifyIdmap(const std::string& target_apk_path,
- const std::string& overlay_apk_path,
- int32_t fulfilled_policies ATTRIBUTE_UNUSED,
- bool enforce_overlayable ATTRIBUTE_UNUSED,
- int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) {
+ const std::string& overlay_apk_path, int32_t fulfilled_policies,
+ bool enforce_overlayable, int32_t user_id ATTRIBUTE_UNUSED,
+ bool* _aidl_return) {
SYSTRACE << "Idmap2Service::verifyIdmap " << overlay_apk_path;
assert(_aidl_return);
const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
@@ -113,34 +130,38 @@ Status Idmap2Service::verifyIdmap(const std::string& target_apk_path,
return error("failed to parse idmap header");
}
- if (strcmp(header->GetTargetPath().data(), target_apk_path.data()) != 0) {
- *_aidl_return = false;
- return ok();
- }
-
- if (target_apk_path != kFrameworkPath) {
- *_aidl_return = (bool) header->IsUpToDate();
+ uint32_t target_crc;
+ if (target_apk_path == kFrameworkPath && android_crc_) {
+ target_crc = *android_crc_;
} else {
- if (!android_crc_) {
- // Loading the framework zip can take several milliseconds. Cache the crc of the framework
- // resource APK to reduce repeated work during boot.
- const auto target_zip = idmap2::ZipFile::Open(target_apk_path);
- if (!target_zip) {
- return error(base::StringPrintf("failed to open target %s", target_apk_path.c_str()));
- }
-
- const auto target_crc = GetPackageCrc(*target_zip);
- if (!target_crc) {
- return error(target_crc.GetErrorMessage());
- }
-
- android_crc_ = *target_crc;
+ auto target_crc_status = GetCrc(target_apk_path, &target_crc);
+ if (!target_crc_status.isOk()) {
+ *_aidl_return = false;
+ return target_crc_status;
+ }
+
+ // Loading the framework zip can take several milliseconds. Cache the crc of the framework
+ // resource APK to reduce repeated work during boot.
+ if (target_apk_path == kFrameworkPath) {
+ android_crc_ = target_crc;
}
+ }
- *_aidl_return = (bool) header->IsUpToDate(android_crc_.value());
+ uint32_t overlay_crc;
+ auto overlay_crc_status = GetCrc(overlay_apk_path, &overlay_crc);
+ if (!overlay_crc_status.isOk()) {
+ *_aidl_return = false;
+ return overlay_crc_status;
+ }
+
+ auto up_to_date =
+ header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(), target_crc, overlay_crc,
+ fulfilled_policies, enforce_overlayable);
+ if (!up_to_date) {
+ *_aidl_return = false;
+ return error(up_to_date.GetErrorMessage());
}
- // TODO(b/119328308): Check that the set of fulfilled policies of the overlay has not changed
return ok();
}
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index 77a7b30a230e..8f25b8d6a734 100644
--- a/cmds/idmap2/include/idmap2/Idmap.h
+++ b/cmds/idmap2/include/idmap2/Idmap.h
@@ -117,6 +117,14 @@ class IdmapHeader {
return overlay_crc_;
}
+ inline uint32_t GetFulfilledPolicies() const {
+ return fulfilled_policies_;
+ }
+
+ bool GetEnforceOverlayable() const {
+ return enforce_overlayable_;
+ }
+
inline StringPiece GetTargetPath() const {
return StringPiece(target_path_);
}
@@ -132,8 +140,11 @@ class IdmapHeader {
// Invariant: anytime the idmap data encoding is changed, the idmap version
// field *must* be incremented. Because of this, we know that if the idmap
// header is up-to-date the entire file is up-to-date.
- Result<Unit> IsUpToDate() const;
- Result<Unit> IsUpToDate(uint32_t target_crc_) const;
+ Result<Unit> IsUpToDate(const char* target_path, const char* overlay_path,
+ uint32_t fulfilled_policies, bool enforce_overlayable) const;
+ Result<Unit> IsUpToDate(const char* target_path, const char* overlay_path, uint32_t target_crc,
+ uint32_t overlay_crc, uint32_t fulfilled_policies,
+ bool enforce_overlayable) const;
void accept(Visitor* v) const;
@@ -145,6 +156,8 @@ class IdmapHeader {
uint32_t version_;
uint32_t target_crc_;
uint32_t overlay_crc_;
+ uint32_t fulfilled_policies_;
+ bool enforce_overlayable_;
char target_path_[kIdmapStringLength];
char overlay_path_[kIdmapStringLength];
std::string debug_info_;
diff --git a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
index 362dcb36007a..255212ad4c66 100644
--- a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
+++ b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
@@ -66,6 +66,8 @@ void BinaryStreamVisitor::visit(const IdmapHeader& header) {
Write32(header.GetVersion());
Write32(header.GetTargetCrc());
Write32(header.GetOverlayCrc());
+ Write32(header.GetFulfilledPolicies());
+ Write8(static_cast<uint8_t>(header.GetEnforceOverlayable()));
WriteString256(header.GetTargetPath());
WriteString256(header.GetOverlayPath());
WriteString(header.GetDebugInfo());
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 706b842b3b47..0bea21735b24 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -112,14 +112,18 @@ Result<uint32_t> GetPackageCrc(const ZipFile& zip) {
std::unique_ptr<const IdmapHeader> IdmapHeader::FromBinaryStream(std::istream& stream) {
std::unique_ptr<IdmapHeader> idmap_header(new IdmapHeader());
-
+ uint8_t enforce_overlayable;
if (!Read32(stream, &idmap_header->magic_) || !Read32(stream, &idmap_header->version_) ||
!Read32(stream, &idmap_header->target_crc_) || !Read32(stream, &idmap_header->overlay_crc_) ||
+ !Read32(stream, &idmap_header->fulfilled_policies_) ||
+ !Read8(stream, &enforce_overlayable) ||
!ReadString256(stream, idmap_header->target_path_) ||
!ReadString256(stream, idmap_header->overlay_path_)) {
return nullptr;
}
+ idmap_header->enforce_overlayable_ = static_cast<bool>(enforce_overlayable);
+
auto debug_str = ReadString(stream);
if (!debug_str) {
return nullptr;
@@ -129,21 +133,35 @@ std::unique_ptr<const IdmapHeader> IdmapHeader::FromBinaryStream(std::istream& s
return std::move(idmap_header);
}
-Result<Unit> IdmapHeader::IsUpToDate() const {
- const std::unique_ptr<const ZipFile> target_zip = ZipFile::Open(target_path_);
+Result<Unit> IdmapHeader::IsUpToDate(const char* target_path, const char* overlay_path,
+ uint32_t fulfilled_policies, bool enforce_overlayable) const {
+ const std::unique_ptr<const ZipFile> target_zip = ZipFile::Open(target_path);
if (!target_zip) {
- return Error("failed to open target %s", GetTargetPath().to_string().c_str());
+ return Error("failed to open target %s", target_path);
}
- Result<uint32_t> target_crc = GetPackageCrc(*target_zip);
+ const Result<uint32_t> target_crc = GetPackageCrc(*target_zip);
if (!target_crc) {
return Error("failed to get target crc");
}
- return IsUpToDate(*target_crc);
+ const std::unique_ptr<const ZipFile> overlay_zip = ZipFile::Open(overlay_path);
+ if (!overlay_zip) {
+ return Error("failed to overlay target %s", overlay_path);
+ }
+
+ const Result<uint32_t> overlay_crc = GetPackageCrc(*overlay_zip);
+ if (!overlay_crc) {
+ return Error("failed to get overlay crc");
+ }
+
+ return IsUpToDate(target_path, overlay_path, *target_crc, *overlay_crc, fulfilled_policies,
+ enforce_overlayable);
}
-Result<Unit> IdmapHeader::IsUpToDate(uint32_t target_crc) const {
+Result<Unit> IdmapHeader::IsUpToDate(const char* target_path, const char* overlay_path,
+ uint32_t target_crc, uint32_t overlay_crc,
+ uint32_t fulfilled_policies, bool enforce_overlayable) const {
if (magic_ != kIdmapMagic) {
return Error("bad magic: actual 0x%08x, expected 0x%08x", magic_, kIdmapMagic);
}
@@ -157,19 +175,30 @@ Result<Unit> IdmapHeader::IsUpToDate(uint32_t target_crc) const {
target_crc);
}
- const std::unique_ptr<const ZipFile> overlay_zip = ZipFile::Open(overlay_path_);
- if (!overlay_zip) {
- return Error("failed to open overlay %s", GetOverlayPath().to_string().c_str());
+ if (overlay_crc_ != overlay_crc) {
+ return Error("bad overlay crc: idmap version 0x%08x, file system version 0x%08x", overlay_crc_,
+ overlay_crc);
}
- Result<uint32_t> overlay_crc = GetPackageCrc(*overlay_zip);
- if (!overlay_crc) {
- return Error("failed to get overlay crc");
+ if (fulfilled_policies_ != fulfilled_policies) {
+ return Error("bad fulfilled policies: idmap version 0x%08x, file system version 0x%08x",
+ fulfilled_policies, fulfilled_policies_);
}
- if (overlay_crc_ != *overlay_crc) {
- return Error("bad overlay crc: idmap version 0x%08x, file system version 0x%08x", overlay_crc_,
- *overlay_crc);
+ if (enforce_overlayable != enforce_overlayable_) {
+ return Error("bad enforce overlayable: idmap version %s, file system version %s",
+ enforce_overlayable ? "true" : "false",
+ enforce_overlayable_ ? "true" : "false");
+ }
+
+ if (strcmp(target_path, target_path_) != 0) {
+ return Error("bad target path: idmap version %s, file system version %s", target_path,
+ target_path_);
+ }
+
+ if (strcmp(overlay_path, overlay_path_) != 0) {
+ return Error("bad overlay path: idmap version %s, file system version %s", overlay_path,
+ overlay_path_);
}
return Unit{};
@@ -320,6 +349,9 @@ Result<std::unique_ptr<const Idmap>> Idmap::FromApkAssets(const ApkAssets& targe
}
header->overlay_crc_ = *crc;
+ header->fulfilled_policies_ = fulfilled_policies;
+ header->enforce_overlayable_ = enforce_overlayable;
+
if (target_apk_path.size() > sizeof(header->target_path_)) {
return Error("target apk path \"%s\" longer than maximum size %zu", target_apk_path.c_str(),
sizeof(header->target_path_));
diff --git a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
index 751c60c4add4..3f62a2ae2029 100644
--- a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
+++ b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
@@ -23,10 +23,12 @@
#include "android-base/macros.h"
#include "android-base/stringprintf.h"
#include "androidfw/ApkAssets.h"
+#include "idmap2/PolicyUtils.h"
#include "idmap2/ResourceUtils.h"
#include "idmap2/Result.h"
using android::ApkAssets;
+using android::idmap2::policy::PoliciesToDebugString;
namespace {
@@ -39,9 +41,6 @@ size_t StringSizeWhenEncoded(const std::string& s) {
namespace android::idmap2 {
-// verbatim copy fomr PrettyPrintVisitor.cpp, move to common utils
-#define RESID(pkg, type, entry) (((pkg) << 24) | ((type) << 16) | (entry))
-
void RawPrintVisitor::visit(const Idmap& idmap ATTRIBUTE_UNUSED) {
}
@@ -50,6 +49,9 @@ void RawPrintVisitor::visit(const IdmapHeader& header) {
print(header.GetVersion(), "version");
print(header.GetTargetCrc(), "target crc");
print(header.GetOverlayCrc(), "overlay crc");
+ print(header.GetFulfilledPolicies(), "fulfilled policies: %s",
+ PoliciesToDebugString(header.GetFulfilledPolicies()).c_str());
+ print(static_cast<uint8_t>(header.GetEnforceOverlayable()), "enforce overlayable");
print(header.GetTargetPath().to_string(), kIdmapStringLength, "target path");
print(header.GetOverlayPath().to_string(), kIdmapStringLength, "overlay path");
print("...", StringSizeWhenEncoded(header.GetDebugInfo()), "debug info");
diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp
index 44acbcaf8ace..34589a1c39dc 100644
--- a/cmds/idmap2/libidmap2/ResourceMapping.cpp
+++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp
@@ -61,8 +61,7 @@ Result<Unit> CheckOverlayable(const LoadedPackage& target_package,
const ResourceId& target_resource) {
static constexpr const PolicyBitmask sDefaultPolicies =
PolicyFlags::ODM_PARTITION | PolicyFlags::OEM_PARTITION | PolicyFlags::SYSTEM_PARTITION |
- PolicyFlags::VENDOR_PARTITION | PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE |
- PolicyFlags::ACTOR_SIGNATURE;
+ PolicyFlags::VENDOR_PARTITION | PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE;
// If the resource does not have an overlayable definition, allow the resource to be overlaid if
// the overlay is preinstalled or signed with the same signature as the target.
@@ -292,13 +291,6 @@ Result<ResourceMapping> ResourceMapping::FromApkAssets(const ApkAssets& target_a
const PolicyBitmask& fulfilled_policies,
bool enforce_overlayable,
LogInfo& log_info) {
- if (enforce_overlayable) {
- log_info.Info(LogMessage() << "fulfilled_policies="
- << ConcatPolicies(BitmaskToPolicies(fulfilled_policies))
- << " enforce_overlayable="
- << (enforce_overlayable ? "true" : "false"));
- }
-
AssetManager2 target_asset_manager;
if (!target_asset_manager.SetApkAssets({&target_apk_assets}, true /* invalidate_caches */,
false /* filter_incompatible_configs*/)) {
diff --git a/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h
index 4973b7638d10..5bd353af4ad3 100644
--- a/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h
+++ b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h
@@ -21,9 +21,12 @@
#include <string>
#include <vector>
+#include "android-base/stringprintf.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/StringPiece.h"
+using android::base::StringPrintf;
+
using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
@@ -48,6 +51,29 @@ inline static const std::array<std::pair<StringPiece, PolicyFlags>, 8> kPolicySt
{kPolicySystem, PolicyFlags::SYSTEM_PARTITION},
{kPolicyVendor, PolicyFlags::VENDOR_PARTITION},
};
+
+inline static std::string PoliciesToDebugString(PolicyBitmask policies) {
+ std::string str;
+ uint32_t remaining = policies;
+ for (auto const& policy : kPolicyStringToFlag) {
+ if ((policies & policy.second) != policy.second) {
+ continue;
+ }
+ if (!str.empty()) {
+ str.append("|");
+ }
+ str.append(policy.first.data());
+ remaining &= ~policy.second;
+ }
+ if (remaining != 0) {
+ if (!str.empty()) {
+ str.append("|");
+ }
+ str.append(StringPrintf("0x%08x", remaining));
+ }
+ return !str.empty() ? str : "none";
+}
+
} // namespace android::idmap2::policy
#endif // IDMAP2_INCLUDE_IDMAP2_POLICIES_H_
diff --git a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
index db4778c8ee09..5fea7bcdaac5 100644
--- a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
+++ b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
@@ -48,6 +48,11 @@ TEST(BinaryStreamVisitorTests, CreateBinaryStreamViaBinaryStreamVisitor) {
ASSERT_TRUE(result2);
const auto idmap2 = std::move(*result2);
+ ASSERT_EQ(idmap1->GetHeader()->GetFulfilledPolicies(),
+ idmap2->GetHeader()->GetFulfilledPolicies());
+ ASSERT_EQ(idmap1->GetHeader()->GetEnforceOverlayable(),
+ idmap2->GetHeader()->GetEnforceOverlayable());
+ ASSERT_EQ(idmap1->GetHeader()->GetTargetPath(), idmap2->GetHeader()->GetTargetPath());
ASSERT_EQ(idmap1->GetHeader()->GetTargetCrc(), idmap2->GetHeader()->GetTargetCrc());
ASSERT_EQ(idmap1->GetHeader()->GetTargetPath(), idmap2->GetHeader()->GetTargetPath());
ASSERT_EQ(idmap1->GetData().size(), 1U);
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index 87da36c01192..6fab5e0f8ae1 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -62,9 +62,11 @@ TEST(IdmapTests, CreateIdmapHeaderFromBinaryStream) {
std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(stream);
ASSERT_THAT(header, NotNull());
ASSERT_EQ(header->GetMagic(), 0x504d4449U);
- ASSERT_EQ(header->GetVersion(), 0x03U);
+ ASSERT_EQ(header->GetVersion(), 0x04U);
ASSERT_EQ(header->GetTargetCrc(), 0x1234U);
ASSERT_EQ(header->GetOverlayCrc(), 0x5678U);
+ ASSERT_EQ(header->GetFulfilledPolicies(), 0x11);
+ ASSERT_EQ(header->GetEnforceOverlayable(), true);
ASSERT_EQ(header->GetTargetPath().to_string(), "targetX.apk");
ASSERT_EQ(header->GetOverlayPath().to_string(), "overlayX.apk");
ASSERT_EQ(header->GetDebugInfo(), "debug");
@@ -73,7 +75,7 @@ TEST(IdmapTests, CreateIdmapHeaderFromBinaryStream) {
TEST(IdmapTests, FailToCreateIdmapHeaderFromBinaryStreamIfPathTooLong) {
std::string raw(reinterpret_cast<const char*>(idmap_raw_data), idmap_raw_data_len);
// overwrite the target path string, including the terminating null, with '.'
- for (size_t i = 0x10; i < 0x110; i++) {
+ for (size_t i = 0x15; i < 0x115; i++) {
raw[i] = '.';
}
std::istringstream stream(raw);
@@ -82,7 +84,7 @@ TEST(IdmapTests, FailToCreateIdmapHeaderFromBinaryStreamIfPathTooLong) {
}
TEST(IdmapTests, CreateIdmapDataHeaderFromBinaryStream) {
- const size_t offset = 0x21c;
+ const size_t offset = 0x221;
std::string raw(reinterpret_cast<const char*>(idmap_raw_data + offset),
idmap_raw_data_len - offset);
std::istringstream stream(raw);
@@ -94,7 +96,7 @@ TEST(IdmapTests, CreateIdmapDataHeaderFromBinaryStream) {
}
TEST(IdmapTests, CreateIdmapDataFromBinaryStream) {
- const size_t offset = 0x21c;
+ const size_t offset = 0x221;
std::string raw(reinterpret_cast<const char*>(idmap_raw_data + offset),
idmap_raw_data_len - offset);
std::istringstream stream(raw);
@@ -128,9 +130,11 @@ TEST(IdmapTests, CreateIdmapFromBinaryStream) {
ASSERT_THAT(idmap->GetHeader(), NotNull());
ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
- ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x03U);
+ ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x04U);
ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0x1234U);
ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0x5678U);
+ ASSERT_EQ(idmap->GetHeader()->GetFulfilledPolicies(), 0x11);
+ ASSERT_EQ(idmap->GetHeader()->GetEnforceOverlayable(), true);
ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), "targetX.apk");
ASSERT_EQ(idmap->GetHeader()->GetOverlayPath().to_string(), "overlayX.apk");
@@ -180,9 +184,11 @@ TEST(IdmapTests, CreateIdmapHeaderFromApkAssets) {
ASSERT_THAT(idmap->GetHeader(), NotNull());
ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
- ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x03U);
+ ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x04U);
ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), android::idmap2::TestConstants::TARGET_CRC);
ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), android::idmap2::TestConstants::OVERLAY_CRC);
+ ASSERT_EQ(idmap->GetHeader()->GetFulfilledPolicies(), PolicyFlags::PUBLIC);
+ ASSERT_EQ(idmap->GetHeader()->GetEnforceOverlayable(), true);
ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), target_apk_path);
ASSERT_EQ(idmap->GetHeader()->GetOverlayPath(), overlay_apk_path);
}
@@ -389,7 +395,8 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) {
std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(stream);
ASSERT_THAT(header, NotNull());
- ASSERT_TRUE(header->IsUpToDate());
+ ASSERT_TRUE(header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(),
+ PolicyFlags::PUBLIC, /* enforce_overlayable */ true));
// magic: bytes (0x0, 0x03)
std::string bad_magic_string(stream.str());
@@ -402,7 +409,8 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) {
IdmapHeader::FromBinaryStream(bad_magic_stream);
ASSERT_THAT(bad_magic_header, NotNull());
ASSERT_NE(header->GetMagic(), bad_magic_header->GetMagic());
- ASSERT_FALSE(bad_magic_header->IsUpToDate());
+ ASSERT_FALSE(bad_magic_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(),
+ PolicyFlags::PUBLIC, /* enforce_overlayable */ true));
// version: bytes (0x4, 0x07)
std::string bad_version_string(stream.str());
@@ -415,7 +423,8 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) {
IdmapHeader::FromBinaryStream(bad_version_stream);
ASSERT_THAT(bad_version_header, NotNull());
ASSERT_NE(header->GetVersion(), bad_version_header->GetVersion());
- ASSERT_FALSE(bad_version_header->IsUpToDate());
+ ASSERT_FALSE(bad_magic_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(),
+ PolicyFlags::PUBLIC, /* enforce_overlayable */ true));
// target crc: bytes (0x8, 0xb)
std::string bad_target_crc_string(stream.str());
@@ -428,7 +437,8 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) {
IdmapHeader::FromBinaryStream(bad_target_crc_stream);
ASSERT_THAT(bad_target_crc_header, NotNull());
ASSERT_NE(header->GetTargetCrc(), bad_target_crc_header->GetTargetCrc());
- ASSERT_FALSE(bad_target_crc_header->IsUpToDate());
+ ASSERT_FALSE(bad_magic_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(),
+ PolicyFlags::PUBLIC, /* enforce_overlayable */ true));
// overlay crc: bytes (0xc, 0xf)
std::string bad_overlay_crc_string(stream.str());
@@ -441,27 +451,55 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) {
IdmapHeader::FromBinaryStream(bad_overlay_crc_stream);
ASSERT_THAT(bad_overlay_crc_header, NotNull());
ASSERT_NE(header->GetOverlayCrc(), bad_overlay_crc_header->GetOverlayCrc());
- ASSERT_FALSE(bad_overlay_crc_header->IsUpToDate());
-
- // target path: bytes (0x10, 0x10f)
+ ASSERT_FALSE(bad_magic_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(),
+ PolicyFlags::PUBLIC, /* enforce_overlayable */ true));
+
+ // fulfilled policy: bytes (0x10, 0x13)
+ std::string bad_policy_string(stream.str());
+ bad_policy_string[0x10] = '.';
+ bad_policy_string[0x11] = '.';
+ bad_policy_string[0x12] = '.';
+ bad_policy_string[0x13] = '.';
+ std::stringstream bad_policy_stream(bad_policy_string);
+ std::unique_ptr<const IdmapHeader> bad_policy_header =
+ IdmapHeader::FromBinaryStream(bad_policy_stream);
+ ASSERT_THAT(bad_policy_header, NotNull());
+ ASSERT_NE(header->GetFulfilledPolicies(), bad_policy_header->GetFulfilledPolicies());
+ ASSERT_FALSE(bad_policy_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(),
+ PolicyFlags::PUBLIC, /* enforce_overlayable */ true));
+
+ // enforce overlayable: bytes (0x14)
+ std::string bad_enforce_string(stream.str());
+ bad_enforce_string[0x14] = '\0';
+ std::stringstream bad_enforce_stream(bad_enforce_string);
+ std::unique_ptr<const IdmapHeader> bad_enforce_header =
+ IdmapHeader::FromBinaryStream(bad_enforce_stream);
+ ASSERT_THAT(bad_enforce_header, NotNull());
+ ASSERT_NE(header->GetEnforceOverlayable(), bad_enforce_header->GetEnforceOverlayable());
+ ASSERT_FALSE(bad_enforce_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(),
+ PolicyFlags::PUBLIC, /* enforce_overlayable */ true));
+
+ // target path: bytes (0x15, 0x114)
std::string bad_target_path_string(stream.str());
- bad_target_path_string[0x10] = '\0';
+ bad_target_path_string[0x15] = '\0';
std::stringstream bad_target_path_stream(bad_target_path_string);
std::unique_ptr<const IdmapHeader> bad_target_path_header =
IdmapHeader::FromBinaryStream(bad_target_path_stream);
ASSERT_THAT(bad_target_path_header, NotNull());
ASSERT_NE(header->GetTargetPath(), bad_target_path_header->GetTargetPath());
- ASSERT_FALSE(bad_target_path_header->IsUpToDate());
+ ASSERT_FALSE(bad_magic_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(),
+ PolicyFlags::PUBLIC, /* enforce_overlayable */ true));
- // overlay path: bytes (0x110, 0x20f)
+ // overlay path: bytes (0x115, 0x214)
std::string bad_overlay_path_string(stream.str());
- bad_overlay_path_string[0x110] = '\0';
+ bad_overlay_path_string[0x115] = '\0';
std::stringstream bad_overlay_path_stream(bad_overlay_path_string);
std::unique_ptr<const IdmapHeader> bad_overlay_path_header =
IdmapHeader::FromBinaryStream(bad_overlay_path_stream);
ASSERT_THAT(bad_overlay_path_header, NotNull());
ASSERT_NE(header->GetOverlayPath(), bad_overlay_path_header->GetOverlayPath());
- ASSERT_FALSE(bad_overlay_path_header->IsUpToDate());
+ ASSERT_FALSE(bad_magic_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(),
+ PolicyFlags::PUBLIC, /* enforce_overlayable */ true));
}
class TestVisitor : public Visitor {
diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
index 5c5c81edee90..b268d5add141 100644
--- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
@@ -43,6 +43,8 @@ namespace android::idmap2 {
<< str << "--------"; \
} while (0)
+#define ADDRESS "[0-9a-f]{8}: "
+
TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
fclose(stderr); // silence expected warnings
@@ -62,15 +64,16 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
RawPrintVisitor visitor(stream);
(*idmap)->accept(&visitor);
-#define ADDRESS "[0-9a-f]{8}: "
ASSERT_CONTAINS_REGEX(ADDRESS "504d4449 magic\n", stream.str());
- ASSERT_CONTAINS_REGEX(ADDRESS "00000003 version\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000004 version\n", stream.str());
ASSERT_CONTAINS_REGEX(
StringPrintf(ADDRESS "%s target crc\n", android::idmap2::TestConstants::TARGET_CRC_STRING),
stream.str());
ASSERT_CONTAINS_REGEX(
StringPrintf(ADDRESS "%s overlay crc\n", android::idmap2::TestConstants::OVERLAY_CRC_STRING),
stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000001 fulfilled policies: public\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS " 01 enforce overlayable\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS " 7f target package id\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS " 7f overlay package id\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00000004 target entry count\n", stream.str());
@@ -83,7 +86,6 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
ASSERT_CONTAINS_REGEX(ADDRESS "7f010000 value: integer/int1\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "7f010000 overlay id: integer/int1\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "7f010000 target id: integer/int1\n", stream.str());
-#undef ADDRESS
}
TEST(RawPrintVisitorTests, CreateRawPrintVisitorWithoutAccessToApks) {
@@ -99,22 +101,23 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitorWithoutAccessToApks) {
RawPrintVisitor visitor(stream);
(*idmap)->accept(&visitor);
- ASSERT_NE(stream.str().find("00000000: 504d4449 magic\n"), std::string::npos);
- ASSERT_NE(stream.str().find("00000004: 00000003 version\n"), std::string::npos);
- ASSERT_NE(stream.str().find("00000008: 00001234 target crc\n"), std::string::npos);
- ASSERT_NE(stream.str().find("0000000c: 00005678 overlay crc\n"), std::string::npos);
- ASSERT_NE(stream.str().find("0000021c: 7f target package id\n"), std::string::npos);
- ASSERT_NE(stream.str().find("0000021d: 7f overlay package id\n"), std::string::npos);
- ASSERT_NE(stream.str().find("0000021e: 00000003 target entry count\n"), std::string::npos);
- ASSERT_NE(stream.str().find("00000222: 00000003 overlay entry count\n"), std::string::npos);
- ASSERT_NE(stream.str().find("00000226: 00000000 string pool index offset\n"), std::string::npos);
- ASSERT_NE(stream.str().find("0000022a: 00000000 string pool byte length\n"), std::string::npos);
- ASSERT_NE(stream.str().find("0000022e: 7f020000 target id\n"), std::string::npos);
- ASSERT_NE(stream.str().find("00000232: 01 type: reference\n"), std::string::npos);
- ASSERT_NE(stream.str().find("00000233: 7f020000 value\n"), std::string::npos);
-
- ASSERT_NE(stream.str().find("00000249: 7f020000 overlay id\n"), std::string::npos);
- ASSERT_NE(stream.str().find("0000024d: 7f020000 target id\n"), std::string::npos);
+ ASSERT_CONTAINS_REGEX(ADDRESS "504d4449 magic\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000004 version\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00001234 target crc\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00005678 overlay crc\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000011 fulfilled policies: public|signature\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS " 01 enforce overlayable\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS " 7f target package id\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS " 7f overlay package id\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000003 target entry count\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000003 overlay entry count\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000000 string pool index offset\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000000 string pool byte length\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 target id\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS " 01 type: reference\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 value\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 overlay id\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 target id\n", stream.str());
}
} // namespace android::idmap2
diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp
index 5754eaf078a9..de039f440e33 100644
--- a/cmds/idmap2/tests/ResourceMappingTests.cpp
+++ b/cmds/idmap2/tests/ResourceMappingTests.cpp
@@ -287,26 +287,66 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsNoDefinedOverlayableAndNoTarget
R::overlay::string::str4, false /* rewrite */));
}
-
-// Overlays that are pre-installed or are signed with the same signature as the target/actor can
+// Overlays that are neither pre-installed nor signed with the same signature as the target cannot
// overlay packages that have not defined overlayable resources.
-TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) {
- constexpr PolicyBitmask kDefaultPolicies =
- PolicyFlags::SIGNATURE | PolicyFlags::ACTOR_SIGNATURE | PolicyFlags::PRODUCT_PARTITION |
- PolicyFlags::SYSTEM_PARTITION | PolicyFlags::VENDOR_PARTITION | PolicyFlags::ODM_PARTITION |
- PolicyFlags::OEM_PARTITION;
+TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPoliciesPublicFail) {
+ auto resources = TestGetResourceMapping("/target/target-no-overlayable.apk",
+ "/overlay/overlay-no-name.apk", PolicyFlags::PUBLIC,
+ /* enforce_overlayable */ true);
+
+ ASSERT_TRUE(resources) << resources.GetErrorMessage();
+ ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 0U);
+}
- for (PolicyBitmask policy = 1U << (sizeof(PolicyBitmask) * 8 - 1); policy > 0;
- policy = policy >> 1U) {
+// Overlays that are pre-installed or are signed with the same signature as the target can overlay
+// packages that have not defined overlayable resources.
+TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) {
+ auto CheckEntries = [&](const PolicyBitmask& fulfilled_policies) -> void {
auto resources = TestGetResourceMapping("/target/target-no-overlayable.apk",
"/system-overlay-invalid/system-overlay-invalid.apk",
- policy, /* enforce_overlayable */ true);
- ASSERT_TRUE(resources) << resources.GetErrorMessage();
+ fulfilled_policies,
+ /* enforce_overlayable */ true);
- const size_t expected_overlaid = (policy & kDefaultPolicies) != 0 ? 10U : 0U;
- ASSERT_EQ(expected_overlaid, resources->GetTargetToOverlayMap().size())
- << "Incorrect number of resources overlaid through policy " << policy;
- }
+ ASSERT_TRUE(resources) << resources.GetErrorMessage();
+ auto& res = *resources;
+ ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 10U);
+ ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE,
+ R::system_overlay_invalid::string::not_overlayable,
+ false /* rewrite */));
+ ASSERT_RESULT(MappingExists(res, R::target::string::other, Res_value::TYPE_REFERENCE,
+ R::system_overlay_invalid::string::other, false /* rewrite */));
+ ASSERT_RESULT(MappingExists(res, R::target::string::policy_actor, Res_value::TYPE_REFERENCE,
+ R::system_overlay_invalid::string::policy_actor,
+ false /* rewrite */));
+ ASSERT_RESULT(MappingExists(res, R::target::string::policy_odm, Res_value::TYPE_REFERENCE,
+ R::system_overlay_invalid::string::policy_odm,
+ false /* rewrite */));
+ ASSERT_RESULT(MappingExists(res, R::target::string::policy_oem, Res_value::TYPE_REFERENCE,
+ R::system_overlay_invalid::string::policy_oem,
+ false /* rewrite */));
+ ASSERT_RESULT(MappingExists(res, R::target::string::policy_product, Res_value::TYPE_REFERENCE,
+ R::system_overlay_invalid::string::policy_product,
+ false /* rewrite */));
+ ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE,
+ R::system_overlay_invalid::string::policy_public,
+ false /* rewrite */));
+ ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE,
+ R::system_overlay_invalid::string::policy_signature,
+ false /* rewrite */));
+ ASSERT_RESULT(MappingExists(res, R::target::string::policy_system, Res_value::TYPE_REFERENCE,
+ R::system_overlay_invalid::string::policy_system,
+ false /* rewrite */));
+ ASSERT_RESULT(MappingExists(
+ res, R::target::string::policy_system_vendor, Res_value::TYPE_REFERENCE,
+ R::system_overlay_invalid::string::policy_system_vendor, false /* rewrite */));
+ };
+
+ CheckEntries(PolicyFlags::SIGNATURE);
+ CheckEntries(PolicyFlags::PRODUCT_PARTITION);
+ CheckEntries(PolicyFlags::SYSTEM_PARTITION);
+ CheckEntries(PolicyFlags::VENDOR_PARTITION);
+ CheckEntries(PolicyFlags::ODM_PARTITION);
+ CheckEntries(PolicyFlags::OEM_PARTITION);
}
} // namespace android::idmap2
diff --git a/cmds/idmap2/tests/TestHelpers.h b/cmds/idmap2/tests/TestHelpers.h
index e899589c7e61..b599dcb0069a 100644
--- a/cmds/idmap2/tests/TestHelpers.h
+++ b/cmds/idmap2/tests/TestHelpers.h
@@ -30,7 +30,7 @@ const unsigned char idmap_raw_data[] = {
0x49, 0x44, 0x4d, 0x50,
// 0x4: version
- 0x03, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00,
// 0x8: target crc
0x34, 0x12, 0x00, 0x00,
@@ -38,7 +38,13 @@ const unsigned char idmap_raw_data[] = {
// 0xc: overlay crc
0x78, 0x56, 0x00, 0x00,
- // 0x10: target path "targetX.apk"
+ // 0x10: fulfilled policies
+ 0x11, 0x00, 0x00, 0x00,
+
+ // 0x14: enforce overlayable
+ 0x01,
+
+ // 0x15: target path "targetX.apk"
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x58, 0x2e, 0x61, 0x70, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -56,7 +62,7 @@ const unsigned char idmap_raw_data[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // 0x110: overlay path "overlayX.apk"
+ // 0x115: overlay path "overlayX.apk"
0x6f, 0x76, 0x65, 0x72, 0x6c, 0x61, 0x79, 0x58, 0x2e, 0x61, 0x70, 0x6b, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -74,7 +80,7 @@ const unsigned char idmap_raw_data[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- // 0x210: debug string
+ // 0x215: debug string
// string length, including terminating null
0x08, 0x00, 0x00, 0x00,
@@ -82,63 +88,63 @@ const unsigned char idmap_raw_data[] = {
0x64, 0x65, 0x62, 0x75, 0x67, 0x00, 0x00, 0x00,
// DATA HEADER
- // 0x21c: target_package_id
+ // 0x221: target_package_id
0x7f,
- // 0x21d: overlay_package_id
+ // 0x222: overlay_package_id
0x7f,
- // 0x21e: target_entry_count
+ // 0x223: target_entry_count
0x03, 0x00, 0x00, 0x00,
- // 0x222: overlay_entry_count
+ // 0x227: overlay_entry_count
0x03, 0x00, 0x00, 0x00,
- // 0x226: string_pool_offset
+ // 0x22b: string_pool_offset
0x00, 0x00, 0x00, 0x00,
- // 0x22a: string_pool_byte_length
+ // 0x22f: string_pool_byte_length
0x00, 0x00, 0x00, 0x00,
// TARGET ENTRIES
- // 0x22e: 0x7f020000
+ // 0x233: 0x7f020000
0x00, 0x00, 0x02, 0x7f,
- // 0x232: TYPE_REFERENCE
+ // 0x237: TYPE_REFERENCE
0x01,
- // 0x233: 0x7f020000
+ // 0x238: 0x7f020000
0x00, 0x00, 0x02, 0x7f,
- // 0x237: 0x7f030000
+ // 0x23c: 0x7f030000
0x00, 0x00, 0x03, 0x7f,
- // 0x23b: TYPE_REFERENCE
+ // 0x240: TYPE_REFERENCE
0x01,
- // 0x23c: 0x7f030000
+ // 0x241: 0x7f030000
0x00, 0x00, 0x03, 0x7f,
- // 0x240: 0x7f030002
+ // 0x245: 0x7f030002
0x02, 0x00, 0x03, 0x7f,
- // 0x244: TYPE_REFERENCE
+ // 0x249: TYPE_REFERENCE
0x01,
- // 0x245: 0x7f030001
+ // 0x24a: 0x7f030001
0x01, 0x00, 0x03, 0x7f,
// OVERLAY ENTRIES
- // 0x249: 0x7f020000 -> 0x7f020000
+ // 0x24e: 0x7f020000 -> 0x7f020000
0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x02, 0x7f,
- // 0x251: 0x7f030000 -> 0x7f030000
+ // 0x256: 0x7f030000 -> 0x7f030000
0x00, 0x00, 0x03, 0x7f, 0x00, 0x00, 0x03, 0x7f,
- // 0x259: 0x7f030001 -> 0x7f030002
+ // 0x25e: 0x7f030001 -> 0x7f030002
0x01, 0x00, 0x03, 0x7f, 0x02, 0x00, 0x03, 0x7f};
-const unsigned int idmap_raw_data_len = 0x261;
+const unsigned int idmap_raw_data_len = 0x266;
std::string GetTestDataPath();
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 36a8b2cfc084..81d059ed84d9 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -444,6 +444,11 @@ message Atom {
TvTunerStateChanged tv_tuner_state_changed = 276 [(module) = "framework"];
MediaOutputOpSwitchReported mediaoutput_op_switch_reported =
277 [(module) = "settings"];
+ CellBroadcastMessageFiltered cb_message_filtered =
+ 278 [(module) = "cellbroadcast"];
+ TvTunerDvrStatus tv_tuner_dvr_status = 279 [(module) = "framework"];
+ TvCasSessionOpenStatus tv_cas_session_open_status =
+ 280 [(module) = "framework"];
// StatsdStats tracks platform atoms with ids upto 500.
// Update StatsdStats::kMaxPushedAtomId when atom ids here approach that value.
@@ -9134,8 +9139,10 @@ message IntegrityRulesPushed {
/**
* Logs when a cell broadcast message is received on the device.
*
- * Logged from CellBroadcastService module:
+ * Logged from Cell Broadcast module and platform:
* packages/modules/CellBroadcastService/src/com/android/cellbroadcastservice/
+ * packages/apps/CellBroadcastReceiver/
+ * frameworks/opt/telephony/src/java/com/android/internal/telephony/CellBroadcastServiceManager.java
*/
message CellBroadcastMessageReported {
// The type of Cell Broadcast message
@@ -9146,8 +9153,40 @@ message CellBroadcastMessageReported {
CDMA_SPC = 3;
}
+ // The parts of the cell broadcast message pipeline
+ enum ReportSource {
+ UNKNOWN_SOURCE = 0;
+ FRAMEWORK = 1;
+ CB_SERVICE = 2;
+ CB_RECEIVER_APP = 3;
+ }
+
// GSM, CDMA, CDMA-SCP
optional CbType type = 1;
+
+ // The source of the report
+ optional ReportSource source = 2;
+}
+
+/**
+ * Logs when a cell broadcast message is filtered out, or otherwise intentionally not sent to CBR.
+ *
+ * Logged from CellBroadcastService module:
+ * packages/modules/CellBroadcastService/src/com/android/cellbroadcastservice/
+ */
+message CellBroadcastMessageFiltered {
+ enum FilterReason {
+ NOT_FILTERED = 0;
+ DUPLICATE_MESSAGE = 1;
+ GEOFENCED_MESSAGE = 2;
+ AREA_INFO_MESSAGE = 3;
+ }
+
+ // GSM, CDMA, CDMA-SCP
+ optional CellBroadcastMessageReported.CbType type = 1;
+
+ // The source of the report
+ optional FilterReason filter = 2;
}
/**
@@ -9174,6 +9213,7 @@ message CellBroadcastMessageError {
UNEXPECTED_GSM_MESSAGE_TYPE_FROM_FWK = 12;
UNEXPECTED_CDMA_MESSAGE_TYPE_FROM_FWK = 13;
UNEXPECTED_CDMA_SCP_MESSAGE_TYPE_FROM_FWK = 14;
+ NO_CONNECTION_TO_CB_SERVICE = 15;
}
// What kind of error occurred
@@ -9205,6 +9245,58 @@ message TvTunerStateChanged {
// new state
optional State state = 2;
}
+
+/**
+ * Logs the status of a dvr playback or record.
+ * This is atom ID 279.
+ *
+ * Logged from:
+ * frameworks/base/media/java/android/media/tv/tuner/dvr
+ */
+message TvTunerDvrStatus {
+ enum Type {
+ UNKNOWN_TYPE = 0;
+ PLAYBACK = 1; // is a playback
+ RECORD = 2; // is a record
+ }
+ enum State {
+ UNKNOWN_STATE = 0;
+ STARTED = 1; // DVR is started
+ STOPPED = 2; // DVR is stopped
+ }
+ // The uid of the application that sent this custom atom.
+ optional int32 uid = 1 [(is_uid) = true];
+ // DVR type
+ optional Type type = 2;
+ // DVR state
+ optional State state = 3;
+ // Identify the segment of a record or playback
+ optional int32 segment_id = 4;
+ // indicate how many overflow or underflow happened between started to stopped
+ optional int32 overflow_underflow_count = 5;
+}
+
+/**
+ * Logs when a cas session opened through MediaCas.
+ * This is atom ID 280.
+ *
+ * Logged from:
+ * frameworks/base/media/java/android/media/MediaCas.java
+ */
+message TvCasSessionOpenStatus {
+ enum State {
+ UNKNOWN = 0;
+ SUCCEEDED = 1; // indicate that the session is opened successfully.
+ FAILED = 2; // indicate that the session isn’t opened successfully.
+ }
+ // The uid of the application that sent this custom atom.
+ optional int32 uid = 1 [(is_uid) = true];
+ // Cas system Id
+ optional int32 cas_system_id = 2;
+ // State of the session
+ optional State state = 3;
+}
+
/**
* Logs when an app is frozen or unfrozen.
*
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
index c829ccd11ec9..e9875baf58c7 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
@@ -37,7 +37,8 @@ CombinationConditionTracker::~CombinationConditionTracker() {
bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConfig,
const vector<sp<ConditionTracker>>& allConditionTrackers,
const unordered_map<int64_t, int>& conditionIdIndexMap,
- vector<bool>& stack) {
+ vector<bool>& stack,
+ vector<ConditionState>& initialConditionCache) {
VLOG("Combination predicate init() %lld", (long long)mConditionId);
if (mInitialized) {
return true;
@@ -73,9 +74,9 @@ bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConf
return false;
}
-
- bool initChildSucceeded = childTracker->init(allConditionConfig, allConditionTrackers,
- conditionIdIndexMap, stack);
+ bool initChildSucceeded =
+ childTracker->init(allConditionConfig, allConditionTrackers, conditionIdIndexMap,
+ stack, initialConditionCache);
if (!initChildSucceeded) {
ALOGW("Child initialization failed %lld ", (long long)child);
@@ -95,6 +96,11 @@ bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConf
childTracker->getLogTrackerIndex().end());
}
+ mUnSlicedPartCondition = evaluateCombinationCondition(mUnSlicedChildren, mLogicalOperation,
+ initialConditionCache);
+ initialConditionCache[mIndex] =
+ evaluateCombinationCondition(mChildren, mLogicalOperation, initialConditionCache);
+
// unmark this node in the recursion stack.
stack[mIndex] = false;
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.h b/cmds/statsd/src/condition/CombinationConditionTracker.h
index e3d860127780..39ff0ab03266 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.h
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.h
@@ -32,8 +32,8 @@ public:
bool init(const std::vector<Predicate>& allConditionConfig,
const std::vector<sp<ConditionTracker>>& allConditionTrackers,
- const std::unordered_map<int64_t, int>& conditionIdIndexMap,
- std::vector<bool>& stack) override;
+ const std::unordered_map<int64_t, int>& conditionIdIndexMap, std::vector<bool>& stack,
+ std::vector<ConditionState>& initialConditionCache) override;
void evaluateCondition(const LogEvent& event,
const std::vector<MatchingState>& eventMatcherValues,
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
index f9a2c344c346..62736c8160bb 100644
--- a/cmds/statsd/src/condition/ConditionTracker.h
+++ b/cmds/statsd/src/condition/ConditionTracker.h
@@ -51,10 +51,12 @@ public:
// need to call init() on children conditions)
// conditionIdIndexMap: the mapping from condition id to its index.
// stack: a bit map to keep track which nodes have been visited on the stack in the recursion.
+ // initialConditionCache: tracks initial conditions of all ConditionTrackers.
virtual bool init(const std::vector<Predicate>& allConditionConfig,
const std::vector<sp<ConditionTracker>>& allConditionTrackers,
const std::unordered_map<int64_t, int>& conditionIdIndexMap,
- std::vector<bool>& stack) = 0;
+ std::vector<bool>& stack,
+ std::vector<ConditionState>& initialConditionCache) = 0;
// evaluate current condition given the new event.
// event: the new log event
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index f23ec50abb50..efb4d4989425 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -95,9 +95,11 @@ SimpleConditionTracker::~SimpleConditionTracker() {
bool SimpleConditionTracker::init(const vector<Predicate>& allConditionConfig,
const vector<sp<ConditionTracker>>& allConditionTrackers,
const unordered_map<int64_t, int>& conditionIdIndexMap,
- vector<bool>& stack) {
+ vector<bool>& stack,
+ vector<ConditionState>& initialConditionCache) {
// SimpleConditionTracker does not have dependency on other conditions, thus we just return
// if the initialization was successful.
+ initialConditionCache[mIndex] = mInitialValue;
return mInitialized;
}
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h
index 5c5cc565f783..ea7f87bde2b8 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.h
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.h
@@ -37,8 +37,8 @@ public:
bool init(const std::vector<Predicate>& allConditionConfig,
const std::vector<sp<ConditionTracker>>& allConditionTrackers,
- const std::unordered_map<int64_t, int>& conditionIdIndexMap,
- std::vector<bool>& stack) override;
+ const std::unordered_map<int64_t, int>& conditionIdIndexMap, std::vector<bool>& stack,
+ std::vector<ConditionState>& initialConditionCache) override;
void evaluateCondition(const LogEvent& event,
const std::vector<MatchingState>& eventMatcherValues,
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index d865c2176c1e..573961276e5b 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -68,14 +68,14 @@ const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
CountMetricProducer::CountMetricProducer(
const ConfigKey& key, const CountMetric& metric, const int conditionIndex,
- const sp<ConditionWizard>& wizard, const int64_t timeBaseNs, const int64_t startTimeNs,
-
+ const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
+ const int64_t timeBaseNs, const int64_t startTimeNs,
const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap,
const vector<int>& slicedStateAtoms,
const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
- : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard, eventActivationMap,
- eventDeactivationMap, slicedStateAtoms, stateGroupMap) {
+ : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, initialConditionCache, wizard,
+ eventActivationMap, eventDeactivationMap, slicedStateAtoms, stateGroupMap) {
if (metric.has_bucket()) {
mBucketSizeNs =
TimeUnitToBucketSizeInMillisGuardrailed(key.GetUid(), metric.bucket()) * 1000000;
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 26b3d3cc6722..f05fb061ccc1 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -43,7 +43,8 @@ class CountMetricProducer : public MetricProducer {
public:
CountMetricProducer(
const ConfigKey& key, const CountMetric& countMetric, const int conditionIndex,
- const sp<ConditionWizard>& wizard, const int64_t timeBaseNs, const int64_t startTimeNs,
+ const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
+ const int64_t timeBaseNs, const int64_t startTimeNs,
const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap = {},
const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
eventDeactivationMap = {},
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 663365924829..e9b043876d3d 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -64,15 +64,16 @@ const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 6;
DurationMetricProducer::DurationMetricProducer(
const ConfigKey& key, const DurationMetric& metric, const int conditionIndex,
- const size_t startIndex, const size_t stopIndex, const size_t stopAllIndex,
- const bool nesting, const sp<ConditionWizard>& wizard,
- const FieldMatcher& internalDimensions, const int64_t timeBaseNs, const int64_t startTimeNs,
+ const vector<ConditionState>& initialConditionCache, const size_t startIndex,
+ const size_t stopIndex, const size_t stopAllIndex, const bool nesting,
+ const sp<ConditionWizard>& wizard, const FieldMatcher& internalDimensions,
+ const int64_t timeBaseNs, const int64_t startTimeNs,
const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap,
const vector<int>& slicedStateAtoms,
const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
- : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard, eventActivationMap,
- eventDeactivationMap, slicedStateAtoms, stateGroupMap),
+ : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, initialConditionCache, wizard,
+ eventActivationMap, eventDeactivationMap, slicedStateAtoms, stateGroupMap),
mAggregationType(metric.aggregation_type()),
mStartIndex(startIndex),
mStopIndex(stopIndex),
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 53f0f28c3386..bfe1010c89de 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -40,10 +40,10 @@ class DurationMetricProducer : public MetricProducer {
public:
DurationMetricProducer(
const ConfigKey& key, const DurationMetric& durationMetric, const int conditionIndex,
- const size_t startIndex, const size_t stopIndex, const size_t stopAllIndex,
- const bool nesting, const sp<ConditionWizard>& wizard,
- const FieldMatcher& internalDimensions, const int64_t timeBaseNs,
- const int64_t startTimeNs,
+ const vector<ConditionState>& initialConditionCache, const size_t startIndex,
+ const size_t stopIndex, const size_t stopAllIndex, const bool nesting,
+ const sp<ConditionWizard>& wizard, const FieldMatcher& internalDimensions,
+ const int64_t timeBaseNs, const int64_t startTimeNs,
const unordered_map<int, shared_ptr<Activation>>& eventActivationMap = {},
const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap = {},
const vector<int>& slicedStateAtoms = {},
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index d68f64ae40b0..dc0036a687f3 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -54,13 +54,14 @@ const int FIELD_ID_ATOMS = 2;
EventMetricProducer::EventMetricProducer(
const ConfigKey& key, const EventMetric& metric, const int conditionIndex,
- const sp<ConditionWizard>& wizard, const int64_t startTimeNs,
+ const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
+ const int64_t startTimeNs,
const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap,
const vector<int>& slicedStateAtoms,
const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
- : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, wizard, eventActivationMap,
- eventDeactivationMap, slicedStateAtoms, stateGroupMap) {
+ : MetricProducer(metric.id(), key, startTimeNs, conditionIndex, initialConditionCache, wizard,
+ eventActivationMap, eventDeactivationMap, slicedStateAtoms, stateGroupMap) {
if (metric.links().size() > 0) {
for (const auto& link : metric.links()) {
Metric2Condition mc;
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index e8f2119a170c..bfb2de36fad4 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -35,7 +35,8 @@ class EventMetricProducer : public MetricProducer {
public:
EventMetricProducer(
const ConfigKey& key, const EventMetric& eventMetric, const int conditionIndex,
- const sp<ConditionWizard>& wizard, const int64_t startTimeNs,
+ const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
+ const int64_t startTimeNs,
const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap = {},
const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
eventDeactivationMap = {},
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 1d4d0b3a5e5d..020f4b638f4d 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -70,14 +70,15 @@ const int FIELD_ID_END_BUCKET_ELAPSED_MILLIS = 8;
GaugeMetricProducer::GaugeMetricProducer(
const ConfigKey& key, const GaugeMetric& metric, const int conditionIndex,
- const sp<ConditionWizard>& wizard, const int whatMatcherIndex,
- const sp<EventMatcherWizard>& matcherWizard, const int pullTagId, const int triggerAtomId,
- const int atomId, const int64_t timeBaseNs, const int64_t startTimeNs,
- const sp<StatsPullerManager>& pullerManager,
+ const vector<ConditionState>& initialConditionCache, const sp<ConditionWizard>& wizard,
+ const int whatMatcherIndex, const sp<EventMatcherWizard>& matcherWizard,
+ const int pullTagId, const int triggerAtomId, const int atomId, const int64_t timeBaseNs,
+ const int64_t startTimeNs, const sp<StatsPullerManager>& pullerManager,
const unordered_map<int, shared_ptr<Activation>>& eventActivationMap,
const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap)
- : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, wizard, eventActivationMap,
- eventDeactivationMap, /*slicedStateAtoms=*/{}, /*stateGroupMap=*/{}),
+ : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, initialConditionCache, wizard,
+ eventActivationMap, eventDeactivationMap, /*slicedStateAtoms=*/{},
+ /*stateGroupMap=*/{}),
mWhatMatcherIndex(whatMatcherIndex),
mEventMatcherWizard(matcherWizard),
mPullerManager(pullerManager),
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index 2eb584b097ea..2fc772b6b641 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -58,6 +58,7 @@ class GaugeMetricProducer : public virtual MetricProducer, public virtual PullDa
public:
GaugeMetricProducer(
const ConfigKey& key, const GaugeMetric& gaugeMetric, const int conditionIndex,
+ const vector<ConditionState>& initialConditionCache,
const sp<ConditionWizard>& conditionWizard, const int whatMatcherIndex,
const sp<EventMatcherWizard>& matcherWizard, const int pullTagId,
const int triggerAtomId, const int atomId, const int64_t timeBaseNs,
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index bb4f03e81e2e..cdd20cdd70f9 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -45,7 +45,8 @@ const int FIELD_ID_ACTIVE_EVENT_ACTIVATION_STATE = 3;
MetricProducer::MetricProducer(
const int64_t& metricId, const ConfigKey& key, const int64_t timeBaseNs,
- const int conditionIndex, const sp<ConditionWizard>& wizard,
+ const int conditionIndex, const vector<ConditionState>& initialConditionCache,
+ const sp<ConditionWizard>& wizard,
const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap,
const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
eventDeactivationMap,
@@ -56,7 +57,7 @@ MetricProducer::MetricProducer(
mTimeBaseNs(timeBaseNs),
mCurrentBucketStartTimeNs(timeBaseNs),
mCurrentBucketNum(0),
- mCondition(initialCondition(conditionIndex)),
+ mCondition(initialCondition(conditionIndex, initialConditionCache)),
mConditionTrackerIndex(conditionIndex),
mConditionSliced(false),
mWizard(wizard),
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 9d37608149ce..be4cd6724bb1 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -129,7 +129,8 @@ struct SkippedBucket {
class MetricProducer : public virtual android::RefBase, public virtual StateListener {
public:
MetricProducer(const int64_t& metricId, const ConfigKey& key, const int64_t timeBaseNs,
- const int conditionIndex, const sp<ConditionWizard>& wizard,
+ const int conditionIndex, const vector<ConditionState>& initialConditionCache,
+ const sp<ConditionWizard>& wizard,
const std::unordered_map<int, std::shared_ptr<Activation>>& eventActivationMap,
const std::unordered_map<int, std::vector<std::shared_ptr<Activation>>>&
eventDeactivationMap,
@@ -138,8 +139,9 @@ public:
virtual ~MetricProducer(){};
- ConditionState initialCondition(const int conditionIndex) const {
- return conditionIndex >= 0 ? ConditionState::kUnknown : ConditionState::kTrue;
+ ConditionState initialCondition(const int conditionIndex,
+ const vector<ConditionState>& initialConditionCache) const {
+ return conditionIndex >= 0 ? initialConditionCache[conditionIndex] : ConditionState::kTrue;
}
/**
@@ -496,6 +498,8 @@ protected:
FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithDimensions);
FRIEND_TEST(ValueMetricE2eTest, TestInitWithSlicedState_WithIncorrectDimensions);
FRIEND_TEST(ValueMetricE2eTest, TestInitialConditionChanges);
+
+ FRIEND_TEST(MetricsManagerTest, TestInitialConditions);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 71df710ee647..c0d117402314 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -78,6 +78,7 @@ const Value ZERO_DOUBLE((int64_t)0);
// ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently
ValueMetricProducer::ValueMetricProducer(
const ConfigKey& key, const ValueMetric& metric, const int conditionIndex,
+ const vector<ConditionState>& initialConditionCache,
const sp<ConditionWizard>& conditionWizard, const int whatMatcherIndex,
const sp<EventMatcherWizard>& matcherWizard, const int pullTagId, const int64_t timeBaseNs,
const int64_t startTimeNs, const sp<StatsPullerManager>& pullerManager,
@@ -85,8 +86,9 @@ ValueMetricProducer::ValueMetricProducer(
const unordered_map<int, vector<shared_ptr<Activation>>>& eventDeactivationMap,
const vector<int>& slicedStateAtoms,
const unordered_map<int, unordered_map<int, int64_t>>& stateGroupMap)
- : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, conditionWizard,
- eventActivationMap, eventDeactivationMap, slicedStateAtoms, stateGroupMap),
+ : MetricProducer(metric.id(), key, timeBaseNs, conditionIndex, initialConditionCache,
+ conditionWizard, eventActivationMap, eventDeactivationMap, slicedStateAtoms,
+ stateGroupMap),
mWhatMatcherIndex(whatMatcherIndex),
mEventMatcherWizard(matcherWizard),
mPullerManager(pullerManager),
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index aaf7df5c9771..505b23921806 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -52,6 +52,7 @@ class ValueMetricProducer : public virtual MetricProducer, public virtual PullDa
public:
ValueMetricProducer(
const ConfigKey& key, const ValueMetric& valueMetric, const int conditionIndex,
+ const vector<ConditionState>& initialConditionCache,
const sp<ConditionWizard>& conditionWizard, const int whatMatcherIndex,
const sp<EventMatcherWizard>& matcherWizard, const int pullTagId,
const int64_t timeBaseNs, const int64_t startTimeNs,
@@ -74,7 +75,7 @@ public:
if (!mSplitBucketForAppUpgrade) {
return;
}
- if (mIsPulled && mCondition) {
+ if (mIsPulled && mCondition == ConditionState::kTrue) {
pullAndMatchEventsLocked(eventTimeNs);
}
flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
@@ -83,7 +84,7 @@ public:
// ValueMetric needs special logic if it's a pulled atom.
void onStatsdInitCompleted(const int64_t& eventTimeNs) override {
std::lock_guard<std::mutex> lock(mMutex);
- if (mIsPulled && mCondition) {
+ if (mIsPulled && mCondition == ConditionState::kTrue) {
pullAndMatchEventsLocked(eventTimeNs);
}
flushCurrentBucketLocked(eventTimeNs, eventTimeNs);
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 210d382b1363..8917c36bb608 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -285,11 +285,14 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config,
const unordered_map<int64_t, int>& logTrackerMap,
unordered_map<int64_t, int>& conditionTrackerMap,
vector<sp<ConditionTracker>>& allConditionTrackers,
- unordered_map<int, std::vector<int>>& trackerToConditionMap) {
+ unordered_map<int, std::vector<int>>& trackerToConditionMap,
+ vector<ConditionState>& initialConditionCache) {
vector<Predicate> conditionConfigs;
const int conditionTrackerCount = config.predicate_size();
conditionConfigs.reserve(conditionTrackerCount);
allConditionTrackers.reserve(conditionTrackerCount);
+ initialConditionCache.reserve(conditionTrackerCount);
+ std::fill(initialConditionCache.begin(), initialConditionCache.end(), ConditionState::kUnknown);
for (int i = 0; i < conditionTrackerCount; i++) {
const Predicate& condition = config.predicate(i);
@@ -321,7 +324,7 @@ bool initConditions(const ConfigKey& key, const StatsdConfig& config,
for (size_t i = 0; i < allConditionTrackers.size(); i++) {
auto& conditionTracker = allConditionTrackers[i];
if (!conditionTracker->init(conditionConfigs, allConditionTrackers, conditionTrackerMap,
- stackTracker)) {
+ stackTracker, initialConditionCache)) {
return false;
}
for (const int trackerIndex : conditionTracker->getLogTrackerIndex()) {
@@ -351,14 +354,14 @@ bool initStates(const StatsdConfig& config, unordered_map<int64_t, int>& stateAt
}
bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t timeBaseTimeNs,
- const int64_t currentTimeNs,
- const sp<StatsPullerManager>& pullerManager,
+ const int64_t currentTimeNs, const sp<StatsPullerManager>& pullerManager,
const unordered_map<int64_t, int>& logTrackerMap,
const unordered_map<int64_t, int>& conditionTrackerMap,
const vector<sp<LogMatchingTracker>>& allAtomMatchers,
const unordered_map<int64_t, int>& stateAtomIdMap,
const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
vector<sp<ConditionTracker>>& allConditionTrackers,
+ const vector<ConditionState>& initialConditionCache,
vector<sp<MetricProducer>>& allMetricProducers,
unordered_map<int, vector<int>>& conditionToMetricMap,
unordered_map<int, vector<int>>& trackerToMetricMap,
@@ -441,9 +444,10 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
eventDeactivationMap);
if (!success) return false;
- sp<MetricProducer> countProducer = new CountMetricProducer(
- key, metric, conditionIndex, wizard, timeBaseTimeNs, currentTimeNs,
- eventActivationMap, eventDeactivationMap, slicedStateAtoms, stateGroupMap);
+ sp<MetricProducer> countProducer =
+ new CountMetricProducer(key, metric, conditionIndex, initialConditionCache, wizard,
+ timeBaseTimeNs, currentTimeNs, eventActivationMap,
+ eventDeactivationMap, slicedStateAtoms, stateGroupMap);
allMetricProducers.push_back(countProducer);
}
@@ -547,10 +551,10 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
if (!success) return false;
sp<MetricProducer> durationMetric = new DurationMetricProducer(
- key, metric, conditionIndex, trackerIndices[0], trackerIndices[1],
- trackerIndices[2], nesting, wizard, internalDimensions, timeBaseTimeNs,
- currentTimeNs, eventActivationMap, eventDeactivationMap, slicedStateAtoms,
- stateGroupMap);
+ key, metric, conditionIndex, initialConditionCache, trackerIndices[0],
+ trackerIndices[1], trackerIndices[2], nesting, wizard, internalDimensions,
+ timeBaseTimeNs, currentTimeNs, eventActivationMap, eventDeactivationMap,
+ slicedStateAtoms, stateGroupMap);
allMetricProducers.push_back(durationMetric);
}
@@ -593,9 +597,9 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
eventDeactivationMap);
if (!success) return false;
- sp<MetricProducer> eventMetric = new EventMetricProducer(
- key, metric, conditionIndex, wizard, timeBaseTimeNs, eventActivationMap,
- eventDeactivationMap);
+ sp<MetricProducer> eventMetric =
+ new EventMetricProducer(key, metric, conditionIndex, initialConditionCache, wizard,
+ timeBaseTimeNs, eventActivationMap, eventDeactivationMap);
allMetricProducers.push_back(eventMetric);
}
@@ -683,9 +687,9 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
if (!success) return false;
sp<MetricProducer> valueProducer = new ValueMetricProducer(
- key, metric, conditionIndex, wizard, trackerIndex, matcherWizard, pullTagId,
- timeBaseTimeNs, currentTimeNs, pullerManager, eventActivationMap,
- eventDeactivationMap, slicedStateAtoms, stateGroupMap);
+ key, metric, conditionIndex, initialConditionCache, wizard, trackerIndex,
+ matcherWizard, pullTagId, timeBaseTimeNs, currentTimeNs, pullerManager,
+ eventActivationMap, eventDeactivationMap, slicedStateAtoms, stateGroupMap);
allMetricProducers.push_back(valueProducer);
}
@@ -778,9 +782,9 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const int64_t
if (!success) return false;
sp<MetricProducer> gaugeProducer = new GaugeMetricProducer(
- key, metric, conditionIndex, wizard, trackerIndex, matcherWizard, pullTagId,
- triggerAtomId, atomTagId, timeBaseTimeNs, currentTimeNs, pullerManager,
- eventActivationMap, eventDeactivationMap);
+ key, metric, conditionIndex, initialConditionCache, wizard, trackerIndex,
+ matcherWizard, pullTagId, triggerAtomId, atomTagId, timeBaseTimeNs, currentTimeNs,
+ pullerManager, eventActivationMap, eventDeactivationMap);
allMetricProducers.push_back(gaugeProducer);
}
for (int i = 0; i < config.no_report_metric_size(); ++i) {
@@ -930,6 +934,7 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap&
std::set<int64_t>& noReportMetricIds) {
unordered_map<int64_t, int> logTrackerMap;
unordered_map<int64_t, int> conditionTrackerMap;
+ vector<ConditionState> initialConditionCache;
unordered_map<int64_t, int> metricProducerMap;
unordered_map<int64_t, int> stateAtomIdMap;
unordered_map<int64_t, unordered_map<int, int64_t>> allStateGroupMaps;
@@ -941,7 +946,7 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap&
VLOG("initLogMatchingTrackers succeed...");
if (!initConditions(key, config, logTrackerMap, conditionTrackerMap, allConditionTrackers,
- trackerToConditionMap)) {
+ trackerToConditionMap, initialConditionCache)) {
ALOGE("initConditionTrackers failed");
return false;
}
@@ -952,10 +957,10 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, UidMap&
}
if (!initMetrics(key, config, timeBaseNs, currentTimeNs, pullerManager, logTrackerMap,
conditionTrackerMap, allAtomMatchers, stateAtomIdMap, allStateGroupMaps,
- allConditionTrackers, allMetricProducers,
- conditionToMetricMap, trackerToMetricMap, metricProducerMap,
- noReportMetricIds, activationAtomTrackerToMetricMap,
- deactivationAtomTrackerToMetricMap, metricsWithActivation)) {
+ allConditionTrackers, initialConditionCache, allMetricProducers,
+ conditionToMetricMap, trackerToMetricMap, metricProducerMap, noReportMetricIds,
+ activationAtomTrackerToMetricMap, deactivationAtomTrackerToMetricMap,
+ metricsWithActivation)) {
ALOGE("initMetricProducers failed");
return false;
}
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index 6af7a9adca20..96b5c26ff789 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -60,12 +60,14 @@ bool initLogTrackers(const StatsdConfig& config,
// [allConditionTrackers]: stores the sp to all the ConditionTrackers
// [trackerToConditionMap]: contain the mapping from index of
// log tracker to condition trackers that use the log tracker
+// [initialConditionCache]: stores the initial conditions for each ConditionTracker
bool initConditions(const ConfigKey& key, const StatsdConfig& config,
const std::unordered_map<int64_t, int>& logTrackerMap,
std::unordered_map<int64_t, int>& conditionTrackerMap,
std::vector<sp<ConditionTracker>>& allConditionTrackers,
std::unordered_map<int, std::vector<int>>& trackerToConditionMap,
- std::unordered_map<int, std::vector<MetricConditionLink>>& eventConditionLinks);
+ std::unordered_map<int, std::vector<MetricConditionLink>>& eventConditionLinks,
+ std::vector<ConditionState>& initialConditionCache);
// Initialize State maps using State protos in the config. These maps will
// eventually be passed to MetricProducers to initialize their state info.
@@ -103,6 +105,7 @@ bool initMetrics(
const unordered_map<int64_t, int>& stateAtomIdMap,
const unordered_map<int64_t, unordered_map<int, int64_t>>& allStateGroupMaps,
vector<sp<ConditionTracker>>& allConditionTrackers,
+ const std::vector<ConditionState>& initialConditionCache,
std::vector<sp<MetricProducer>>& allMetricProducers,
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
std::unordered_map<int, std::vector<int>>& trackerToMetricMap,
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index b3b095bf4bff..6259757fe092 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -276,11 +276,157 @@ StatsdConfig buildCirclePredicates() {
return config;
}
+StatsdConfig buildConfigWithDifferentPredicates() {
+ StatsdConfig config;
+ config.set_id(12345);
+
+ auto pulledAtomMatcher =
+ CreateSimpleAtomMatcher("SUBSYSTEM_SLEEP", util::SUBSYSTEM_SLEEP_STATE);
+ *config.add_atom_matcher() = pulledAtomMatcher;
+ auto screenOnAtomMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = screenOnAtomMatcher;
+ auto screenOffAtomMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = screenOffAtomMatcher;
+ auto batteryNoneAtomMatcher = CreateBatteryStateNoneMatcher();
+ *config.add_atom_matcher() = batteryNoneAtomMatcher;
+ auto batteryUsbAtomMatcher = CreateBatteryStateUsbMatcher();
+ *config.add_atom_matcher() = batteryUsbAtomMatcher;
+
+ // Simple condition with InitialValue set to default (unknown).
+ auto screenOnUnknownPredicate = CreateScreenIsOnPredicate();
+ *config.add_predicate() = screenOnUnknownPredicate;
+
+ // Simple condition with InitialValue set to false.
+ auto screenOnFalsePredicate = config.add_predicate();
+ screenOnFalsePredicate->set_id(StringToId("ScreenIsOnInitialFalse"));
+ SimplePredicate* simpleScreenOnFalsePredicate =
+ screenOnFalsePredicate->mutable_simple_predicate();
+ simpleScreenOnFalsePredicate->set_start(screenOnAtomMatcher.id());
+ simpleScreenOnFalsePredicate->set_stop(screenOffAtomMatcher.id());
+ simpleScreenOnFalsePredicate->set_initial_value(SimplePredicate_InitialValue_FALSE);
+
+ // Simple condition with InitialValue set to false.
+ auto onBatteryFalsePredicate = config.add_predicate();
+ onBatteryFalsePredicate->set_id(StringToId("OnBatteryInitialFalse"));
+ SimplePredicate* simpleOnBatteryFalsePredicate =
+ onBatteryFalsePredicate->mutable_simple_predicate();
+ simpleOnBatteryFalsePredicate->set_start(batteryNoneAtomMatcher.id());
+ simpleOnBatteryFalsePredicate->set_stop(batteryUsbAtomMatcher.id());
+ simpleOnBatteryFalsePredicate->set_initial_value(SimplePredicate_InitialValue_FALSE);
+
+ // Combination condition with both simple condition InitialValues set to false.
+ auto screenOnFalseOnBatteryFalsePredicate = config.add_predicate();
+ screenOnFalseOnBatteryFalsePredicate->set_id(StringToId("ScreenOnFalseOnBatteryFalse"));
+ screenOnFalseOnBatteryFalsePredicate->mutable_combination()->set_operation(
+ LogicalOperation::AND);
+ addPredicateToPredicateCombination(*screenOnFalsePredicate,
+ screenOnFalseOnBatteryFalsePredicate);
+ addPredicateToPredicateCombination(*onBatteryFalsePredicate,
+ screenOnFalseOnBatteryFalsePredicate);
+
+ // Combination condition with one simple condition InitialValue set to unknown and one set to
+ // false.
+ auto screenOnUnknownOnBatteryFalsePredicate = config.add_predicate();
+ screenOnUnknownOnBatteryFalsePredicate->set_id(StringToId("ScreenOnUnknowneOnBatteryFalse"));
+ screenOnUnknownOnBatteryFalsePredicate->mutable_combination()->set_operation(
+ LogicalOperation::AND);
+ addPredicateToPredicateCombination(screenOnUnknownPredicate,
+ screenOnUnknownOnBatteryFalsePredicate);
+ addPredicateToPredicateCombination(*onBatteryFalsePredicate,
+ screenOnUnknownOnBatteryFalsePredicate);
+
+ // Simple condition metric with initial value false.
+ ValueMetric* metric1 = config.add_value_metric();
+ metric1->set_id(StringToId("ValueSubsystemSleepWhileScreenOnInitialFalse"));
+ metric1->set_what(pulledAtomMatcher.id());
+ *metric1->mutable_value_field() =
+ CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
+ metric1->set_bucket(FIVE_MINUTES);
+ metric1->set_condition(screenOnFalsePredicate->id());
+
+ // Simple condition metric with initial value unknown.
+ ValueMetric* metric2 = config.add_value_metric();
+ metric2->set_id(StringToId("ValueSubsystemSleepWhileScreenOnInitialUnknown"));
+ metric2->set_what(pulledAtomMatcher.id());
+ *metric2->mutable_value_field() =
+ CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
+ metric2->set_bucket(FIVE_MINUTES);
+ metric2->set_condition(screenOnUnknownPredicate.id());
+
+ // Combination condition metric with initial values false and false.
+ ValueMetric* metric3 = config.add_value_metric();
+ metric3->set_id(StringToId("ValueSubsystemSleepWhileScreenOnFalseDeviceUnpluggedFalse"));
+ metric3->set_what(pulledAtomMatcher.id());
+ *metric3->mutable_value_field() =
+ CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
+ metric3->set_bucket(FIVE_MINUTES);
+ metric3->set_condition(screenOnFalseOnBatteryFalsePredicate->id());
+
+ // Combination condition metric with initial values unknown and false.
+ ValueMetric* metric4 = config.add_value_metric();
+ metric4->set_id(StringToId("ValueSubsystemSleepWhileScreenOnUnknownDeviceUnpluggedFalse"));
+ metric4->set_what(pulledAtomMatcher.id());
+ *metric4->mutable_value_field() =
+ CreateDimensions(util::SUBSYSTEM_SLEEP_STATE, {4 /* time sleeping field */});
+ metric4->set_bucket(FIVE_MINUTES);
+ metric4->set_condition(screenOnUnknownOnBatteryFalsePredicate->id());
+
+ return config;
+}
+
bool isSubset(const set<int32_t>& set1, const set<int32_t>& set2) {
return std::includes(set2.begin(), set2.end(), set1.begin(), set1.end());
}
} // anonymous namespace
+TEST(MetricsManagerTest, TestInitialConditions) {
+ UidMap uidMap;
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> periodicAlarmMonitor;
+ StatsdConfig config = buildConfigWithDifferentPredicates();
+ set<int> allTagIds;
+ vector<sp<LogMatchingTracker>> allAtomMatchers;
+ vector<sp<ConditionTracker>> allConditionTrackers;
+ vector<sp<MetricProducer>> allMetricProducers;
+ std::vector<sp<AnomalyTracker>> allAnomalyTrackers;
+ std::vector<sp<AlarmTracker>> allAlarmTrackers;
+ unordered_map<int, std::vector<int>> conditionToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToConditionMap;
+ unordered_map<int, std::vector<int>> activationAtomTrackerToMetricMap;
+ unordered_map<int, std::vector<int>> deactivationAtomTrackerToMetricMap;
+ unordered_map<int64_t, int> alertTrackerMap;
+ vector<int> metricsWithActivation;
+ std::set<int64_t> noReportMetricIds;
+
+ EXPECT_TRUE(initStatsdConfig(
+ kConfigKey, config, uidMap, pullerManager, anomalyAlarmMonitor, periodicAlarmMonitor,
+ timeBaseSec, timeBaseSec, allTagIds, allAtomMatchers, allConditionTrackers,
+ allMetricProducers, allAnomalyTrackers, allAlarmTrackers, conditionToMetricMap,
+ trackerToMetricMap, trackerToConditionMap, activationAtomTrackerToMetricMap,
+ deactivationAtomTrackerToMetricMap, alertTrackerMap, metricsWithActivation,
+ noReportMetricIds));
+ ASSERT_EQ(4u, allMetricProducers.size());
+ ASSERT_EQ(5u, allConditionTrackers.size());
+
+ ConditionKey queryKey;
+ vector<ConditionState> conditionCache(5, ConditionState::kNotEvaluated);
+
+ allConditionTrackers[3]->isConditionMet(queryKey, allConditionTrackers, false, conditionCache);
+ allConditionTrackers[4]->isConditionMet(queryKey, allConditionTrackers, false, conditionCache);
+ EXPECT_EQ(ConditionState::kUnknown, conditionCache[0]);
+ EXPECT_EQ(ConditionState::kFalse, conditionCache[1]);
+ EXPECT_EQ(ConditionState::kFalse, conditionCache[2]);
+ EXPECT_EQ(ConditionState::kFalse, conditionCache[3]);
+ EXPECT_EQ(ConditionState::kUnknown, conditionCache[4]);
+
+ EXPECT_EQ(ConditionState::kFalse, allMetricProducers[0]->mCondition);
+ EXPECT_EQ(ConditionState::kUnknown, allMetricProducers[1]->mCondition);
+ EXPECT_EQ(ConditionState::kFalse, allMetricProducers[2]->mCondition);
+ EXPECT_EQ(ConditionState::kUnknown, allMetricProducers[3]->mCondition);
+}
+
TEST(MetricsManagerTest, TestGoodConfig) {
UidMap uidMap;
sp<StatsPullerManager> pullerManager = new StatsPullerManager();
diff --git a/cmds/statsd/tests/condition/CombinationConditionTracker_test.cpp b/cmds/statsd/tests/condition/CombinationConditionTracker_test.cpp
index 6529d65a5825..1d501fd5a87c 100644
--- a/cmds/statsd/tests/condition/CombinationConditionTracker_test.cpp
+++ b/cmds/statsd/tests/condition/CombinationConditionTracker_test.cpp
@@ -24,6 +24,7 @@ using namespace android::os::statsd;
using std::vector;
#ifdef __ANDROID__
+
TEST(ConditionTrackerTest, TestUnknownCondition) {
LogicalOperation operation = LogicalOperation::AND;
diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
index 86e24fb0c80b..07b5311b1207 100644
--- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
+++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
@@ -112,6 +112,114 @@ std::map<int64_t, HashableDimensionKey> getWakeLockQueryKey(
return outputKeyMap;
}
+TEST(SimpleConditionTrackerTest, TestNonSlicedInitialValueFalse) {
+ SimplePredicate simplePredicate;
+ simplePredicate.set_start(StringToId("SCREEN_TURNED_ON"));
+ simplePredicate.set_stop(StringToId("SCREEN_TURNED_OFF"));
+ simplePredicate.set_count_nesting(false);
+ simplePredicate.set_initial_value(SimplePredicate_InitialValue_FALSE);
+
+ unordered_map<int64_t, int> trackerNameIndexMap;
+ trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
+ trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
+
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"),
+ 0 /*tracker index*/, simplePredicate,
+ trackerNameIndexMap);
+
+ ConditionKey queryKey;
+ vector<sp<ConditionTracker>> allPredicates;
+ vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
+
+ // Check that initial condition is false.
+ conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
+ EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
+
+ vector<MatchingState> matcherState;
+ vector<bool> changedCache(1, false);
+
+ // Matched stop event.
+ // Check that condition is still false.
+ unique_ptr<LogEvent> screenOffEvent =
+ CreateScreenStateChangedEvent(/*timestamp=*/50, android::view::DISPLAY_STATE_OFF);
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kNotMatched); // On matcher not matched
+ matcherState.push_back(MatchingState::kMatched); // Off matcher matched
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ conditionTracker.evaluateCondition(*screenOffEvent, matcherState, allPredicates, conditionCache,
+ changedCache);
+ EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
+ EXPECT_FALSE(changedCache[0]);
+
+ // Matched start event.
+ // Check that condition has changed to true.
+ unique_ptr<LogEvent> screenOnEvent =
+ CreateScreenStateChangedEvent(/*timestamp=*/100, android::view::DISPLAY_STATE_ON);
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kMatched); // On matcher matched
+ matcherState.push_back(MatchingState::kNotMatched); // Off matcher not matched
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+ conditionTracker.evaluateCondition(*screenOnEvent, matcherState, allPredicates, conditionCache,
+ changedCache);
+ EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
+ EXPECT_TRUE(changedCache[0]);
+}
+
+TEST(SimpleConditionTrackerTest, TestNonSlicedInitialValueUnknown) {
+ SimplePredicate simplePredicate;
+ simplePredicate.set_start(StringToId("SCREEN_TURNED_ON"));
+ simplePredicate.set_stop(StringToId("SCREEN_TURNED_OFF"));
+ simplePredicate.set_count_nesting(false);
+ simplePredicate.set_initial_value(SimplePredicate_InitialValue_UNKNOWN);
+
+ unordered_map<int64_t, int> trackerNameIndexMap;
+ trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
+ trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
+
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"),
+ 0 /*tracker index*/, simplePredicate,
+ trackerNameIndexMap);
+
+ ConditionKey queryKey;
+ vector<sp<ConditionTracker>> allPredicates;
+ vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
+
+ // Check that initial condition is unknown.
+ conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
+ EXPECT_EQ(ConditionState::kUnknown, conditionCache[0]);
+
+ vector<MatchingState> matcherState;
+ vector<bool> changedCache(1, false);
+
+ // Matched stop event.
+ // Check that condition is changed to false.
+ unique_ptr<LogEvent> screenOffEvent =
+ CreateScreenStateChangedEvent(/*timestamp=*/50, android::view::DISPLAY_STATE_OFF);
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kNotMatched); // On matcher not matched
+ matcherState.push_back(MatchingState::kMatched); // Off matcher matched
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ conditionTracker.evaluateCondition(*screenOffEvent, matcherState, allPredicates, conditionCache,
+ changedCache);
+ EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
+ EXPECT_TRUE(changedCache[0]);
+
+ // Matched start event.
+ // Check that condition has changed to true.
+ unique_ptr<LogEvent> screenOnEvent =
+ CreateScreenStateChangedEvent(/*timestamp=*/100, android::view::DISPLAY_STATE_ON);
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kMatched); // On matcher matched
+ matcherState.push_back(MatchingState::kNotMatched); // Off matcher not matched
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+ conditionTracker.evaluateCondition(*screenOnEvent, matcherState, allPredicates, conditionCache,
+ changedCache);
+ EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
+ EXPECT_TRUE(changedCache[0]);
+}
+
TEST(SimpleConditionTrackerTest, TestNonSlicedCondition) {
SimplePredicate simplePredicate;
simplePredicate.set_start(StringToId("SCREEN_TURNED_ON"));
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index 74ecaac0f9e3..bb8e7bfd90f4 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -74,8 +74,8 @@ TEST(CountMetricProducerTest, TestFirstBucket) {
metric.set_bucket(ONE_MINUTE);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, 5,
- 600 * NS_PER_SEC + NS_PER_SEC / 2);
+ CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
+ wizard, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2);
EXPECT_EQ(600500000000, countProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(10, countProducer.mCurrentBucketNum);
EXPECT_EQ(660000000005, countProducer.getCurrentBucketEndTimeNs());
@@ -94,8 +94,8 @@ TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- bucketStartTimeNs, bucketStartTimeNs);
+ CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
+ wizard, bucketStartTimeNs, bucketStartTimeNs);
// 2 events in bucket 1.
LogEvent event1(/*uid=*/0, /*pid=*/0);
@@ -157,8 +157,8 @@ TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- CountMetricProducer countProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs,
- bucketStartTimeNs);
+ CountMetricProducer countProducer(kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard,
+ bucketStartTimeNs, bucketStartTimeNs);
countProducer.onConditionChanged(true, bucketStartTimeNs);
@@ -220,12 +220,14 @@ TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
getMockedDimensionKey(conditionTagId, 2, "222")};
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
EXPECT_CALL(*wizard, query(_, key1, _)).WillOnce(Return(ConditionState::kFalse));
EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
- CountMetricProducer countProducer(kConfigKey, metric, 1 /*condition tracker index*/, wizard,
- bucketStartTimeNs, bucketStartTimeNs);
+ CountMetricProducer countProducer(kConfigKey, metric, 0 /*condition tracker index*/,
+ {ConditionState::kUnknown}, wizard, bucketStartTimeNs,
+ bucketStartTimeNs);
countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
countProducer.flushIfNeededLocked(bucketStartTimeNs + 1);
@@ -261,7 +263,8 @@ TEST_P(CountMetricProducerTest_PartialBucket, TestSplitInCurrentBucket) {
alert.set_trigger_if_sum_gt(2);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
+
+ CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, {}, wizard,
bucketStartTimeNs, bucketStartTimeNs);
sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
@@ -327,7 +330,8 @@ TEST_P(CountMetricProducerTest_PartialBucket, TestSplitInNextBucket) {
metric.set_bucket(ONE_MINUTE);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
+
+ CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, {}, wizard,
bucketStartTimeNs, bucketStartTimeNs);
// Bucket is flushed yet.
@@ -391,8 +395,9 @@ TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) {
metric.set_bucket(ONE_MINUTE);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- bucketStartTimeNs, bucketStartTimeNs);
+
+ CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
+ wizard, bucketStartTimeNs, bucketStartTimeNs);
sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
@@ -453,8 +458,8 @@ TEST(CountMetricProducerTest, TestOneWeekTimeUnit) {
int64_t oneDayNs = 24 * 60 * 60 * 1e9;
int64_t fiveWeeksNs = 5 * 7 * oneDayNs;
- CountMetricProducer countProducer(
- kConfigKey, metric, -1 /* meaning no condition */, wizard, oneDayNs, fiveWeeksNs);
+ CountMetricProducer countProducer(kConfigKey, metric, -1 /* meaning no condition */, {}, wizard,
+ oneDayNs, fiveWeeksNs);
int64_t fiveWeeksOneDayNs = fiveWeeksNs + oneDayNs;
diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
index ddda71db4bd4..05cfa37b0ee1 100644
--- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
@@ -70,9 +70,11 @@ TEST(DurationMetricTrackerTest, TestFirstBucket) {
metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
FieldMatcher dimensions;
- DurationMetricProducer durationProducer(
- kConfigKey, metric, -1 /*no condition*/, 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, 5, 600 * NS_PER_SEC + NS_PER_SEC/2);
+
+ DurationMetricProducer durationProducer(kConfigKey, metric, -1 /*no condition*/, {},
+ 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard,
+ dimensions, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2);
EXPECT_EQ(600500000000, durationProducer.mCurrentBucketStartTimeNs);
EXPECT_EQ(10, durationProducer.mCurrentBucketNum);
@@ -96,7 +98,8 @@ TEST(DurationMetricTrackerTest, TestNoCondition) {
makeLogEvent(&event2, bucketStartTimeNs + bucketSizeNs + 2, tagId);
FieldMatcher dimensions;
- DurationMetricProducer durationProducer(kConfigKey, metric, -1 /*no condition*/,
+
+ DurationMetricProducer durationProducer(kConfigKey, metric, -1 /*no condition*/, {},
1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard,
dimensions, bucketStartTimeNs, bucketStartTimeNs);
@@ -138,10 +141,11 @@ TEST(DurationMetricTrackerTest, TestNonSlicedCondition) {
makeLogEvent(&event4, bucketStartTimeNs + bucketSizeNs + 3, tagId);
FieldMatcher dimensions;
- DurationMetricProducer durationProducer(kConfigKey, metric, 0 /* condition index */,
- 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard,
- dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+ DurationMetricProducer durationProducer(
+ kConfigKey, metric, 0 /* condition index */, {ConditionState::kUnknown},
+ 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
+ wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
durationProducer.mCondition = ConditionState::kFalse;
EXPECT_FALSE(durationProducer.mCondition);
@@ -187,10 +191,11 @@ TEST(DurationMetricTrackerTest, TestNonSlicedConditionUnknownState) {
makeLogEvent(&event4, bucketStartTimeNs + bucketSizeNs + 3, tagId);
FieldMatcher dimensions;
- DurationMetricProducer durationProducer(kConfigKey, metric, 0 /* condition index */,
- 1 /* start index */, 2 /* stop index */,
- 3 /* stop_all index */, false /*nesting*/, wizard,
- dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+ DurationMetricProducer durationProducer(
+ kConfigKey, metric, 0 /* condition index */, {ConditionState::kUnknown},
+ 1 /* start index */, 2 /* stop index */, 3 /* stop_all index */, false /*nesting*/,
+ wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
EXPECT_EQ(ConditionState::kUnknown, durationProducer.mCondition);
EXPECT_FALSE(durationProducer.isConditionSliced());
@@ -232,7 +237,8 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestSumDuration) {
metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
FieldMatcher dimensions;
- DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
+
+ DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */, {},
1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard,
dimensions, bucketStartTimeNs, bucketStartTimeNs);
@@ -294,7 +300,8 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestSumDurationWithSplitInFollo
metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
FieldMatcher dimensions;
- DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
+
+ DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */, {},
1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard,
dimensions, bucketStartTimeNs, bucketStartTimeNs);
@@ -357,7 +364,8 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestSumDurationAnomaly) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
FieldMatcher dimensions;
- DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
+
+ DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */, {},
1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard,
dimensions, bucketStartTimeNs, bucketStartTimeNs);
@@ -402,7 +410,8 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestMaxDuration) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
FieldMatcher dimensions;
- DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
+
+ DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */, {},
1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard,
dimensions, bucketStartTimeNs, bucketStartTimeNs);
@@ -455,7 +464,8 @@ TEST_P(DurationMetricProducerTest_PartialBucket, TestMaxDurationWithSplitInNextB
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
FieldMatcher dimensions;
- DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
+
+ DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */, {},
1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard,
dimensions, bucketStartTimeNs, bucketStartTimeNs);
diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
index 5bae3648bd80..dfbb9da568b0 100644
--- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
@@ -65,8 +65,8 @@ TEST(EventMetricProducerTest, TestNoCondition) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- EventMetricProducer eventProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- bucketStartTimeNs);
+ EventMetricProducer eventProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
+ wizard, bucketStartTimeNs);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
@@ -101,7 +101,8 @@ TEST(EventMetricProducerTest, TestEventsWithNonSlicedCondition) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- EventMetricProducer eventProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs);
+ EventMetricProducer eventProducer(kConfigKey, metric, 0 /*condition index*/,
+ {ConditionState::kUnknown}, wizard, bucketStartTimeNs);
eventProducer.onConditionChanged(true /*condition*/, bucketStartTimeNs);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
@@ -155,7 +156,8 @@ TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) {
// Condition is true for second event.
EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
- EventMetricProducer eventProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs);
+ EventMetricProducer eventProducer(kConfigKey, metric, 0 /*condition index*/,
+ {ConditionState::kUnknown}, wizard, bucketStartTimeNs);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index cc5f45922d45..5997bedcdf2d 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -104,10 +104,9 @@ TEST(GaugeMetricProducerTest, TestFirstBucket) {
// statsd started long ago.
// The metric starts in the middle of the bucket
- GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard,
- -1, -1, tagId, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2,
- pullerManager);
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
+ wizard, logEventMatcherIndex, eventMatcherWizard, -1, -1,
+ tagId, 5, 600 * NS_PER_SEC + NS_PER_SEC / 2, pullerManager);
gaugeProducer.prepareFirstBucket();
EXPECT_EQ(600500000000, gaugeProducer.mCurrentBucketStartTimeNs);
@@ -147,9 +146,9 @@ TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) {
return true;
}));
- GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
- bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
+ wizard, logEventMatcherIndex, eventMatcherWizard, tagId, -1,
+ tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
gaugeProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
@@ -225,8 +224,8 @@ TEST_P(GaugeMetricProducerTest_PartialBucket, TestPushedEvents) {
new EventMatcherWizard({new SimpleLogMatchingTracker(
atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
- GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard,
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
+ wizard, logEventMatcherIndex, eventMatcherWizard,
-1 /* -1 means no pulling */, -1, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
gaugeProducer.prepareFirstBucket();
@@ -308,7 +307,6 @@ TEST_P(GaugeMetricProducerTest_PartialBucket, TestPulled) {
sp<EventMatcherWizard> eventMatcherWizard =
new EventMatcherWizard({new SimpleLogMatchingTracker(
atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
@@ -322,9 +320,9 @@ TEST_P(GaugeMetricProducerTest_PartialBucket, TestPulled) {
return true;
}));
- GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
- bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
+ wizard, logEventMatcherIndex, eventMatcherWizard, tagId, -1,
+ tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
gaugeProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
@@ -393,9 +391,9 @@ TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _))
.WillOnce(Return(false));
- GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
- bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
+ wizard, logEventMatcherIndex, eventMatcherWizard, tagId, -1,
+ tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
gaugeProducer.prepareFirstBucket();
vector<shared_ptr<LogEvent>> allData;
@@ -450,7 +448,8 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition) {
return true;
}));
- GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, 0 /*condition index*/,
+ {ConditionState::kUnknown}, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, -1, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
gaugeProducer.prepareFirstBucket();
@@ -536,7 +535,8 @@ TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) {
return true;
}));
- GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, 0 /*condition index*/,
+ {ConditionState::kUnknown}, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, -1, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
gaugeProducer.prepareFirstBucket();
@@ -584,9 +584,9 @@ TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) {
new EventMatcherWizard({new SimpleLogMatchingTracker(
atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
- GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId,
- bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
+ wizard, logEventMatcherIndex, eventMatcherWizard, tagId, -1,
+ tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
gaugeProducer.prepareFirstBucket();
Alert alert;
@@ -683,9 +683,10 @@ TEST(GaugeMetricProducerTest, TestPullOnTrigger) {
.WillOnce(Return(true));
int triggerId = 5;
- GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard, tagId, triggerId,
- tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
+ wizard, logEventMatcherIndex, eventMatcherWizard, tagId,
+ triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
+ pullerManager);
gaugeProducer.prepareFirstBucket();
ASSERT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size());
@@ -761,9 +762,10 @@ TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput) {
.WillOnce(Return(true));
int triggerId = 5;
- GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard, tagId, triggerId,
- tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
+ wizard, logEventMatcherIndex, eventMatcherWizard, tagId,
+ triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
+ pullerManager);
gaugeProducer.prepareFirstBucket();
LogEvent triggerEvent(/*uid=*/0, /*pid=*/0);
@@ -823,9 +825,10 @@ TEST(GaugeMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) {
}));
int triggerId = 5;
- GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard, tagId, triggerId,
- tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
+ wizard, logEventMatcherIndex, eventMatcherWizard, tagId,
+ triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs,
+ pullerManager);
gaugeProducer.prepareFirstBucket();
LogEvent triggerEvent(/*uid=*/0, /*pid=*/0);
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 52eb7409aa5d..58a3259bbf2c 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -111,37 +111,17 @@ public:
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _))
.WillRepeatedly(Return());
- sp<ValueMetricProducer> valueProducer = new ValueMetricProducer(
- kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, logEventMatcherIndex,
- eventMatcherWizard, tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ sp<ValueMetricProducer> valueProducer =
+ new ValueMetricProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
+ wizard, logEventMatcherIndex, eventMatcherWizard, tagId,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
valueProducer->prepareFirstBucket();
return valueProducer;
}
static sp<ValueMetricProducer> createValueProducerWithCondition(
- sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric) {
- UidMap uidMap;
- SimpleAtomMatcher atomMatcher;
- atomMatcher.set_atom_id(tagId);
- sp<EventMatcherWizard> eventMatcherWizard =
- new EventMatcherWizard({new SimpleLogMatchingTracker(
- atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
- sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _))
- .WillOnce(Return());
- EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _))
- .WillRepeatedly(Return());
-
- sp<ValueMetricProducer> valueProducer = new ValueMetricProducer(
- kConfigKey, metric, 1, wizard, logEventMatcherIndex, eventMatcherWizard, tagId,
- bucketStartTimeNs, bucketStartTimeNs, pullerManager);
- valueProducer->prepareFirstBucket();
- valueProducer->mCondition = ConditionState::kFalse;
- return valueProducer;
- }
-
- static sp<ValueMetricProducer> createValueProducerWithNoInitialCondition(
- sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric) {
+ sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric,
+ ConditionState conditionAfterFirstBucketPrepared) {
UidMap uidMap;
SimpleAtomMatcher atomMatcher;
atomMatcher.set_atom_id(tagId);
@@ -155,9 +135,11 @@ public:
.WillRepeatedly(Return());
sp<ValueMetricProducer> valueProducer = new ValueMetricProducer(
- kConfigKey, metric, 1, wizard, logEventMatcherIndex, eventMatcherWizard, tagId,
- bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+ kConfigKey, metric, 0 /*condition index*/, {ConditionState::kUnknown}, wizard,
+ logEventMatcherIndex, eventMatcherWizard, tagId, bucketStartTimeNs,
+ bucketStartTimeNs, pullerManager);
valueProducer->prepareFirstBucket();
+ valueProducer->mCondition = conditionAfterFirstBucketPrepared;
return valueProducer;
}
@@ -176,8 +158,9 @@ public:
.WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _))
.WillRepeatedly(Return());
+
sp<ValueMetricProducer> valueProducer = new ValueMetricProducer(
- kConfigKey, metric, -1 /* no condition */, wizard, logEventMatcherIndex,
+ kConfigKey, metric, -1 /* no condition */, {}, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager, {},
{}, slicedStateAtoms, stateGroupMap);
valueProducer->prepareFirstBucket();
@@ -232,9 +215,9 @@ TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime) {
// statsd started long ago.
// The metric starts in the middle of the bucket
- ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard, -1, startTimeBase,
- 22, pullerManager);
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
+ wizard, logEventMatcherIndex, eventMatcherWizard, -1,
+ startTimeBase, 22, pullerManager);
valueProducer.prepareFirstBucket();
EXPECT_EQ(startTimeBase, valueProducer.calcPreviousBucketEndTime(60 * NS_PER_SEC + 10));
@@ -262,8 +245,8 @@ TEST(ValueMetricProducerTest, TestFirstBucket) {
// statsd started long ago.
// The metric starts in the middle of the bucket
- ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard, -1, 5,
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
+ wizard, logEventMatcherIndex, eventMatcherWizard, -1, 5,
600 * NS_PER_SEC + NS_PER_SEC / 2, pullerManager);
valueProducer.prepareFirstBucket();
@@ -427,7 +410,7 @@ TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) {
}));
sp<ValueMetricProducer> valueProducer = new ValueMetricProducer(
- kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, logEventMatcherIndex,
+ kConfigKey, metric, -1 /*-1 meaning no condition*/, {}, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager);
valueProducer->prepareFirstBucket();
@@ -629,7 +612,8 @@ TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
@@ -689,7 +673,8 @@ TEST_P(ValueMetricProducerTest_PartialBucket, TestPushedEvents) {
atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
valueProducer.prepareFirstBucket();
@@ -762,7 +747,8 @@ TEST_P(ValueMetricProducerTest_PartialBucket, TestPulledValue) {
data->push_back(CreateRepeatedValueLogEvent(tagId, partialBucketSplitTimeNs, 120));
return true;
}));
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
valueProducer.prepareFirstBucket();
@@ -813,7 +799,8 @@ TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, bucketStartTimeNs, _, _))
.WillOnce(Return(true));
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
valueProducer.prepareFirstBucket();
@@ -851,7 +838,8 @@ TEST_P(ValueMetricProducerTest_PartialBucket, TestPulledValueWhileConditionFalse
return true;
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
@@ -875,6 +863,7 @@ TEST_P(ValueMetricProducerTest_PartialBucket, TestPulledValueWhileConditionFalse
{bucketStartTimeNs}, {partialBucketSplitTimeNs});
EXPECT_FALSE(valueProducer->mCondition);
}
+
TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
@@ -887,7 +876,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
valueProducer.prepareFirstBucket();
@@ -931,9 +920,9 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
- eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
- pullerManager);
+ ValueMetricProducer valueProducer(kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard,
+ logEventMatcherIndex, eventMatcherWizard, -1,
+ bucketStartTimeNs, bucketStartTimeNs, pullerManager);
valueProducer.prepareFirstBucket();
valueProducer.mCondition = ConditionState::kFalse;
@@ -1001,9 +990,11 @@ TEST(ValueMetricProducerTest, TestAnomalyDetection) {
atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
- logEventMatcherIndex, eventMatcherWizard, -1 /*not pulled*/,
- bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, {},
+ wizard, logEventMatcherIndex, eventMatcherWizard,
+ -1 /*not pulled*/, bucketStartTimeNs, bucketStartTimeNs,
+ pullerManager);
valueProducer.prepareFirstBucket();
sp<AnomalyTracker> anomalyTracker = valueProducer.addAnomalyTracker(alert, alarmMonitor);
@@ -1158,7 +1149,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) {
return true;
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
@@ -1229,7 +1221,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) {
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
@@ -1300,7 +1293,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMin) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
valueProducer.prepareFirstBucket();
@@ -1344,7 +1337,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateMax) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
valueProducer.prepareFirstBucket();
@@ -1387,7 +1380,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateAvg) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
valueProducer.prepareFirstBucket();
@@ -1435,7 +1428,7 @@ TEST(ValueMetricProducerTest, TestPushedAggregateSum) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
valueProducer.prepareFirstBucket();
@@ -1479,7 +1472,7 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
valueProducer.prepareFirstBucket();
@@ -1551,7 +1544,7 @@ TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
pullerManager);
valueProducer.prepareFirstBucket();
@@ -1944,7 +1937,8 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfB
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
// has one slice
@@ -1979,7 +1973,8 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange) {
.WillOnce(Return(false));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
@@ -2023,7 +2018,8 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullFailBeforeConditionChange) {
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
// Don't directly set mCondition; the real code never does that. Go through regular code path
// to avoid unexpected behaviors.
@@ -2057,9 +2053,8 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded) {
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
-
- valueProducer->mCondition = ConditionState::kFalse;
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
// Max delay is set to 0 so pull will exceed max delay.
valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
@@ -2080,9 +2075,9 @@ TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate) {
EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)).WillOnce(Return());
EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)).WillRepeatedly(Return());
- ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
- eventMatcherWizard, tagId, bucket2StartTimeNs,
- bucket2StartTimeNs, pullerManager);
+ ValueMetricProducer valueProducer(kConfigKey, metric, 0, {ConditionState::kUnknown}, wizard,
+ logEventMatcherIndex, eventMatcherWizard, tagId,
+ bucket2StartTimeNs, bucket2StartTimeNs, pullerManager);
valueProducer.prepareFirstBucket();
valueProducer.mCondition = ConditionState::kFalse;
@@ -2105,9 +2100,8 @@ TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange) {
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
-
- valueProducer->mCondition = ConditionState::kFalse;
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
valueProducer->mHasGlobalBase = false;
valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
@@ -2142,9 +2136,8 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenOneConditionFailed
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
-
- valueProducer->mCondition = ConditionState::kTrue;
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kTrue);
// Bucket start.
vector<shared_ptr<LogEvent>> allData;
@@ -2218,8 +2211,8 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenGuardRailHit) {
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
- valueProducer->mCondition = ConditionState::kFalse;
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
valueProducer->onConditionChanged(true, bucketStartTimeNs + 2);
EXPECT_EQ(true, valueProducer->mCurrentBucketIsSkipped);
@@ -2283,9 +2276,8 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenInitialPullFailed)
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
-
- valueProducer->mCondition = ConditionState::kTrue;
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kTrue);
// Bucket start.
vector<shared_ptr<LogEvent>> allData;
@@ -2363,9 +2355,8 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenLastPullFailed) {
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
-
- valueProducer->mCondition = ConditionState::kTrue;
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kTrue);
// Bucket start.
vector<shared_ptr<LogEvent>> allData;
@@ -2468,7 +2459,8 @@ TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged) {
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
@@ -2518,7 +2510,8 @@ TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onBucketBoundary) {
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
valueProducer->onConditionChanged(false, bucketStartTimeNs + 11);
@@ -2566,7 +2559,8 @@ TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries) {
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
@@ -2673,8 +2667,8 @@ TEST(ValueMetricProducerTest, TestBucketBoundariesOnConditionChange) {
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
- valueProducer->mCondition = ConditionState::kUnknown;
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(
+ pullerManager, metric, ConditionState::kUnknown);
valueProducer->onConditionChanged(false, bucketStartTimeNs);
ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
@@ -2814,7 +2808,8 @@ TEST(ValueMetricProducerTest, TestDataIsNotUpdatedWhenNoConditionChanged) {
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
valueProducer->onConditionChanged(false, bucketStartTimeNs + 10);
@@ -2866,7 +2861,8 @@ TEST(ValueMetricProducerTest, TestBucketInvalidIfGlobalBaseIsNotSet) {
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
valueProducer->onConditionChanged(true, bucket2StartTimeNs + 10);
vector<shared_ptr<LogEvent>> allData;
@@ -2911,7 +2907,7 @@ TEST(ValueMetricProducerTest, TestPullNeededFastDump) {
return true;
}));
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
valueProducer.prepareFirstBucket();
@@ -2949,7 +2945,7 @@ TEST(ValueMetricProducerTest, TestFastDumpWithoutCurrentBucket) {
return true;
}));
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
valueProducer.prepareFirstBucket();
@@ -3002,7 +2998,7 @@ TEST(ValueMetricProducerTest, TestPullNeededNoTimeConstraints) {
return true;
}));
- ValueMetricProducer valueProducer(kConfigKey, metric, -1, wizard, logEventMatcherIndex,
+ ValueMetricProducer valueProducer(kConfigKey, metric, -1, {}, wizard, logEventMatcherIndex,
eventMatcherWizard, tagId, bucketStartTimeNs,
bucketStartTimeNs, pullerManager);
valueProducer.prepareFirstBucket();
@@ -3058,8 +3054,8 @@ TEST(ValueMetricProducerTest, TestPulledData_noDiff_withMultipleConditionChanges
return true;
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
- valueProducer->mCondition = ConditionState::kFalse;
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
valueProducer->onConditionChanged(false, bucketStartTimeNs + 50);
@@ -3099,8 +3095,8 @@ TEST(ValueMetricProducerTest, TestPulledData_noDiff_bucketBoundaryTrue) {
return true;
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
- valueProducer->mCondition = ConditionState::kFalse;
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
@@ -3124,8 +3120,8 @@ TEST(ValueMetricProducerTest, TestPulledData_noDiff_bucketBoundaryFalse) {
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
- valueProducer->mCondition = ConditionState::kFalse;
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
// Now the alarm is delivered. Condition is off though.
vector<shared_ptr<LogEvent>> allData;
@@ -3152,8 +3148,8 @@ TEST(ValueMetricProducerTest, TestPulledData_noDiff_withFailure) {
}))
.WillOnce(Return(false));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
- valueProducer->mCondition = ConditionState::kFalse;
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
valueProducer->onConditionChanged(false, bucketStartTimeNs + 50);
@@ -3191,7 +3187,8 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenDumpReportRequeste
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
// Condition change event.
valueProducer->onConditionChanged(true, bucketStartTimeNs + 20);
@@ -3236,7 +3233,8 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenConditionEventWron
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
// Condition change event.
valueProducer->onConditionChanged(true, bucketStartTimeNs + 50);
@@ -3298,7 +3296,8 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenAccumulateEventWro
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
// Condition change event.
valueProducer->onConditionChanged(true, bucketStartTimeNs + 50);
@@ -3363,8 +3362,8 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenConditionUnknown)
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithNoInitialCondition(pullerManager,
- metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(
+ pullerManager, metric, ConditionState::kUnknown);
// Condition change event.
valueProducer->onConditionChanged(true, bucketStartTimeNs + 50);
@@ -3413,7 +3412,8 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenPullFailed) {
.WillOnce(Return(false));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
// Condition change event.
valueProducer->onConditionChanged(true, bucketStartTimeNs + 50);
@@ -3468,7 +3468,8 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenMultipleBucketsSki
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
// Condition change event.
valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
@@ -3542,7 +3543,8 @@ TEST(ValueMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) {
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
// Condition change event.
valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
@@ -3579,7 +3581,8 @@ TEST(ValueMetricProducerTest_BucketDrop, TestBucketDropWhenDataUnavailable) {
sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(
+ pullerManager, metric, ConditionState::kUnknown);
// Check dump report.
ProtoOutputStream output;
@@ -3632,7 +3635,8 @@ TEST(ValueMetricProducerTest_BucketDrop, TestBucketDropWhenForceBucketSplitBefor
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric,
+ ConditionState::kFalse);
// Condition changed event
int64_t conditionChangeTimeNs = bucketStartTimeNs + 10;
@@ -3687,8 +3691,8 @@ TEST(ValueMetricProducerTest_BucketDrop, TestMultipleBucketDropEvents) {
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithNoInitialCondition(pullerManager,
- metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(
+ pullerManager, metric, ConditionState::kUnknown);
// Condition change event.
valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
@@ -3756,8 +3760,8 @@ TEST(ValueMetricProducerTest_BucketDrop, TestMaxBucketDropEvents) {
}));
sp<ValueMetricProducer> valueProducer =
- ValueMetricProducerTestHelper::createValueProducerWithNoInitialCondition(pullerManager,
- metric);
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(
+ pullerManager, metric, ConditionState::kUnknown);
// First condition change event causes guardrail to be reached.
valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
@@ -4718,6 +4722,46 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) {
EXPECT_EQ(5, report.value_metrics().data(4).bucket_info(1).values(0).value_long());
}
+/*
+ * Test bucket splits when condition is unknown.
+ */
+TEST(ValueMetricProducerTest, TestForcedBucketSplitWhenConditionUnknownSkipsBucket) {
+ ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
+
+ sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+
+ sp<ValueMetricProducer> valueProducer =
+ ValueMetricProducerTestHelper::createValueProducerWithCondition(
+ pullerManager, metric,
+ ConditionState::kUnknown);
+
+ // App update event.
+ int64_t appUpdateTimeNs = bucketStartTimeNs + 1000;
+ valueProducer->notifyAppUpgrade(appUpdateTimeNs);
+
+ // Check dump report.
+ ProtoOutputStream output;
+ std::set<string> strSet;
+ int64_t dumpReportTimeNs = bucketStartTimeNs + 10000000000; // 10 seconds
+ valueProducer->onDumpReport(dumpReportTimeNs, false /* include current buckets */, true,
+ NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output);
+
+ StatsLogReport report = outputStreamToProto(&output);
+ EXPECT_TRUE(report.has_value_metrics());
+ ASSERT_EQ(0, report.value_metrics().data_size());
+ ASSERT_EQ(1, report.value_metrics().skipped_size());
+
+ EXPECT_EQ(NanoToMillis(bucketStartTimeNs),
+ report.value_metrics().skipped(0).start_bucket_elapsed_millis());
+ EXPECT_EQ(NanoToMillis(appUpdateTimeNs),
+ report.value_metrics().skipped(0).end_bucket_elapsed_millis());
+ ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size());
+
+ auto dropEvent = report.value_metrics().skipped(0).drop_event(0);
+ EXPECT_EQ(BucketDropReason::NO_DATA, dropEvent.drop_reason());
+ EXPECT_EQ(NanoToMillis(appUpdateTimeNs), dropEvent.drop_time_millis());
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index ed0ea556dc9d..ac00a042b79e 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -520,6 +520,12 @@ public abstract class AccessibilityService extends Service {
*/
public static final int GLOBAL_ACTION_ACCESSIBILITY_SHORTCUT = 13;
+ /**
+ * Action to show Launcher's all apps.
+ * @hide
+ */
+ public static final int GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS = 14;
+
private static final String LOG_TAG = "AccessibilityService";
/**
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 87fc8fe392f0..6c10682adc0e 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -5568,7 +5568,7 @@ public class Activity extends ContextThemeWrapper
options = transferSpringboardActivityOptions(options);
String resolvedType = null;
if (fillInIntent != null) {
- fillInIntent.migrateExtraStreamToClipData();
+ fillInIntent.migrateExtraStreamToClipData(this);
fillInIntent.prepareToLeaveProcess(this);
resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
}
@@ -5823,7 +5823,7 @@ public class Activity extends ContextThemeWrapper
if (referrer != null) {
intent.putExtra(Intent.EXTRA_REFERRER, referrer);
}
- intent.migrateExtraStreamToClipData();
+ intent.migrateExtraStreamToClipData(this);
intent.prepareToLeaveProcess(this);
result = ActivityTaskManager.getService()
.startActivity(mMainThread.getApplicationThread(), getBasePackageName(),
@@ -5894,7 +5894,7 @@ public class Activity extends ContextThemeWrapper
@Nullable Bundle options) {
if (mParent == null) {
try {
- intent.migrateExtraStreamToClipData();
+ intent.migrateExtraStreamToClipData(this);
intent.prepareToLeaveProcess(this);
return ActivityTaskManager.getService()
.startNextMatchingActivity(mToken, intent, options);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index cffa59c06a53..108b9eec34fb 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3252,18 +3252,56 @@ public final class ActivityThread extends ClientTransactionHandler {
@Override
public void handleFixedRotationAdjustments(@NonNull IBinder token,
@Nullable FixedRotationAdjustments fixedRotationAdjustments) {
- final Consumer<DisplayAdjustments> override = fixedRotationAdjustments != null
- ? displayAdjustments -> displayAdjustments.setFixedRotationAdjustments(
- fixedRotationAdjustments)
- : null;
+ handleFixedRotationAdjustments(token, fixedRotationAdjustments, null /* overrideConfig */);
+ }
+
+ /**
+ * Applies the rotation adjustments to override display information in resources belong to the
+ * provided token. If the token is activity token, the adjustments also apply to application
+ * because the appearance of activity is usually more sensitive to the application resources.
+ *
+ * @param token The token to apply the adjustments.
+ * @param fixedRotationAdjustments The information to override the display adjustments of
+ * corresponding resources. If it is null, the exiting override
+ * will be cleared.
+ * @param overrideConfig The override configuration of activity. It is used to override
+ * application configuration. If it is non-null, it means the token is
+ * confirmed as activity token. Especially when launching new activity,
+ * {@link #mActivities} hasn't put the new token.
+ */
+ private void handleFixedRotationAdjustments(@NonNull IBinder token,
+ @Nullable FixedRotationAdjustments fixedRotationAdjustments,
+ @Nullable Configuration overrideConfig) {
+ // The element of application configuration override is set only if the application
+ // adjustments are needed, because activity already has its own override configuration.
+ final Configuration[] appConfigOverride;
+ final Consumer<DisplayAdjustments> override;
+ if (fixedRotationAdjustments != null) {
+ appConfigOverride = new Configuration[1];
+ override = displayAdjustments -> {
+ displayAdjustments.setFixedRotationAdjustments(fixedRotationAdjustments);
+ if (appConfigOverride[0] != null) {
+ displayAdjustments.getConfiguration().updateFrom(appConfigOverride[0]);
+ }
+ };
+ } else {
+ appConfigOverride = null;
+ override = null;
+ }
if (!mResourcesManager.overrideTokenDisplayAdjustments(token, override)) {
// No resources are associated with the token.
return;
}
- if (mActivities.get(token) == null) {
- // Only apply the override to application for activity token because the appearance of
- // activity is usually more sensitive to the application resources.
- return;
+ if (overrideConfig == null) {
+ final ActivityClientRecord r = mActivities.get(token);
+ if (r == null) {
+ // It is not an activity token. Nothing to do for application.
+ return;
+ }
+ overrideConfig = r.overrideConfig;
+ }
+ if (appConfigOverride != null) {
+ appConfigOverride[0] = overrideConfig;
}
// Apply the last override to application resources for compatibility. Because the Resources
@@ -3503,7 +3541,8 @@ public final class ActivityThread extends ClientTransactionHandler {
// The rotation adjustments must be applied before creating the activity, so the activity
// can get the adjusted display info during creation.
if (r.mPendingFixedRotationAdjustments != null) {
- handleFixedRotationAdjustments(r.token, r.mPendingFixedRotationAdjustments);
+ handleFixedRotationAdjustments(r.token, r.mPendingFixedRotationAdjustments,
+ r.overrideConfig);
r.mPendingFixedRotationAdjustments = null;
}
@@ -7388,6 +7427,10 @@ public final class ActivityThread extends ClientTransactionHandler {
}
}
+ public Bundle getCoreSettings() {
+ return mCoreSettings;
+ }
+
public int getIntCoreSetting(String key, int defaultValue) {
synchronized (mResourcesManager) {
if (mCoreSettings != null) {
@@ -7397,6 +7440,18 @@ public final class ActivityThread extends ClientTransactionHandler {
}
}
+ /**
+ * Get the string value of the given key from core settings.
+ */
+ public String getStringCoreSetting(String key, String defaultValue) {
+ synchronized (mResourcesManager) {
+ if (mCoreSettings != null) {
+ return mCoreSettings.getString(key, defaultValue);
+ }
+ return defaultValue;
+ }
+ }
+
float getFloatCoreSetting(String key, float defaultValue) {
synchronized (mResourcesManager) {
if (mCoreSettings != null) {
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 6bd8fd7c6ecf..6f8233d5de9b 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -139,6 +139,10 @@ public class ApplicationPackageManager extends PackageManager {
public static final String APP_PERMISSION_BUTTON_ALLOW_ALWAYS =
"app_permission_button_allow_always";
+ // Name of the package which the permission controller's resources are in.
+ public static final String PERMISSION_CONTROLLER_RESOURCE_PACKAGE =
+ "com.android.permissioncontroller";
+
private final Object mLock = new Object();
@GuardedBy("mLock")
@@ -893,8 +897,7 @@ public class ApplicationPackageManager extends PackageManager {
mContext.createPackageContext(permissionController, 0);
int textId = context.getResources().getIdentifier(APP_PERMISSION_BUTTON_ALLOW_ALWAYS,
- "string", "com.android.permissioncontroller");
-// permissionController); STOPSHIP b/147434671
+ "string", PERMISSION_CONTROLLER_RESOURCE_PACKAGE);
if (textId != 0) {
return context.getText(textId);
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 48160e475d50..86a3579effe1 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1087,7 +1087,7 @@ class ContextImpl extends Context {
try {
String resolvedType = null;
if (fillInIntent != null) {
- fillInIntent.migrateExtraStreamToClipData();
+ fillInIntent.migrateExtraStreamToClipData(this);
fillInIntent.prepareToLeaveProcess(this);
resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
}
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 2d06ee8d06bc..b68639eb9ac6 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -216,4 +216,14 @@ oneway interface ITaskStackListener {
* in {@link android.content.pm.ActivityInfo}.
*/
void onTaskRequestedOrientationChanged(int taskId, int requestedOrientation);
+
+ /**
+ * Called when a rotation is about to start on the foreground activity.
+ * This applies for:
+ * * free sensor rotation
+ * * forced rotation
+ * * rotation settings set through adb command line
+ * * rotation that occurs when rotation tile is toggled in quick settings
+ */
+ void onActivityRotation();
}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index e233adeb3f65..721525d9af9d 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1718,7 +1718,7 @@ public class Instrumentation {
}
}
try {
- intent.migrateExtraStreamToClipData();
+ intent.migrateExtraStreamToClipData(who);
intent.prepareToLeaveProcess(who);
int result = ActivityTaskManager.getService().startActivity(whoThread,
who.getBasePackageName(), who.getAttributionTag(), intent,
@@ -1788,7 +1788,7 @@ public class Instrumentation {
try {
String[] resolvedTypes = new String[intents.length];
for (int i=0; i<intents.length; i++) {
- intents[i].migrateExtraStreamToClipData();
+ intents[i].migrateExtraStreamToClipData(who);
intents[i].prepareToLeaveProcess(who);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(who.getContentResolver());
}
@@ -1857,7 +1857,7 @@ public class Instrumentation {
}
}
try {
- intent.migrateExtraStreamToClipData();
+ intent.migrateExtraStreamToClipData(who);
intent.prepareToLeaveProcess(who);
int result = ActivityTaskManager.getService().startActivity(whoThread,
who.getBasePackageName(), who.getAttributionTag(), intent,
@@ -1924,7 +1924,7 @@ public class Instrumentation {
}
}
try {
- intent.migrateExtraStreamToClipData();
+ intent.migrateExtraStreamToClipData(who);
intent.prepareToLeaveProcess(who);
int result = ActivityTaskManager.getService().startActivityAsUser(whoThread,
who.getBasePackageName(), who.getAttributionTag(), intent,
@@ -1970,7 +1970,7 @@ public class Instrumentation {
}
}
try {
- intent.migrateExtraStreamToClipData();
+ intent.migrateExtraStreamToClipData(who);
intent.prepareToLeaveProcess(who);
int result = ActivityTaskManager.getService()
.startActivityAsCaller(whoThread, who.getBasePackageName(), intent,
@@ -2017,7 +2017,7 @@ public class Instrumentation {
}
}
try {
- intent.migrateExtraStreamToClipData();
+ intent.migrateExtraStreamToClipData(who);
intent.prepareToLeaveProcess(who);
int result = appTask.startActivity(whoThread.asBinder(), who.getBasePackageName(),
who.getAttributionTag(), intent,
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 10f7835b3d69..f9b48e710148 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -38,6 +38,7 @@ import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.os.FileUtils;
+import android.os.GraphicsEnvironment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Process;
@@ -46,6 +47,7 @@ import android.os.StrictMode;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
+import android.provider.Settings;
import android.security.net.config.NetworkSecurityConfigProvider;
import android.sysprop.VndkProperties;
import android.text.TextUtils;
@@ -824,6 +826,32 @@ public final class LoadedApk {
final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
+ if (mActivityThread != null) {
+ final String gpuDebugApp = mActivityThread.getStringCoreSetting(
+ Settings.Global.GPU_DEBUG_APP, "");
+ if (!gpuDebugApp.isEmpty() && mPackageName.equals(gpuDebugApp)) {
+
+ // The current application is used to debug, attempt to get the debug layers.
+ try {
+ // Get the ApplicationInfo from PackageManager so that metadata fields present.
+ final ApplicationInfo ai = ActivityThread.getPackageManager()
+ .getApplicationInfo(mPackageName, PackageManager.GET_META_DATA,
+ UserHandle.myUserId());
+ final String debugLayerPath = GraphicsEnvironment.getInstance()
+ .getDebugLayerPathsFromSettings(mActivityThread.getCoreSettings(),
+ ActivityThread.getPackageManager(), mPackageName, ai);
+ if (debugLayerPath != null) {
+ libraryPermittedPath += File.pathSeparator + debugLayerPath;
+ }
+ } catch (RemoteException e) {
+ // Unlikely to fail for applications, but in case of failure, something is wrong
+ // inside the system server, hence just skip.
+ Slog.e(ActivityThread.TAG,
+ "RemoteException when fetching debug layer paths for: " + mPackageName);
+ }
+ }
+ }
+
// If we're not asked to include code, we construct a classloader that has
// no code path included. We still need to set up the library search paths
// and permitted path because NativeActivity relies on it (it attempts to
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index e8ce92db62ad..980fdb87f3fb 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -7625,9 +7625,8 @@ public class Notification implements Parcelable
}
boolean isConversationLayout = mConversationType != CONVERSATION_TYPE_LEGACY;
boolean isImportantConversation = mConversationType == CONVERSATION_TYPE_IMPORTANT;
- Icon largeIcon = isConversationLayout && mShortcutIcon != null
- ? mShortcutIcon
- : mBuilder.mN.mLargeIcon;
+ Icon conversationIcon = mShortcutIcon;
+ Icon largeIcon = mBuilder.mN.mLargeIcon;
TemplateBindResult bindResult = new TemplateBindResult();
StandardTemplateParams p = mBuilder.mParams.reset()
.hasProgress(false)
@@ -7671,6 +7670,8 @@ public class Notification implements Parcelable
contentView.setCharSequence(R.id.status_bar_latest_event_content,
"setConversationTitle", conversationTitle);
if (isConversationLayout) {
+ contentView.setIcon(R.id.status_bar_latest_event_content,
+ "setConversationIcon", conversationIcon);
contentView.setBoolean(R.id.status_bar_latest_event_content,
"setIsImportantConversation", isImportantConversation);
}
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 792f840638a9..cd352e141994 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -351,7 +351,7 @@ public final class PendingIntent implements Parcelable {
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
try {
- intent.migrateExtraStreamToClipData();
+ intent.migrateExtraStreamToClipData(context);
intent.prepareToLeaveProcess(context);
IIntentSender target =
ActivityManager.getService().getIntentSenderWithFeature(
@@ -377,7 +377,7 @@ public final class PendingIntent implements Parcelable {
String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
context.getContentResolver()) : null;
try {
- intent.migrateExtraStreamToClipData();
+ intent.migrateExtraStreamToClipData(context);
intent.prepareToLeaveProcess(context);
IIntentSender target =
ActivityManager.getService().getIntentSenderWithFeature(
@@ -491,7 +491,7 @@ public final class PendingIntent implements Parcelable {
String packageName = context.getPackageName();
String[] resolvedTypes = new String[intents.length];
for (int i=0; i<intents.length; i++) {
- intents[i].migrateExtraStreamToClipData();
+ intents[i].migrateExtraStreamToClipData(context);
intents[i].prepareToLeaveProcess(context);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
}
@@ -517,7 +517,7 @@ public final class PendingIntent implements Parcelable {
String packageName = context.getPackageName();
String[] resolvedTypes = new String[intents.length];
for (int i=0; i<intents.length; i++) {
- intents[i].migrateExtraStreamToClipData();
+ intents[i].migrateExtraStreamToClipData(context);
intents[i].prepareToLeaveProcess(context);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
}
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index 5d8daf88a8de..843d1c7414f8 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -199,4 +199,8 @@ public abstract class TaskStackListener extends ITaskStackListener.Stub {
@Override
public void onTaskRequestedOrientationChanged(int taskId, int requestedOrientation) {
}
+
+ @Override
+ public void onActivityRotation() {
+ }
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index baaf8f76797a..be3cfeff729e 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1884,6 +1884,9 @@ public class Intent implements Parcelable, Cloneable {
/**
* Activity action: Launch UI to manage auto-revoke state.
+ *
+ * This is equivalent to Intent#ACTION_APPLICATION_DETAILS_SETTINGS
+ *
* <p>
* Input: {@link Intent#setData data} should be a {@code package}-scheme {@link Uri} with
* a package name, whose auto-revoke state will be reviewed (mandatory).
@@ -11272,6 +11275,19 @@ public class Intent implements Parcelable, Cloneable {
* @hide
*/
public boolean migrateExtraStreamToClipData() {
+ return migrateExtraStreamToClipData(AppGlobals.getInitialApplication());
+ }
+
+ /**
+ * Migrate any {@link #EXTRA_STREAM} in {@link #ACTION_SEND} and
+ * {@link #ACTION_SEND_MULTIPLE} to {@link ClipData}. Also inspects nested
+ * intents in {@link #ACTION_CHOOSER}.
+ *
+ * @param context app context
+ * @return Whether any contents were migrated.
+ * @hide
+ */
+ public boolean migrateExtraStreamToClipData(Context context) {
// Refuse to touch if extras already parcelled
if (mExtras != null && mExtras.isParcelled()) return false;
@@ -11289,7 +11305,7 @@ public class Intent implements Parcelable, Cloneable {
try {
final Intent intent = getParcelableExtra(EXTRA_INTENT);
if (intent != null) {
- migrated |= intent.migrateExtraStreamToClipData();
+ migrated |= intent.migrateExtraStreamToClipData(context);
}
} catch (ClassCastException e) {
}
@@ -11299,7 +11315,7 @@ public class Intent implements Parcelable, Cloneable {
for (int i = 0; i < intents.length; i++) {
final Intent intent = (Intent) intents[i];
if (intent != null) {
- migrated |= intent.migrateExtraStreamToClipData();
+ migrated |= intent.migrateExtraStreamToClipData(context);
}
}
}
@@ -11362,13 +11378,17 @@ public class Intent implements Parcelable, Cloneable {
} catch (ClassCastException e) {
}
} else if (isImageCaptureIntent()) {
- final Uri output;
+ Uri output;
try {
output = getParcelableExtra(MediaStore.EXTRA_OUTPUT);
} catch (ClassCastException e) {
return false;
}
+
if (output != null) {
+ output = maybeConvertFileToContentUri(context, output);
+ putExtra(MediaStore.EXTRA_OUTPUT, output);
+
setClipData(ClipData.newRawUri("", output));
addFlags(FLAG_GRANT_WRITE_URI_PERMISSION|FLAG_GRANT_READ_URI_PERMISSION);
return true;
@@ -11378,6 +11398,23 @@ public class Intent implements Parcelable, Cloneable {
return false;
}
+ private Uri maybeConvertFileToContentUri(Context context, Uri uri) {
+ if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())
+ && context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.R) {
+ File file = new File(uri.getPath());
+ try {
+ if (!file.exists()) file.createNewFile();
+ uri = MediaStore.scanFile(context.getContentResolver(), new File(uri.getPath()));
+ if (uri != null) {
+ return uri;
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Ignoring failure to create file " + file, e);
+ }
+ }
+ return uri;
+ }
+
/**
* Convert the dock state to a human readable format.
* @hide
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index b1f88693d9c0..bd02210259b8 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -245,6 +245,13 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
public float minAspectRatio;
/**
+ * Indicates that the activity works well with size changes like display changing size.
+ *
+ * @hide
+ */
+ public boolean supportsSizeChanges;
+
+ /**
* Name of the VrListenerService component to run for this activity.
* @see android.R.attr#enableVrMode
* @hide
@@ -1013,6 +1020,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
colorMode = orig.colorMode;
maxAspectRatio = orig.maxAspectRatio;
minAspectRatio = orig.minAspectRatio;
+ supportsSizeChanges = orig.supportsSizeChanges;
}
/**
@@ -1188,6 +1196,9 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
if (minAspectRatio != 0) {
pw.println(prefix + "minAspectRatio=" + minAspectRatio);
}
+ if (supportsSizeChanges) {
+ pw.println(prefix + "supportsSizeChanges=true");
+ }
super.dumpBack(pw, prefix, dumpFlags);
}
@@ -1232,6 +1243,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
dest.writeInt(colorMode);
dest.writeFloat(maxAspectRatio);
dest.writeFloat(minAspectRatio);
+ dest.writeBoolean(supportsSizeChanges);
}
/**
@@ -1350,6 +1362,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
colorMode = source.readInt();
maxAspectRatio = source.readFloat();
minAspectRatio = source.readFloat();
+ supportsSizeChanges = source.readBoolean();
}
/**
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index ed75504529b9..fc4ccd072e75 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1449,6 +1449,13 @@ public class PackageInstaller {
/** {@hide} */
public static final int UID_UNKNOWN = -1;
+ /**
+ * This value is derived from the maximum file name length. No package above this limit
+ * can ever be successfully installed on the device.
+ * @hide
+ */
+ public static final int MAX_PACKAGE_NAME_LENGTH = 255;
+
/** {@hide} */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public int mode = MODE_INVALID;
@@ -1642,6 +1649,8 @@ public class PackageInstaller {
/**
* Optionally set a label representing the app being installed.
+ *
+ * This value will be trimmed to the first 1000 characters.
*/
public void setAppLabel(@Nullable CharSequence appLabel) {
this.appLabel = (appLabel != null) ? appLabel.toString() : null;
@@ -1711,7 +1720,8 @@ public class PackageInstaller {
*
* <p>Initially, all restricted permissions are whitelisted but you can change
* which ones are whitelisted by calling this method or the corresponding ones
- * on the {@link PackageManager}.
+ * on the {@link PackageManager}. Only soft or hard restricted permissions on the current
+ * Android version are supported and any invalid entries will be removed.
*
* @see PackageManager#addWhitelistedRestrictedPermission(String, String, int)
* @see PackageManager#removeWhitelistedRestrictedPermission(String, String, int)
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index f354bdb5a08b..65ce1e7ef079 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -49,8 +49,16 @@ import java.util.Objects;
* in the implementation of Parcelable in subclasses.
*/
public class PackageItemInfo {
- /** The maximum length of a safe label, in characters */
- private static final int MAX_SAFE_LABEL_LENGTH = 50000;
+
+ /**
+ * The maximum length of a safe label, in characters
+ *
+ * TODO(b/157997155): It may make sense to expose this publicly so that apps can check for the
+ * value and truncate the strings/use a different label, without having to hardcode and make
+ * assumptions about the value.
+ * @hide
+ */
+ public static final int MAX_SAFE_LABEL_LENGTH = 1000;
/** @hide */
public static final float DEFAULT_MAX_LABEL_SIZE_PX = 500f;
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 0d8618fe7e86..c8dd4d9d9d51 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -207,6 +207,7 @@ public class PackageParser {
public static final String TAG_USES_SPLIT = "uses-split";
public static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect";
+ public static final String METADATA_SUPPORTS_SIZE_CHANGES = "android.supports_size_changes";
public static final String METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY =
"android.activity_window_layout_affinity";
@@ -3897,6 +3898,7 @@ public class PackageParser {
// every activity info has had a chance to set it from its attributes.
setMaxAspectRatio(owner);
setMinAspectRatio(owner);
+ setSupportsSizeChanges(owner);
if (hasDomainURLs(owner)) {
owner.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
@@ -4694,6 +4696,18 @@ public class PackageParser {
}
}
+ private void setSupportsSizeChanges(Package owner) {
+ final boolean supportsSizeChanges = owner.mAppMetaData != null
+ && owner.mAppMetaData.getBoolean(METADATA_SUPPORTS_SIZE_CHANGES, false);
+
+ for (Activity activity : owner.activities) {
+ if (supportsSizeChanges || (activity.metaData != null
+ && activity.metaData.getBoolean(METADATA_SUPPORTS_SIZE_CHANGES, false))) {
+ activity.info.supportsSizeChanges = true;
+ }
+ }
+ }
+
/**
* @param configChanges The bit mask of configChanges fetched from AndroidManifest.xml.
* @param recreateOnConfigChanges The bit mask recreateOnConfigChanges fetched from
@@ -4863,6 +4877,7 @@ public class PackageParser {
info.resizeMode = target.info.resizeMode;
info.maxAspectRatio = target.info.maxAspectRatio;
info.minAspectRatio = target.info.minAspectRatio;
+ info.supportsSizeChanges = target.info.supportsSizeChanges;
info.requestedVrComponent = target.info.requestedVrComponent;
info.directBootAware = target.info.directBootAware;
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
index 216b3bb5de8e..e4507483c08f 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -445,6 +445,7 @@ public class PackageInfoWithoutStateUtils {
ai.maxAspectRatio = maxAspectRatio != null ? maxAspectRatio : 0f;
Float minAspectRatio = a.getMinAspectRatio();
ai.minAspectRatio = minAspectRatio != null ? minAspectRatio : 0f;
+ ai.supportsSizeChanges = a.getSupportsSizeChanges();
ai.requestedVrComponent = a.getRequestedVrComponent();
ai.rotationAnimation = a.getRotationAnimation();
ai.colorMode = a.getColorMode();
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 5a7947503d5c..317107829623 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -1912,6 +1912,7 @@ public class ParsingPackageUtils {
// every activity info has had a chance to set it from its attributes.
setMaxAspectRatio(pkg);
setMinAspectRatio(pkg);
+ setSupportsSizeChanges(pkg);
pkg.setHasDomainUrls(hasDomainURLs(pkg));
@@ -2366,6 +2367,23 @@ public class ParsingPackageUtils {
}
}
+ private void setSupportsSizeChanges(ParsingPackage pkg) {
+ final Bundle appMetaData = pkg.getMetaData();
+ final boolean supportsSizeChanges = appMetaData != null
+ && appMetaData.getBoolean(PackageParser.METADATA_SUPPORTS_SIZE_CHANGES, false);
+
+ List<ParsedActivity> activities = pkg.getActivities();
+ int activitiesSize = activities.size();
+ for (int index = 0; index < activitiesSize; index++) {
+ ParsedActivity activity = activities.get(index);
+ if (supportsSizeChanges || (activity.getMetaData() != null
+ && activity.getMetaData().getBoolean(
+ PackageParser.METADATA_SUPPORTS_SIZE_CHANGES, false))) {
+ activity.setSupportsSizeChanges(true);
+ }
+ }
+ }
+
private static ParseResult<ParsingPackage> parseOverlay(ParseInput input, ParsingPackage pkg,
Resources res, XmlResourceParser parser) {
TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestResourceOverlay);
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivity.java b/core/java/android/content/pm/parsing/component/ParsedActivity.java
index 4c93d0950388..19150283d71e 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivity.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivity.java
@@ -73,6 +73,8 @@ public class ParsedActivity extends ParsedMainComponent {
@Nullable
private Float minAspectRatio;
+ private boolean supportsSizeChanges;
+
@Nullable
String requestedVrComponent;
int rotationAnimation = -1;
@@ -101,6 +103,7 @@ public class ParsedActivity extends ParsedMainComponent {
this.resizeMode = other.resizeMode;
this.maxAspectRatio = other.maxAspectRatio;
this.minAspectRatio = other.minAspectRatio;
+ this.supportsSizeChanges = other.supportsSizeChanges;
this.requestedVrComponent = other.requestedVrComponent;
this.rotationAnimation = other.rotationAnimation;
this.colorMode = other.colorMode;
@@ -165,6 +168,7 @@ public class ParsedActivity extends ParsedMainComponent {
alias.resizeMode = target.resizeMode;
alias.maxAspectRatio = target.maxAspectRatio;
alias.minAspectRatio = target.minAspectRatio;
+ alias.supportsSizeChanges = target.supportsSizeChanges;
alias.requestedVrComponent = target.requestedVrComponent;
alias.directBootAware = target.directBootAware;
alias.setProcessName(target.getProcessName());
@@ -217,6 +221,11 @@ public class ParsedActivity extends ParsedMainComponent {
return this;
}
+ public ParsedActivity setSupportsSizeChanges(boolean supportsSizeChanges) {
+ this.supportsSizeChanges = supportsSizeChanges;
+ return this;
+ }
+
public ParsedActivity setFlags(int flags) {
this.flags = flags;
return this;
@@ -279,6 +288,7 @@ public class ParsedActivity extends ParsedMainComponent {
dest.writeInt(this.resizeMode);
dest.writeValue(this.maxAspectRatio);
dest.writeValue(this.minAspectRatio);
+ dest.writeBoolean(this.supportsSizeChanges);
dest.writeString(this.requestedVrComponent);
dest.writeInt(this.rotationAnimation);
dest.writeInt(this.colorMode);
@@ -315,6 +325,7 @@ public class ParsedActivity extends ParsedMainComponent {
this.resizeMode = in.readInt();
this.maxAspectRatio = (Float) in.readValue(Float.class.getClassLoader());
this.minAspectRatio = (Float) in.readValue(Float.class.getClassLoader());
+ this.supportsSizeChanges = in.readBoolean();
this.requestedVrComponent = in.readString();
this.rotationAnimation = in.readInt();
this.colorMode = in.readInt();
@@ -414,6 +425,10 @@ public class ParsedActivity extends ParsedMainComponent {
return minAspectRatio;
}
+ public boolean getSupportsSizeChanges() {
+ return supportsSizeChanges;
+ }
+
@Nullable
public String getRequestedVrComponent() {
return requestedVrComponent;
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
index f64560a14832..fb8fd74545c7 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
@@ -302,7 +302,14 @@ public class ParsedActivityUtils {
}
String permission = array.getNonConfigurationString(permissionAttr, 0);
- activity.setPermission(permission != null ? permission : pkg.getPermission());
+ if (isAlias) {
+ // An alias will override permissions to allow referencing an Activity through its alias
+ // without needing the original permission. If an alias needs the same permission,
+ // it must be re-declared.
+ activity.setPermission(permission);
+ } else {
+ activity.setPermission(permission != null ? permission : pkg.getPermission());
+ }
final boolean setExported = array.hasValue(exportedAttr);
if (setExported) {
diff --git a/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java b/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java
index b37b61757053..6811e06fbe7e 100644
--- a/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java
@@ -20,7 +20,10 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.PackageManager;
import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.parsing.ParsingUtils;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
@@ -29,9 +32,6 @@ import android.text.TextUtils;
import android.util.TypedValue;
import com.android.internal.annotations.VisibleForTesting;
-import android.content.pm.parsing.ParsingPackageUtils;
-import android.content.pm.parsing.result.ParseInput;
-import android.content.pm.parsing.result.ParseResult;
/** @hide */
class ParsedComponentUtils {
@@ -60,16 +60,27 @@ class ParsedComponentUtils {
component.setName(className);
component.setPackageName(packageName);
- if (useRoundIcon) {
- component.icon = array.getResourceId(roundIconAttr, 0);
+ int roundIconVal = useRoundIcon ? array.getResourceId(roundIconAttr, 0) : 0;
+ if (roundIconVal != 0) {
+ component.icon = roundIconVal;
+ component.nonLocalizedLabel = null;
+ } else {
+ int iconVal = array.getResourceId(iconAttr, 0);
+ if (iconVal != 0) {
+ component.icon = iconVal;
+ component.nonLocalizedLabel = null;
+ }
}
- if (component.icon == 0) {
- component.icon = array.getResourceId(iconAttr, 0);
+ int logoVal = array.getResourceId(logoAttr, 0);
+ if (logoVal != 0) {
+ component.logo = logoVal;
}
- component.logo = array.getResourceId(logoAttr, 0);
- component.banner = array.getResourceId(bannerAttr, 0);
+ int bannerVal = array.getResourceId(bannerAttr, 0);
+ if (bannerVal != 0) {
+ component.banner = bannerVal;
+ }
if (descriptionAttr != null) {
component.descriptionRes = array.getResourceId(descriptionAttr, 0);
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index 8d472da1fb7c..570cc2c11738 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -116,22 +116,25 @@ public class BiometricManager {
/**
* Any biometric (e.g. fingerprint, iris, or face) on the device that meets or exceeds the
- * requirements for <strong>Strong</strong>, as defined by the Android CDD.
+ * requirements for <strong>Tier 3</strong> (formerly <strong>Strong</strong>), as defined
+ * by the Android CDD.
*/
int BIOMETRIC_STRONG = 0x000F;
/**
* Any biometric (e.g. fingerprint, iris, or face) on the device that meets or exceeds the
- * requirements for <strong>Weak</strong>, as defined by the Android CDD.
+ * requirements for <strong>Tier 2</strong> (formerly <strong>Weak</strong>), as defined by
+ * the Android CDD.
*
* <p>Note that this is a superset of {@link #BIOMETRIC_STRONG} and is defined such that
- * <code>BIOMETRIC_STRONG | BIOMETRIC_WEAK == BIOMETRIC_WEAK</code>.
+ * {@code BIOMETRIC_STRONG | BIOMETRIC_WEAK == BIOMETRIC_WEAK}.
*/
int BIOMETRIC_WEAK = 0x00FF;
/**
* Any biometric (e.g. fingerprint, iris, or face) on the device that meets or exceeds the
- * requirements for <strong>Convenience</strong>, as defined by the Android CDD.
+ * requirements for <strong>Tier 1</strong> (formerly <strong>Convenience</strong>), as
+ * defined by the Android CDD.
*
* <p>This constant is intended for use by {@link android.provider.DeviceConfig} to adjust
* the reported strength of a biometric sensor. It is not a valid parameter for any of the
diff --git a/core/java/android/hardware/hdmi/HdmiClient.java b/core/java/android/hardware/hdmi/HdmiClient.java
index bff8c39e8c56..a921215c6133 100644
--- a/core/java/android/hardware/hdmi/HdmiClient.java
+++ b/core/java/android/hardware/hdmi/HdmiClient.java
@@ -1,6 +1,7 @@
package android.hardware.hdmi;
import android.annotation.NonNull;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.hardware.hdmi.HdmiControlManager.VendorCommandListener;
import android.os.RemoteException;
@@ -84,7 +85,8 @@ public abstract class HdmiClient {
* @param hasVendorId {@code true} if the command type will be &lt;Vendor Command With ID&gt;.
* {@code false} if the command will be &lt;Vendor Command&gt;
*/
- public void sendVendorCommand(int targetAddress, byte[] params, boolean hasVendorId) {
+ public void sendVendorCommand(int targetAddress,
+ @SuppressLint("MissingNullability") byte[] params, boolean hasVendorId) {
try {
mService.sendVendorCommand(getDeviceType(), targetAddress, params, hasVendorId);
} catch (RemoteException e) {
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 6bc962b67576..1ce9b9c71c0e 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -18,6 +18,7 @@ package android.hardware.hdmi;
import static com.android.internal.os.RoSystemProperties.PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -28,8 +29,10 @@ import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.os.Binder;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.util.ArrayMap;
@@ -40,6 +43,7 @@ import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.Executor;
/**
* The {@link HdmiControlManager} class is used to send HDMI control messages
@@ -54,6 +58,7 @@ import java.util.Objects;
* @hide
*/
@SystemApi
+@TestApi
@SystemService(Context.HDMI_CONTROL_SERVICE)
@RequiresFeature(PackageManager.FEATURE_HDMI_CEC)
public final class HdmiControlManager {
@@ -136,6 +141,8 @@ public final class HdmiControlManager {
public static final int POWER_STATUS_TRANSIENT_TO_ON = 2;
public static final int POWER_STATUS_TRANSIENT_TO_STANDBY = 3;
+ /** @hide */
+ @SystemApi
@IntDef ({
RESULT_SUCCESS,
RESULT_TIMEOUT,
@@ -397,8 +404,11 @@ public final class HdmiControlManager {
* See {@link HdmiDeviceInfo#DEVICE_PLAYBACK}
* See {@link HdmiDeviceInfo#DEVICE_TV}
* See {@link HdmiDeviceInfo#DEVICE_AUDIO_SYSTEM}
+ *
+ * @hide
*/
@Nullable
+ @SystemApi
@SuppressLint("Doclava125")
public HdmiClient getClient(int type) {
if (mService == null) {
@@ -427,8 +437,11 @@ public final class HdmiControlManager {
* system if the system is configured to host more than one type of HDMI-CEC logical devices.
*
* @return {@link HdmiPlaybackClient} instance. {@code null} on failure.
+ *
+ * @hide
*/
@Nullable
+ @SystemApi
@SuppressLint("Doclava125")
public HdmiPlaybackClient getPlaybackClient() {
return (HdmiPlaybackClient) getClient(HdmiDeviceInfo.DEVICE_PLAYBACK);
@@ -442,8 +455,11 @@ public final class HdmiControlManager {
* system if the system is configured to host more than one type of HDMI-CEC logical devices.
*
* @return {@link HdmiTvClient} instance. {@code null} on failure.
+ *
+ * @hide
*/
@Nullable
+ @SystemApi
@SuppressLint("Doclava125")
public HdmiTvClient getTvClient() {
return (HdmiTvClient) getClient(HdmiDeviceInfo.DEVICE_TV);
@@ -475,10 +491,8 @@ public final class HdmiControlManager {
* system if the system is configured to host more than one type of HDMI-CEC logical device.
*
* @return {@link HdmiSwitchClient} instance. {@code null} on failure.
- * @hide
*/
@Nullable
- @SystemApi
@SuppressLint("Doclava125")
public HdmiSwitchClient getSwitchClient() {
return (HdmiSwitchClient) getClient(HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH);
@@ -787,7 +801,10 @@ public final class HdmiControlManager {
/**
* Listener used to get hotplug event from HDMI port.
+ *
+ * @hide
*/
+ @SystemApi
public interface HotplugEventListener {
void onReceived(HdmiHotplugEvent event);
}
@@ -818,8 +835,29 @@ public final class HdmiControlManager {
mHdmiControlStatusChangeListeners = new ArrayMap<>();
/**
+ * Listener used to get the status of the HDMI CEC volume control feature (enabled/disabled).
+ * @hide
+ */
+ public interface HdmiCecVolumeControlFeatureListener {
+ /**
+ * Called when the HDMI Control (CEC) volume control feature is enabled/disabled.
+ *
+ * @param enabled status of HDMI CEC volume control feature
+ * @see {@link HdmiControlManager#setHdmiCecVolumeControlEnabled(boolean)} ()}
+ **/
+ void onHdmiCecVolumeControlFeature(boolean enabled);
+ }
+
+ private final ArrayMap<HdmiCecVolumeControlFeatureListener,
+ IHdmiCecVolumeControlFeatureListener>
+ mHdmiCecVolumeControlFeatureListeners = new ArrayMap<>();
+
+ /**
* Listener used to get vendor-specific commands.
+ *
+ * @hide
*/
+ @SystemApi
public interface VendorCommandListener {
/**
* Called when a vendor command is received.
@@ -858,7 +896,10 @@ public final class HdmiControlManager {
*
* @param listener {@link HotplugEventListener} instance
* @see HdmiControlManager#removeHotplugEventListener(HotplugEventListener)
+ *
+ * @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.HDMI_CEC)
public void addHotplugEventListener(HotplugEventListener listener) {
if (mService == null) {
@@ -882,7 +923,10 @@ public final class HdmiControlManager {
* Removes a listener to stop getting informed of {@link HdmiHotplugEvent}.
*
* @param listener {@link HotplugEventListener} instance to be removed
+ *
+ * @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.HDMI_CEC)
public void removeHotplugEventListener(HotplugEventListener listener) {
if (mService == null) {
@@ -979,4 +1023,76 @@ public final class HdmiControlManager {
};
}
+ /**
+ * Adds a listener to get informed of changes to the state of the HDMI CEC volume control
+ * feature.
+ *
+ * Upon adding a listener, the current state of the HDMI CEC volume control feature will be
+ * sent immediately.
+ *
+ * <p>To stop getting the notification,
+ * use {@link #removeHdmiCecVolumeControlFeatureListener(HdmiCecVolumeControlFeatureListener)}.
+ *
+ * @param listener {@link HdmiCecVolumeControlFeatureListener} instance
+ * @hide
+ * @see #removeHdmiCecVolumeControlFeatureListener(HdmiCecVolumeControlFeatureListener)
+ */
+ @RequiresPermission(android.Manifest.permission.HDMI_CEC)
+ public void addHdmiCecVolumeControlFeatureListener(@NonNull @CallbackExecutor Executor executor,
+ @NonNull HdmiCecVolumeControlFeatureListener listener) {
+ if (mService == null) {
+ Log.e(TAG, "HdmiControlService is not available");
+ return;
+ }
+ if (mHdmiCecVolumeControlFeatureListeners.containsKey(listener)) {
+ Log.e(TAG, "listener is already registered");
+ return;
+ }
+ IHdmiCecVolumeControlFeatureListener wrappedListener =
+ createHdmiCecVolumeControlFeatureListenerWrapper(executor, listener);
+ mHdmiCecVolumeControlFeatureListeners.put(listener, wrappedListener);
+ try {
+ mService.addHdmiCecVolumeControlFeatureListener(wrappedListener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Removes a listener to stop getting informed of changes to the state of the HDMI CEC volume
+ * control feature.
+ *
+ * @param listener {@link HdmiCecVolumeControlFeatureListener} instance to be removed
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.HDMI_CEC)
+ public void removeHdmiCecVolumeControlFeatureListener(
+ HdmiCecVolumeControlFeatureListener listener) {
+ if (mService == null) {
+ Log.e(TAG, "HdmiControlService is not available");
+ return;
+ }
+ IHdmiCecVolumeControlFeatureListener wrappedListener =
+ mHdmiCecVolumeControlFeatureListeners.remove(listener);
+ if (wrappedListener == null) {
+ Log.e(TAG, "tried to remove not-registered listener");
+ return;
+ }
+ try {
+ mService.removeHdmiCecVolumeControlFeatureListener(wrappedListener);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private IHdmiCecVolumeControlFeatureListener createHdmiCecVolumeControlFeatureListenerWrapper(
+ Executor executor, final HdmiCecVolumeControlFeatureListener listener) {
+ return new android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener.Stub() {
+ @Override
+ public void onHdmiCecVolumeControlFeature(boolean enabled) {
+ Binder.clearCallingIdentity();
+ executor.execute(() -> listener.onHdmiCecVolumeControlFeature(enabled));
+ }
+ };
+ }
}
diff --git a/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java b/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java
new file mode 100644
index 000000000000..02896351ea3a
--- /dev/null
+++ b/core/java/android/hardware/hdmi/HdmiControlServiceWrapper.java
@@ -0,0 +1,469 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.hdmi;
+
+import android.annotation.BinderThread;
+import android.annotation.NonNull;
+import android.annotation.TestApi;
+
+import java.util.List;
+
+/**
+ * A wrapper of the Binder interface that clients running in the application process
+ * will use to perform HDMI-CEC features by communicating with other devices
+ * on the bus.
+ *
+ * @hide
+ */
+@TestApi
+public final class HdmiControlServiceWrapper {
+
+ /** Pure CEC switch device type. */
+ public static final int DEVICE_PURE_CEC_SWITCH = HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH;
+
+ private List<HdmiPortInfo> mInfoList = null;
+ private int[] mTypes = null;
+
+ /**
+ * Create a new HdmiControlManager with the current HdmiControlService wrapper
+ *
+ * @return the created HdmiControlManager
+ */
+ @NonNull
+ public HdmiControlManager createHdmiControlManager() {
+ return new HdmiControlManager(mInterface);
+ }
+
+ private final IHdmiControlService mInterface = new IHdmiControlService.Stub() {
+
+ @Override
+ public int[] getSupportedTypes() {
+ return HdmiControlServiceWrapper.this.getSupportedTypes();
+ }
+
+ @Override
+ public HdmiDeviceInfo getActiveSource() {
+ return HdmiControlServiceWrapper.this.getActiveSource();
+ }
+
+ @Override
+ public void oneTouchPlay(IHdmiControlCallback callback) {
+ HdmiControlServiceWrapper.this.oneTouchPlay(callback);
+ }
+
+ @Override
+ public void queryDisplayStatus(IHdmiControlCallback callback) {
+ HdmiControlServiceWrapper.this.queryDisplayStatus(callback);
+ }
+
+ @Override
+ public void addHdmiControlStatusChangeListener(IHdmiControlStatusChangeListener listener) {
+ HdmiControlServiceWrapper.this.addHdmiControlStatusChangeListener(listener);
+ }
+
+ @Override
+ public void removeHdmiControlStatusChangeListener(
+ IHdmiControlStatusChangeListener listener) {
+ HdmiControlServiceWrapper.this.removeHdmiControlStatusChangeListener(listener);
+ }
+
+ @Override
+ public void addHotplugEventListener(IHdmiHotplugEventListener listener) {
+ HdmiControlServiceWrapper.this.addHotplugEventListener(listener);
+ }
+
+ @Override
+ public void removeHotplugEventListener(IHdmiHotplugEventListener listener) {
+ HdmiControlServiceWrapper.this.removeHotplugEventListener(listener);
+ }
+
+ @Override
+ public void addDeviceEventListener(IHdmiDeviceEventListener listener) {
+ HdmiControlServiceWrapper.this.addDeviceEventListener(listener);
+ }
+
+ @Override
+ public void deviceSelect(int deviceId, IHdmiControlCallback callback) {
+ HdmiControlServiceWrapper.this.deviceSelect(deviceId, callback);
+ }
+
+ @Override
+ public void portSelect(int portId, IHdmiControlCallback callback) {
+ HdmiControlServiceWrapper.this.portSelect(portId, callback);
+ }
+
+ @Override
+ public void sendKeyEvent(int deviceType, int keyCode, boolean isPressed) {
+ HdmiControlServiceWrapper.this.sendKeyEvent(deviceType, keyCode, isPressed);
+ }
+
+ @Override
+ public void sendVolumeKeyEvent(int deviceType, int keyCode, boolean isPressed) {
+ HdmiControlServiceWrapper.this.sendVolumeKeyEvent(deviceType, keyCode, isPressed);
+ }
+
+ @Override
+ public List<HdmiPortInfo> getPortInfo() {
+ return HdmiControlServiceWrapper.this.getPortInfo();
+ }
+
+ @Override
+ public boolean canChangeSystemAudioMode() {
+ return HdmiControlServiceWrapper.this.canChangeSystemAudioMode();
+ }
+
+ @Override
+ public boolean getSystemAudioMode() {
+ return HdmiControlServiceWrapper.this.getSystemAudioMode();
+ }
+
+ @Override
+ public int getPhysicalAddress() {
+ return HdmiControlServiceWrapper.this.getPhysicalAddress();
+ }
+
+ @Override
+ public void setSystemAudioMode(boolean enabled, IHdmiControlCallback callback) {
+ HdmiControlServiceWrapper.this.setSystemAudioMode(enabled, callback);
+ }
+
+ @Override
+ public void addSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) {
+ HdmiControlServiceWrapper.this.addSystemAudioModeChangeListener(listener);
+ }
+
+ @Override
+ public void removeSystemAudioModeChangeListener(
+ IHdmiSystemAudioModeChangeListener listener) {
+ HdmiControlServiceWrapper.this.removeSystemAudioModeChangeListener(listener);
+ }
+
+ @Override
+ public void setArcMode(boolean enabled) {
+ HdmiControlServiceWrapper.this.setArcMode(enabled);
+ }
+
+ @Override
+ public void setProhibitMode(boolean enabled) {
+ HdmiControlServiceWrapper.this.setProhibitMode(enabled);
+ }
+
+ @Override
+ public void setSystemAudioVolume(int oldIndex, int newIndex, int maxIndex) {
+ HdmiControlServiceWrapper.this.setSystemAudioVolume(oldIndex, newIndex, maxIndex);
+ }
+
+ @Override
+ public void setSystemAudioMute(boolean mute) {
+ HdmiControlServiceWrapper.this.setSystemAudioMute(mute);
+ }
+
+ @Override
+ public void setInputChangeListener(IHdmiInputChangeListener listener) {
+ HdmiControlServiceWrapper.this.setInputChangeListener(listener);
+ }
+
+ @Override
+ public List<HdmiDeviceInfo> getInputDevices() {
+ return HdmiControlServiceWrapper.this.getInputDevices();
+ }
+
+ @Override
+ public List<HdmiDeviceInfo> getDeviceList() {
+ return HdmiControlServiceWrapper.this.getDeviceList();
+ }
+
+ @Override
+ public void powerOffRemoteDevice(int logicalAddress, int powerStatus) {
+ HdmiControlServiceWrapper.this.powerOffRemoteDevice(logicalAddress, powerStatus);
+ }
+
+ @Override
+ public void powerOnRemoteDevice(int logicalAddress, int powerStatus) {
+ HdmiControlServiceWrapper.this.powerOnRemoteDevice(logicalAddress, powerStatus);
+ }
+
+ @Override
+ public void askRemoteDeviceToBecomeActiveSource(int physicalAddress) {
+ HdmiControlServiceWrapper.this.askRemoteDeviceToBecomeActiveSource(physicalAddress);
+ }
+
+ @Override
+ public void sendVendorCommand(int deviceType, int targetAddress, byte[] params,
+ boolean hasVendorId) {
+ HdmiControlServiceWrapper.this.sendVendorCommand(
+ deviceType, targetAddress, params, hasVendorId);
+ }
+
+ @Override
+ public void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) {
+ HdmiControlServiceWrapper.this.addVendorCommandListener(listener, deviceType);
+ }
+
+ @Override
+ public void sendStandby(int deviceType, int deviceId) {
+ HdmiControlServiceWrapper.this.sendStandby(deviceType, deviceId);
+ }
+
+ @Override
+ public void setHdmiRecordListener(IHdmiRecordListener callback) {
+ HdmiControlServiceWrapper.this.setHdmiRecordListener(callback);
+ }
+
+ @Override
+ public void startOneTouchRecord(int recorderAddress, byte[] recordSource) {
+ HdmiControlServiceWrapper.this.startOneTouchRecord(recorderAddress, recordSource);
+ }
+
+ @Override
+ public void stopOneTouchRecord(int recorderAddress) {
+ HdmiControlServiceWrapper.this.stopOneTouchRecord(recorderAddress);
+ }
+
+ @Override
+ public void startTimerRecording(int recorderAddress, int sourceType, byte[] recordSource) {
+ HdmiControlServiceWrapper.this.startTimerRecording(
+ recorderAddress, sourceType, recordSource);
+ }
+
+ @Override
+ public void clearTimerRecording(int recorderAddress, int sourceType, byte[] recordSource) {
+ HdmiControlServiceWrapper.this.clearTimerRecording(
+ recorderAddress, sourceType, recordSource);
+ }
+
+ @Override
+ public void sendMhlVendorCommand(int portId, int offset, int length, byte[] data) {
+ HdmiControlServiceWrapper.this.sendMhlVendorCommand(portId, offset, length, data);
+ }
+
+ @Override
+ public void addHdmiMhlVendorCommandListener(IHdmiMhlVendorCommandListener listener) {
+ HdmiControlServiceWrapper.this.addHdmiMhlVendorCommandListener(listener);
+ }
+
+ @Override
+ public void setStandbyMode(boolean isStandbyModeOn) {
+ HdmiControlServiceWrapper.this.setStandbyMode(isStandbyModeOn);
+ }
+
+ @Override
+ public void setHdmiCecVolumeControlEnabled(boolean isHdmiCecVolumeControlEnabled) {
+ HdmiControlServiceWrapper.this.setHdmiCecVolumeControlEnabled(
+ isHdmiCecVolumeControlEnabled);
+ }
+
+ @Override
+ public boolean isHdmiCecVolumeControlEnabled() {
+ return HdmiControlServiceWrapper.this.isHdmiCecVolumeControlEnabled();
+ }
+
+ @Override
+ public void reportAudioStatus(int deviceType, int volume, int maxVolume, boolean isMute) {
+ HdmiControlServiceWrapper.this.reportAudioStatus(deviceType, volume, maxVolume, isMute);
+ }
+
+ @Override
+ public void setSystemAudioModeOnForAudioOnlySource() {
+ HdmiControlServiceWrapper.this.setSystemAudioModeOnForAudioOnlySource();
+ }
+
+ @Override
+ public void addHdmiCecVolumeControlFeatureListener(
+ IHdmiCecVolumeControlFeatureListener listener) {
+ HdmiControlServiceWrapper.this.addHdmiCecVolumeControlFeatureListener(listener);
+ }
+
+ @Override
+ public void removeHdmiCecVolumeControlFeatureListener(
+ IHdmiCecVolumeControlFeatureListener listener) {
+ HdmiControlServiceWrapper.this.removeHdmiCecVolumeControlFeatureListener(listener);
+ }
+ };
+
+ @BinderThread
+ public void setPortInfo(@NonNull List<HdmiPortInfo> infoList) {
+ mInfoList = infoList;
+ }
+
+ @BinderThread
+ public void setDeviceTypes(@NonNull int[] types) {
+ mTypes = types;
+ }
+
+ /** @hide */
+ public List<HdmiPortInfo> getPortInfo() {
+ return mInfoList;
+ }
+
+ /** @hide */
+ public int[] getSupportedTypes() {
+ return mTypes;
+ }
+
+ /** @hide */
+ public HdmiDeviceInfo getActiveSource() {
+ return null;
+ }
+
+ /** @hide */
+ public void oneTouchPlay(IHdmiControlCallback callback) {}
+
+ /** @hide */
+ public void queryDisplayStatus(IHdmiControlCallback callback) {}
+
+ /** @hide */
+ public void addHdmiControlStatusChangeListener(IHdmiControlStatusChangeListener listener) {}
+
+ /** @hide */
+ public void removeHdmiControlStatusChangeListener(IHdmiControlStatusChangeListener listener) {}
+
+ /** @hide */
+ public void addHotplugEventListener(IHdmiHotplugEventListener listener) {}
+
+ /** @hide */
+ public void removeHotplugEventListener(IHdmiHotplugEventListener listener) {}
+
+ /** @hide */
+ public void addDeviceEventListener(IHdmiDeviceEventListener listener) {}
+
+ /** @hide */
+ public void deviceSelect(int deviceId, IHdmiControlCallback callback) {}
+
+ /** @hide */
+ public void portSelect(int portId, IHdmiControlCallback callback) {}
+
+ /** @hide */
+ public void sendKeyEvent(int deviceType, int keyCode, boolean isPressed) {}
+
+ /** @hide */
+ public void sendVolumeKeyEvent(int deviceType, int keyCode, boolean isPressed) {}
+
+ /** @hide */
+ public boolean canChangeSystemAudioMode() {
+ return true;
+ }
+
+ /** @hide */
+ public boolean getSystemAudioMode() {
+ return true;
+ }
+
+ /** @hide */
+ public int getPhysicalAddress() {
+ return 0xffff;
+ }
+
+ /** @hide */
+ public void setSystemAudioMode(boolean enabled, IHdmiControlCallback callback) {}
+
+ /** @hide */
+ public void addSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) {}
+
+ /** @hide */
+ public void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) {}
+
+ /** @hide */
+ public void setArcMode(boolean enabled) {}
+
+ /** @hide */
+ public void setProhibitMode(boolean enabled) {}
+
+ /** @hide */
+ public void setSystemAudioVolume(int oldIndex, int newIndex, int maxIndex) {}
+
+ /** @hide */
+ public void setSystemAudioMute(boolean mute) {}
+
+ /** @hide */
+ public void setInputChangeListener(IHdmiInputChangeListener listener) {}
+
+ /** @hide */
+ public List<HdmiDeviceInfo> getInputDevices() {
+ return null;
+ }
+
+ /** @hide */
+ public List<HdmiDeviceInfo> getDeviceList() {
+ return null;
+ }
+
+ /** @hide */
+ public void powerOffRemoteDevice(int logicalAddress, int powerStatus) {}
+
+ /** @hide */
+ public void powerOnRemoteDevice(int logicalAddress, int powerStatus) {}
+
+ /** @hide */
+ public void askRemoteDeviceToBecomeActiveSource(int physicalAddress) {}
+
+ /** @hide */
+ public void sendVendorCommand(int deviceType, int targetAddress, byte[] params,
+ boolean hasVendorId) {}
+
+ /** @hide */
+ public void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) {}
+
+ /** @hide */
+ public void sendStandby(int deviceType, int deviceId) {}
+
+ /** @hide */
+ public void setHdmiRecordListener(IHdmiRecordListener callback) {}
+
+ /** @hide */
+ public void startOneTouchRecord(int recorderAddress, byte[] recordSource) {}
+
+ /** @hide */
+ public void stopOneTouchRecord(int recorderAddress) {}
+
+ /** @hide */
+ public void startTimerRecording(int recorderAddress, int sourceType, byte[] recordSource) {}
+
+ /** @hide */
+ public void clearTimerRecording(int recorderAddress, int sourceType, byte[] recordSource) {}
+
+ /** @hide */
+ public void sendMhlVendorCommand(int portId, int offset, int length, byte[] data) {}
+
+ /** @hide */
+ public void addHdmiMhlVendorCommandListener(IHdmiMhlVendorCommandListener listener) {}
+
+ /** @hide */
+ public void setStandbyMode(boolean isStandbyModeOn) {}
+
+ /** @hide */
+ public void setHdmiCecVolumeControlEnabled(boolean isHdmiCecVolumeControlEnabled) {}
+
+ /** @hide */
+ public boolean isHdmiCecVolumeControlEnabled() {
+ return true;
+ }
+
+ /** @hide */
+ public void reportAudioStatus(int deviceType, int volume, int maxVolume, boolean isMute) {}
+
+ /** @hide */
+ public void setSystemAudioModeOnForAudioOnlySource() {}
+
+ /** @hide */
+ public void addHdmiCecVolumeControlFeatureListener(
+ IHdmiCecVolumeControlFeatureListener listener) {}
+
+ /** @hide */
+ public void removeHdmiCecVolumeControlFeatureListener(
+ IHdmiCecVolumeControlFeatureListener listener) {}
+}
diff --git a/core/java/android/hardware/hdmi/HdmiPortInfo.java b/core/java/android/hardware/hdmi/HdmiPortInfo.java
index 2623458aff5b..52c3628f358b 100644
--- a/core/java/android/hardware/hdmi/HdmiPortInfo.java
+++ b/core/java/android/hardware/hdmi/HdmiPortInfo.java
@@ -18,6 +18,7 @@ package android.hardware.hdmi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -28,6 +29,7 @@ import android.os.Parcelable;
* @hide
*/
@SystemApi
+@TestApi
public final class HdmiPortInfo implements Parcelable {
/** HDMI port type: Input */
public static final int PORT_INPUT = 0;
@@ -153,7 +155,9 @@ public final class HdmiPortInfo implements Parcelable {
* @param dest The Parcel in which the object should be written.
* @param flags Additional flags about how the object should be written.
* May be 0 or {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE}.
+ * @hide
*/
+ @SystemApi
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mId);
@@ -187,4 +191,9 @@ public final class HdmiPortInfo implements Parcelable {
&& mCecSupported == other.mCecSupported && mArcSupported == other.mArcSupported
&& mMhlSupported == other.mMhlSupported;
}
+
+ @Override
+ public int hashCode() {
+ return mId;
+ }
}
diff --git a/core/java/android/hardware/hdmi/HdmiSwitchClient.java b/core/java/android/hardware/hdmi/HdmiSwitchClient.java
index 7833653e41b0..913edfd0ebf4 100644
--- a/core/java/android/hardware/hdmi/HdmiSwitchClient.java
+++ b/core/java/android/hardware/hdmi/HdmiSwitchClient.java
@@ -18,6 +18,7 @@ package android.hardware.hdmi;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.hardware.hdmi.HdmiControlManager.ControlCallbackResult;
import android.os.Binder;
import android.os.RemoteException;
@@ -38,6 +39,7 @@ import java.util.concurrent.Executor;
* @hide
*/
@SystemApi
+@TestApi
public class HdmiSwitchClient extends HdmiClient {
private static final String TAG = "HdmiSwitchClient";
@@ -187,11 +189,8 @@ public class HdmiSwitchClient extends HdmiClient {
* <p>This returns an empty list when the current device does not have HDMI input.
*
* @return a list of {@link HdmiPortInfo}
- *
- * @hide
*/
@NonNull
- @SystemApi
public List<HdmiPortInfo> getPortInfo() {
try {
return mService.getPortInfo();
diff --git a/core/java/android/hardware/hdmi/IHdmiCecVolumeControlFeatureListener.aidl b/core/java/android/hardware/hdmi/IHdmiCecVolumeControlFeatureListener.aidl
new file mode 100644
index 000000000000..873438bb1d20
--- /dev/null
+++ b/core/java/android/hardware/hdmi/IHdmiCecVolumeControlFeatureListener.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.hdmi;
+
+/**
+ * Listener used to get the status of the HDMI CEC volume control feature (enabled/disabled).
+ * @hide
+ */
+oneway interface IHdmiCecVolumeControlFeatureListener {
+
+ /**
+ * Called when the HDMI Control (CEC) volume control feature is enabled/disabled.
+ *
+ * @param enabled status of HDMI CEC volume control feature
+ * @see {@link HdmiControlManager#setHdmiCecVolumeControlEnabled(boolean)} ()}
+ **/
+ void onHdmiCecVolumeControlFeature(boolean enabled);
+}
diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
index 3582a927ff46..4c724ef62ea9 100644
--- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl
+++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl
@@ -18,6 +18,7 @@ package android.hardware.hdmi;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiPortInfo;
+import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener;
import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.hdmi.IHdmiControlStatusChangeListener;
import android.hardware.hdmi.IHdmiDeviceEventListener;
@@ -44,6 +45,8 @@ interface IHdmiControlService {
void queryDisplayStatus(IHdmiControlCallback callback);
void addHdmiControlStatusChangeListener(IHdmiControlStatusChangeListener listener);
void removeHdmiControlStatusChangeListener(IHdmiControlStatusChangeListener listener);
+ void addHdmiCecVolumeControlFeatureListener(IHdmiCecVolumeControlFeatureListener listener);
+ void removeHdmiCecVolumeControlFeatureListener(IHdmiCecVolumeControlFeatureListener listener);
void addHotplugEventListener(IHdmiHotplugEventListener listener);
void removeHotplugEventListener(IHdmiHotplugEventListener listener);
void addDeviceEventListener(IHdmiDeviceEventListener listener);
diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java
index b0fca006d1e2..d7ca63a54987 100644
--- a/core/java/android/inputmethodservice/AbstractInputMethodService.java
+++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java
@@ -260,4 +260,10 @@ public abstract class AbstractInputMethodService extends Service
*/
public void notifyUserActionIfNecessary() {
}
+
+ /** @hide */
+ @Override
+ public final boolean isUiContext() {
+ return true;
+ }
}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 9ded22fb70c6..a3fd60e9d3b0 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -679,13 +679,14 @@ public final class NetworkCapabilities implements Parcelable {
*/
public void restrictCapabilitesForTestNetwork(int creatorUid) {
final long originalCapabilities = mNetworkCapabilities;
+ final long originalTransportTypes = mTransportTypes;
final NetworkSpecifier originalSpecifier = mNetworkSpecifier;
final int originalSignalStrength = mSignalStrength;
final int originalOwnerUid = getOwnerUid();
final int[] originalAdministratorUids = getAdministratorUids();
clearAll();
- // Reset the transports to only contain TRANSPORT_TEST.
- mTransportTypes = (1 << TRANSPORT_TEST);
+ mTransportTypes = (originalTransportTypes & TEST_NETWORKS_ALLOWED_TRANSPORTS)
+ | (1 << TRANSPORT_TEST);
mNetworkCapabilities = originalCapabilities & TEST_NETWORKS_ALLOWED_CAPABILITIES;
mNetworkSpecifier = originalSpecifier;
mSignalStrength = originalSignalStrength;
@@ -787,6 +788,13 @@ public final class NetworkCapabilities implements Parcelable {
};
/**
+ * Allowed transports on a test network, in addition to TRANSPORT_TEST.
+ */
+ private static final int TEST_NETWORKS_ALLOWED_TRANSPORTS = 1 << TRANSPORT_TEST
+ // Test ethernet networks can be created with EthernetManager#setIncludeTestInterfaces
+ | 1 << TRANSPORT_ETHERNET;
+
+ /**
* Adds the given transport type to this {@code NetworkCapability} instance.
* Multiple transports may be applied. Note that when searching
* for a network to satisfy a request, any listed in the request will satisfy the request.
diff --git a/core/java/android/os/AppZygote.java b/core/java/android/os/AppZygote.java
index 92574968e965..74b814ea4159 100644
--- a/core/java/android/os/AppZygote.java
+++ b/core/java/android/os/AppZygote.java
@@ -92,10 +92,9 @@ public class AppZygote {
@GuardedBy("mLock")
private void stopZygoteLocked() {
if (mZygote != null) {
- // Close the connection and kill the zygote process. This will not cause
- // child processes to be killed by itself.
mZygote.close();
- Process.killProcess(mZygote.getPid());
+ // use killProcessGroup() here, so we kill all untracked children as well.
+ Process.killProcessGroup(mZygoteUid, mZygote.getPid());
mZygote = null;
}
}
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 034e6a7a06c4..df58a6c636f5 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -22,6 +22,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -93,8 +94,8 @@ public class GraphicsEnvironment {
private static final int GAME_DRIVER_GLOBAL_OPT_IN_OFF = 3;
private ClassLoader mClassLoader;
- private String mLayerPath;
- private String mDebugLayerPath;
+ private String mLibrarySearchPaths;
+ private String mLibraryPermittedPaths;
/**
* Set up GraphicsEnvironment
@@ -185,118 +186,131 @@ public class GraphicsEnvironment {
}
/**
- * Store the layer paths available to the loader.
+ * Store the class loader for namespace lookup later.
*/
public void setLayerPaths(ClassLoader classLoader,
- String layerPath,
- String debugLayerPath) {
+ String searchPaths,
+ String permittedPaths) {
// We have to store these in the class because they are set up before we
// have access to the Context to properly set up GraphicsEnvironment
mClassLoader = classLoader;
- mLayerPath = layerPath;
- mDebugLayerPath = debugLayerPath;
+ mLibrarySearchPaths = searchPaths;
+ mLibraryPermittedPaths = permittedPaths;
+ }
+
+ /**
+ * Returns the debug layer paths from settings.
+ * Returns null if:
+ * 1) The application process is not debuggable or layer injection metadata flag is not
+ * true; Or
+ * 2) ENABLE_GPU_DEBUG_LAYERS is not true; Or
+ * 3) Package name is not equal to GPU_DEBUG_APP.
+ */
+ public String getDebugLayerPathsFromSettings(
+ Bundle coreSettings, IPackageManager pm, String packageName,
+ ApplicationInfo ai) {
+ if (!debugLayerEnabled(coreSettings, packageName, ai)) {
+ return null;
+ }
+ Log.i(TAG, "GPU debug layers enabled for " + packageName);
+ String debugLayerPaths = "";
+
+ // Grab all debug layer apps and add to paths.
+ final String gpuDebugLayerApps =
+ coreSettings.getString(Settings.Global.GPU_DEBUG_LAYER_APP, "");
+ if (!gpuDebugLayerApps.isEmpty()) {
+ Log.i(TAG, "GPU debug layer apps: " + gpuDebugLayerApps);
+ // If a colon is present, treat this as multiple apps, so Vulkan and GLES
+ // layer apps can be provided at the same time.
+ final String[] layerApps = gpuDebugLayerApps.split(":");
+ for (int i = 0; i < layerApps.length; i++) {
+ String paths = getDebugLayerAppPaths(pm, layerApps[i]);
+ if (!paths.isEmpty()) {
+ // Append the path so files placed in the app's base directory will
+ // override the external path
+ debugLayerPaths += paths + File.pathSeparator;
+ }
+ }
+ }
+ return debugLayerPaths;
}
/**
* Return the debug layer app's on-disk and in-APK lib directories
*/
- private static String getDebugLayerAppPaths(PackageManager pm, String app) {
+ private static String getDebugLayerAppPaths(IPackageManager pm, String packageName) {
final ApplicationInfo appInfo;
try {
- appInfo = pm.getApplicationInfo(app, PackageManager.MATCH_ALL);
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Debug layer app '" + app + "' not installed");
-
- return null;
+ appInfo = pm.getApplicationInfo(packageName, PackageManager.MATCH_ALL,
+ UserHandle.myUserId());
+ } catch (RemoteException e) {
+ return "";
+ }
+ if (appInfo == null) {
+ Log.w(TAG, "Debug layer app '" + packageName + "' not installed");
}
final String abi = chooseAbi(appInfo);
-
final StringBuilder sb = new StringBuilder();
sb.append(appInfo.nativeLibraryDir)
- .append(File.pathSeparator);
- sb.append(appInfo.sourceDir)
+ .append(File.pathSeparator)
+ .append(appInfo.sourceDir)
.append("!/lib/")
.append(abi);
final String paths = sb.toString();
-
if (DEBUG) Log.v(TAG, "Debug layer app libs: " + paths);
return paths;
}
+ private boolean debugLayerEnabled(Bundle coreSettings, String packageName, ApplicationInfo ai) {
+ // Only enable additional debug functionality if the following conditions are met:
+ // 1. App is debuggable or device is rooted or layer injection metadata flag is true
+ // 2. ENABLE_GPU_DEBUG_LAYERS is true
+ // 3. Package name is equal to GPU_DEBUG_APP
+ if (!isDebuggable() && !canInjectLayers(ai)) {
+ return false;
+ }
+ final int enable = coreSettings.getInt(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
+ if (enable == 0) {
+ return false;
+ }
+ final String gpuDebugApp = coreSettings.getString(Settings.Global.GPU_DEBUG_APP, "");
+ if (packageName == null
+ || (gpuDebugApp.isEmpty() || packageName.isEmpty())
+ || !gpuDebugApp.equals(packageName)) {
+ return false;
+ }
+ return true;
+ }
+
/**
* Set up layer search paths for all apps
- * If debuggable, check for additional debug settings
*/
private void setupGpuLayers(
Context context, Bundle coreSettings, PackageManager pm, String packageName,
ApplicationInfo ai) {
+ final boolean enabled = debugLayerEnabled(coreSettings, packageName, ai);
String layerPaths = "";
+ if (enabled) {
+ layerPaths = mLibraryPermittedPaths;
- // Only enable additional debug functionality if the following conditions are met:
- // 1. App is debuggable or device is rooted or layer injection metadata flag is true
- // 2. ENABLE_GPU_DEBUG_LAYERS is true
- // 3. Package name is equal to GPU_DEBUG_APP
+ final String layers = coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS);
+ Log.i(TAG, "Vulkan debug layer list: " + layers);
+ if (layers != null && !layers.isEmpty()) {
+ setDebugLayers(layers);
+ }
- if (isDebuggable() || canInjectLayers(ai)) {
-
- final int enable = coreSettings.getInt(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
-
- if (enable != 0) {
-
- final String gpuDebugApp = coreSettings.getString(Settings.Global.GPU_DEBUG_APP);
-
- if ((gpuDebugApp != null && packageName != null)
- && (!gpuDebugApp.isEmpty() && !packageName.isEmpty())
- && gpuDebugApp.equals(packageName)) {
- Log.i(TAG, "GPU debug layers enabled for " + packageName);
-
- // Prepend the debug layer path as a searchable path.
- // This will ensure debug layers added will take precedence over
- // the layers specified by the app.
- layerPaths = mDebugLayerPath + ":";
-
- // If there is a debug layer app specified, add its path.
- final String gpuDebugLayerApp =
- coreSettings.getString(Settings.Global.GPU_DEBUG_LAYER_APP);
-
- if (gpuDebugLayerApp != null && !gpuDebugLayerApp.isEmpty()) {
- Log.i(TAG, "GPU debug layer app: " + gpuDebugLayerApp);
- // If a colon is present, treat this as multiple apps, so Vulkan and GLES
- // layer apps can be provided at the same time.
- String[] layerApps = gpuDebugLayerApp.split(":");
- for (int i = 0; i < layerApps.length; i++) {
- String paths = getDebugLayerAppPaths(pm, layerApps[i]);
- if (paths != null) {
- // Append the path so files placed in the app's base directory will
- // override the external path
- layerPaths += paths + ":";
- }
- }
- }
-
- final String layers = coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS);
-
- Log.i(TAG, "Vulkan debug layer list: " + layers);
- if (layers != null && !layers.isEmpty()) {
- setDebugLayers(layers);
- }
-
- final String layersGLES =
- coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS_GLES);
-
- Log.i(TAG, "GLES debug layer list: " + layersGLES);
- if (layersGLES != null && !layersGLES.isEmpty()) {
- setDebugLayersGLES(layersGLES);
- }
- }
+ final String layersGLES =
+ coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS_GLES);
+ Log.i(TAG, "GLES debug layer list: " + layersGLES);
+ if (layersGLES != null && !layersGLES.isEmpty()) {
+ setDebugLayersGLES(layersGLES);
}
}
// Include the app's lib directory in all cases
- layerPaths += mLayerPath;
-
+ layerPaths += mLibrarySearchPaths;
setLayerPaths(mClassLoader, layerPaths);
}
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 02b822a99f2a..772845d4e683 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -817,6 +817,9 @@ public final class StrictMode {
/** @hide */
public @NonNull Builder permitActivityLeaks() {
+ synchronized (StrictMode.class) {
+ sExpectedActivityInstanceCount.clear();
+ }
return disable(DETECT_VM_ACTIVITY_LEAKS);
}
@@ -2586,8 +2589,10 @@ public final class StrictMode {
return;
}
+ // Use the instance count from InstanceTracker as initial value.
Integer expected = sExpectedActivityInstanceCount.get(klass);
- Integer newExpected = expected == null ? 1 : expected + 1;
+ Integer newExpected =
+ expected == null ? InstanceTracker.getInstanceCount(klass) + 1 : expected + 1;
sExpectedActivityInstanceCount.put(klass, newExpected);
}
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 7845200f4bf7..a8391c2b5461 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -4090,13 +4090,6 @@ public class UserManager {
public static int getMaxSupportedUsers() {
// Don't allow multiple users on certain builds
if (android.os.Build.ID.startsWith("JVP")) return 1;
- if (ActivityManager.isLowRamDeviceStatic()) {
- // Low-ram devices are Svelte. Most of the time they don't get multi-user.
- if ((Resources.getSystem().getConfiguration().uiMode & Configuration.UI_MODE_TYPE_MASK)
- != Configuration.UI_MODE_TYPE_TELEVISION) {
- return 1;
- }
- }
return SystemProperties.getInt("fw.max_users",
Resources.getSystem().getInteger(R.integer.config_multiuserMaximumUsers));
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 4ca48cb3e57c..e8806a03d00e 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1365,6 +1365,7 @@ public class StorageManager {
String[] packageNames = ActivityThread.getPackageManager().getPackagesForUid(
android.os.Process.myUid());
if (packageNames == null || packageNames.length <= 0) {
+ Log.w(TAG, "Missing package names; no storage volumes available");
return new StorageVolume[0];
}
packageName = packageNames[0];
@@ -1372,6 +1373,7 @@ public class StorageManager {
final int uid = ActivityThread.getPackageManager().getPackageUid(packageName,
PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId);
if (uid <= 0) {
+ Log.w(TAG, "Missing UID; no storage volumes available");
return new StorageVolume[0];
}
return storageManager.getVolumeList(uid, packageName, flags);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1b19e1290121..e10fceaa5bc7 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1778,6 +1778,15 @@ public final class Settings {
= "android.settings.NOTIFICATION_SETTINGS";
/**
+ * Activity Action: Show conversation settings.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_CONVERSATION_SETTINGS
+ = "android.settings.CONVERSATION_SETTINGS";
+
+ /**
* Activity Action: Show notification history screen.
*
* @hide
@@ -14245,15 +14254,6 @@ public final class Settings {
public static final String KERNEL_CPU_THREAD_READER = "kernel_cpu_thread_reader";
/**
- * Persistent user id that is last logged in to.
- *
- * They map to user ids, for example, 10, 11, 12.
- *
- * @hide
- */
- public static final String LAST_ACTIVE_USER_ID = "last_active_persistent_user_id";
-
- /**
* Whether we've enabled native flags health check on this device. Takes effect on
* reboot. The value "1" enables native flags health check; otherwise it's disabled.
* @hide
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index b34268d04238..a2489b9b68d9 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -4325,6 +4325,15 @@ public final class Telephony {
public static final String ETWS_WARNING_TYPE = "etws_warning_type";
/**
+ * ETWS (Earthquake and Tsunami Warning System) primary message or not (ETWS alerts only).
+ * <p>See {@link android.telephony.SmsCbEtwsInfo}</p>
+ * <P>Type: BOOLEAN</P>
+ *
+ * @hide // TODO: Unhide this for S.
+ */
+ public static final String ETWS_IS_PRIMARY = "etws_is_primary";
+
+ /**
* CMAS (Commercial Mobile Alert System) message class (CMAS alerts only).
* <p>See {@link android.telephony.SmsCbCmasInfo}</p>
* <P>Type: INTEGER</P>
@@ -4464,37 +4473,6 @@ public final class Telephony {
CMAS_URGENCY,
CMAS_CERTAINTY
};
-
- /**
- * Query columns for instantiating {@link android.telephony.SmsCbMessage} objects.
- * @hide
- */
- public static final String[] QUERY_COLUMNS_FWK = {
- _ID,
- SLOT_INDEX,
- SUBSCRIPTION_ID,
- GEOGRAPHICAL_SCOPE,
- PLMN,
- LAC,
- CID,
- SERIAL_NUMBER,
- SERVICE_CATEGORY,
- LANGUAGE_CODE,
- MESSAGE_BODY,
- MESSAGE_FORMAT,
- MESSAGE_PRIORITY,
- ETWS_WARNING_TYPE,
- CMAS_MESSAGE_CLASS,
- CMAS_CATEGORY,
- CMAS_RESPONSE_TYPE,
- CMAS_SEVERITY,
- CMAS_URGENCY,
- CMAS_CERTAINTY,
- RECEIVED_TIME,
- MESSAGE_BROADCASTED,
- GEOMETRIES,
- MAXIMUM_WAIT_TIME
- };
}
/**
diff --git a/core/java/android/service/autofill/InlineSuggestionRoot.java b/core/java/android/service/autofill/InlineSuggestionRoot.java
index c879653859d8..16c3f1d4e476 100644
--- a/core/java/android/service/autofill/InlineSuggestionRoot.java
+++ b/core/java/android/service/autofill/InlineSuggestionRoot.java
@@ -58,7 +58,9 @@ public class InlineSuggestionRoot extends FrameLayout {
case MotionEvent.ACTION_DOWN: {
mDownX = event.getX();
mDownY = event.getY();
- } break;
+ }
+ // Intentionally fall through to the next case so that when the window is obscured
+ // we transfer the touch to the remote IME window and don't handle it locally.
case MotionEvent.ACTION_MOVE: {
final float distance = MathUtils.dist(mDownX, mDownY,
diff --git a/core/java/android/service/controls/Control.java b/core/java/android/service/controls/Control.java
index d01bc2524332..8383072a48e3 100644
--- a/core/java/android/service/controls/Control.java
+++ b/core/java/android/service/controls/Control.java
@@ -73,25 +73,37 @@ public final class Control implements Parcelable {
})
public @interface Status {};
+ /**
+ * Reserved for use with the {@link StatelessBuilder}, and while loading. When state is
+ * requested via {@link ControlsProviderService#createPublisherFor}, use other status codes
+ * to indicate the proper device state.
+ */
public static final int STATUS_UNKNOWN = 0;
/**
- * The device corresponding to the {@link Control} is responding correctly.
+ * Used to indicate that the state of the device was successfully retrieved. This includes
+ * all scenarios where the device may have a warning for the user, such as "Lock jammed",
+ * or "Vacuum stuck". Any information for the user should be set through
+ * {@link StatefulBuilder#setStatusText}.
*/
public static final int STATUS_OK = 1;
/**
- * The device corresponding to the {@link Control} cannot be found or was removed.
+ * The device corresponding to the {@link Control} cannot be found or was removed. The user
+ * will be alerted and directed to the application to resolve.
*/
public static final int STATUS_NOT_FOUND = 2;
/**
- * The device corresponding to the {@link Control} is in an error state.
+ * Used to indicate that there was a temporary error while loading the device state. A default
+ * error message will be displayed in place of any custom text that was set through
+ * {@link StatefulBuilder#setStatusText}.
*/
public static final int STATUS_ERROR = 3;
/**
- * The {@link Control} is currently disabled.
+ * The {@link Control} is currently disabled. A default error message will be displayed in
+ * place of any custom text that was set through {@link StatefulBuilder#setStatusText}.
*/
public static final int STATUS_DISABLED = 4;
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 4a0dd870f797..0341b6d96b29 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -1311,7 +1311,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
throw new IllegalStateException("Can't call before onCreate()");
}
try {
- intent.migrateExtraStreamToClipData();
+ intent.migrateExtraStreamToClipData(mContext);
intent.prepareToLeaveProcess(mContext);
int res = mSystemService.startVoiceActivity(mToken, intent,
intent.resolveType(mContext.getContentResolver()),
@@ -1340,7 +1340,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
throw new IllegalStateException("Can't call before onCreate()");
}
try {
- intent.migrateExtraStreamToClipData();
+ intent.migrateExtraStreamToClipData(mContext);
intent.prepareToLeaveProcess(mContext);
int res = mSystemService.startAssistantActivity(mToken, intent,
intent.resolveType(mContext.getContentResolver()),
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index e4fbf9f0e187..9b293eb463e5 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -340,6 +340,10 @@ public class PhoneStateListener {
/**
* Listen for display info changed event.
*
+ * Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE
+ * READ_PHONE_STATE} or that the calling app has carrier privileges (see
+ * {@link TelephonyManager#hasCarrierPrivileges}).
+ *
* @see #onDisplayInfoChanged
*/
public static final int LISTEN_DISPLAY_INFO_CHANGED = 0x00100000;
diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java
index f6c72c4eefbc..55c527ba6fa6 100644
--- a/core/java/android/view/GestureDetector.java
+++ b/core/java/android/view/GestureDetector.java
@@ -16,6 +16,8 @@
package android.view;
+import static android.os.StrictMode.vmIncorrectContextUseEnabled;
+
import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS;
import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DOUBLE_TAP;
import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS;
@@ -26,9 +28,12 @@ import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFI
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Build;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.os.StrictMode;
import android.os.SystemClock;
+import android.util.Log;
import com.android.internal.util.FrameworkStatsLog;
@@ -228,6 +233,7 @@ public class GestureDetector {
}
}
+ private static final String TAG = GestureDetector.class.getSimpleName();
@UnsupportedAppUsage
private int mTouchSlopSquare;
private int mDoubleTapTouchSlopSquare;
@@ -378,7 +384,8 @@ public class GestureDetector {
* You may only use this constructor from a {@link android.os.Looper} thread.
* @see android.os.Handler#Handler()
*
- * @param context the application's context
+ * @param context An {@link android.app.Activity} or a {@link Context} created from
+ * {@link Context#createWindowContext(int, Bundle)}
* @param listener the listener invoked for all the callbacks, this must
* not be null. If the listener implements the {@link OnDoubleTapListener} or
* {@link OnContextClickListener} then it will also be set as the listener for
@@ -395,7 +402,8 @@ public class GestureDetector {
* thread associated with the supplied {@link android.os.Handler}.
* @see android.os.Handler#Handler()
*
- * @param context the application's context
+ * @param context An {@link android.app.Activity} or a {@link Context} created from
+ * {@link Context#createWindowContext(int, Bundle)}
* @param listener the listener invoked for all the callbacks, this must
* not be null. If the listener implements the {@link OnDoubleTapListener} or
* {@link OnContextClickListener} then it will also be set as the listener for
@@ -425,7 +433,8 @@ public class GestureDetector {
* thread associated with the supplied {@link android.os.Handler}.
* @see android.os.Handler#Handler()
*
- * @param context the application's context
+ * @param context An {@link android.app.Activity} or a {@link Context} created from
+ * {@link Context#createWindowContext(int, Bundle)}
* @param listener the listener invoked for all the callbacks, this must
* not be null.
* @param handler the handler to use for running deferred listener events.
@@ -456,6 +465,17 @@ public class GestureDetector {
mMaximumFlingVelocity = ViewConfiguration.getMaximumFlingVelocity();
mAmbiguousGestureMultiplier = ViewConfiguration.getAmbiguousGestureMultiplier();
} else {
+ if (!context.isUiContext() && vmIncorrectContextUseEnabled()) {
+ final String errorMessage =
+ "Tried to access UI constants from a non-visual Context.";
+ final String message = "GestureDetector must be accessed from Activity or other "
+ + "visual Context. Use an Activity or a Context created with "
+ + "Context#createWindowContext(int, Bundle), which are adjusted to the "
+ + "configuration and visual bounds of an area on screen.";
+ final Exception exception = new IllegalArgumentException(errorMessage);
+ StrictMode.onIncorrectContextUsed(message, exception);
+ Log.e(TAG, errorMessage + message, exception);
+ }
final ViewConfiguration configuration = ViewConfiguration.get(context);
touchSlop = configuration.getScaledTouchSlop();
doubleTapTouchSlop = configuration.getScaledDoubleTapTouchSlop();
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index d12ca73599f3..4e07a5f58de4 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -195,7 +195,10 @@ public class Surface implements Parcelable {
// From native_window.h. Keep these in sync.
/**
- * There are no inherent restrictions on the frame rate of this surface.
+ * There are no inherent restrictions on the frame rate of this surface. When the
+ * system selects a frame rate other than what the app requested, the app will be able
+ * to run at the system frame rate without requiring pull down. This value should be
+ * used when displaying game content, UIs, and anything that isn't video.
*/
public static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0;
@@ -205,7 +208,7 @@ public class Surface implements Parcelable {
* other than what the app requested, the app will need to do pull down or use some
* other technique to adapt to the system's frame rate. The user experience is likely
* to be worse (e.g. more frame stuttering) than it would be if the system had chosen
- * the app's requested frame rate.
+ * the app's requested frame rate. This value should be used for video content.
*/
public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 9109f50247e0..6f73e8985a8a 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -323,6 +323,14 @@ public final class SurfaceControl implements Parcelable {
public static final int CURSOR_WINDOW = 0x00002000;
/**
+ * Surface creation flag: Indicates the effect layer will not have a color fill on
+ * creation.
+ *
+ * @hide
+ */
+ public static final int NO_COLOR_FILL = 0x00004000;
+
+ /**
* Surface creation flag: Creates a normal surface.
* This is the default.
*
@@ -577,7 +585,7 @@ public final class SurfaceControl implements Parcelable {
throw new IllegalStateException(
"width and height must be positive or unset");
}
- if ((mWidth > 0 || mHeight > 0) && (isColorLayerSet() || isContainerLayerSet())) {
+ if ((mWidth > 0 || mHeight > 0) && (isEffectLayer() || isContainerLayer())) {
throw new IllegalStateException(
"Only buffer layers can set a valid buffer size.");
}
@@ -749,10 +757,27 @@ public final class SurfaceControl implements Parcelable {
}
/**
- * Indicate whether a 'ColorLayer' is to be constructed.
+ * Indicate whether an 'EffectLayer' is to be constructed.
+ *
+ * An effect layer behaves like a container layer by default but it can support
+ * color fill, shadows and/or blur. These layers will not have an associated buffer.
+ * When created, this layer has no effects set and will be transparent but the caller
+ * can render an effect by calling:
+ * - {@link Transaction#setColor(SurfaceControl, float[])}
+ * - {@link Transaction#setBackgroundBlurRadius(SurfaceControl, int)}
+ * - {@link Transaction#setShadowRadius(SurfaceControl, float)}
*
- * Color layers will not have an associated BufferQueue and will instead always render a
- * solid color (that is, solid before plane alpha). Currently that color is black.
+ * @hide
+ */
+ public Builder setEffectLayer() {
+ mFlags |= NO_COLOR_FILL;
+ unsetBufferSize();
+ return setFlags(FX_SURFACE_EFFECT, FX_SURFACE_MASK);
+ }
+
+ /**
+ * A convenience function to create an effect layer with a default color fill
+ * applied to it. Currently that color is black.
*
* @hide
*/
@@ -761,7 +786,7 @@ public final class SurfaceControl implements Parcelable {
return setFlags(FX_SURFACE_EFFECT, FX_SURFACE_MASK);
}
- private boolean isColorLayerSet() {
+ private boolean isEffectLayer() {
return (mFlags & FX_SURFACE_EFFECT) == FX_SURFACE_EFFECT;
}
@@ -786,7 +811,7 @@ public final class SurfaceControl implements Parcelable {
return setFlags(FX_SURFACE_CONTAINER, FX_SURFACE_MASK);
}
- private boolean isContainerLayerSet() {
+ private boolean isContainerLayer() {
return (mFlags & FX_SURFACE_CONTAINER) == FX_SURFACE_CONTAINER;
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index bd811fc1f052..a954f3631a01 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1200,8 +1200,10 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
}
if (mDeferredDestroySurfaceControl != null) {
- mTmpTransaction.remove(mDeferredDestroySurfaceControl).apply();
- mDeferredDestroySurfaceControl = null;
+ synchronized (mSurfaceControlLock) {
+ mTmpTransaction.remove(mDeferredDestroySurfaceControl).apply();
+ mDeferredDestroySurfaceControl = null;
+ }
}
runOnUiThread(this::performDrawFinished);
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 9b5b8824b0e6..a5ec4e900641 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -209,7 +209,11 @@ public class WindowlessWindowManager implements IWindowSession {
/** @hide */
protected SurfaceControl getSurfaceControl(View rootView) {
- final State s = mStateForWindow.get(rootView.getViewRootImpl().mWindow.asBinder());
+ final ViewRootImpl root = rootView.getViewRootImpl();
+ if (root == null) {
+ return null;
+ }
+ final State s = mStateForWindow.get(root.mWindow.asBinder());
if (s == null) {
return null;
}
diff --git a/core/java/android/view/autofill/AutofillId.java b/core/java/android/view/autofill/AutofillId.java
index b387a68dd8a3..68943bf2a83a 100644
--- a/core/java/android/view/autofill/AutofillId.java
+++ b/core/java/android/view/autofill/AutofillId.java
@@ -75,7 +75,10 @@ public final class AutofillId implements Parcelable {
/** @hide */
public static AutofillId withoutSession(@NonNull AutofillId id) {
final int flags = id.mFlags & ~FLAG_HAS_SESSION;
- return new AutofillId(flags, id.mViewId, id.mVirtualLongId, NO_SESSION);
+ final long virtualChildId =
+ ((id.mFlags & FLAG_IS_VIRTUAL_LONG) != 0) ? id.mVirtualLongId
+ : id.mVirtualIntId;
+ return new AutofillId(flags, id.mViewId, virtualChildId, NO_SESSION);
}
/** @hide */
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 7042f29fc4e4..4a6551176198 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -205,6 +205,8 @@ public class WebChromeClient {
* <p>Note that if the {@link WebChromeClient} is set to be {@code null},
* or if {@link WebChromeClient} is not set at all, the default dialog will
* be suppressed and Javascript execution will continue immediately.
+ * <p>Note that the default dialog does not inherit the {@link
+ * android.view.Display#FLAG_SECURE} flag from the parent window.
*
* @param view The WebView that initiated the callback.
* @param url The url of the page requesting the dialog.
@@ -240,6 +242,8 @@ public class WebChromeClient {
* or if {@link WebChromeClient} is not set at all, the default dialog will
* be suppressed and the default value of {@code false} will be returned to
* the JavaScript code immediately.
+ * <p>Note that the default dialog does not inherit the {@link
+ * android.view.Display#FLAG_SECURE} flag from the parent window.
*
* @param view The WebView that initiated the callback.
* @param url The url of the page requesting the dialog.
@@ -274,6 +278,8 @@ public class WebChromeClient {
* or if {@link WebChromeClient} is not set at all, the default dialog will
* be suppressed and {@code null} will be returned to the JavaScript code
* immediately.
+ * <p>Note that the default dialog does not inherit the {@link
+ * android.view.Display#FLAG_SECURE} flag from the parent window.
*
* @param view The WebView that initiated the callback.
* @param url The url of the page requesting the dialog.
@@ -308,6 +314,8 @@ public class WebChromeClient {
* <p>Note that if the {@link WebChromeClient} is set to be {@code null},
* or if {@link WebChromeClient} is not set at all, the default dialog will
* be suppressed and the navigation will be resumed immediately.
+ * <p>Note that the default dialog does not inherit the {@link
+ * android.view.Display#FLAG_SECURE} flag from the parent window.
*
* @param view The WebView that initiated the callback.
* @param url The url of the page requesting the dialog.
diff --git a/core/java/android/window/VirtualDisplayTaskEmbedder.java b/core/java/android/window/VirtualDisplayTaskEmbedder.java
index d2614da31ff9..9ccb4c172158 100644
--- a/core/java/android/window/VirtualDisplayTaskEmbedder.java
+++ b/core/java/android/window/VirtualDisplayTaskEmbedder.java
@@ -365,8 +365,8 @@ public class VirtualDisplayTaskEmbedder extends TaskEmbedder {
// Found the topmost stack on target display. Now check if the topmost task's
// description changed.
if (taskInfo.taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
- mHost.onTaskBackgroundColorChanged(VirtualDisplayTaskEmbedder.this,
- taskInfo.taskDescription.getBackgroundColor());
+ mHost.post(()-> mHost.onTaskBackgroundColorChanged(VirtualDisplayTaskEmbedder.this,
+ taskInfo.taskDescription.getBackgroundColor()));
}
}
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 9a732455113c..8be37e9e492d 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -264,6 +264,29 @@ public final class WindowContainerTransaction implements Parcelable {
return this;
}
+ /**
+ * Merges another WCT into this one.
+ * @param transfer When true, this will transfer everything from other potentially leaving
+ * other in an unusable state. When false, other is left alone, but
+ * SurfaceFlinger Transactions will not be merged.
+ * @hide
+ */
+ public void merge(WindowContainerTransaction other, boolean transfer) {
+ for (int i = 0, n = other.mChanges.size(); i < n; ++i) {
+ final IBinder key = other.mChanges.keyAt(i);
+ Change existing = mChanges.get(key);
+ if (existing == null) {
+ existing = new Change();
+ mChanges.put(key, existing);
+ }
+ existing.merge(other.mChanges.valueAt(i), transfer);
+ }
+ for (int i = 0, n = other.mHierarchyOps.size(); i < n; ++i) {
+ mHierarchyOps.add(transfer ? other.mHierarchyOps.get(i)
+ : new HierarchyOp(other.mHierarchyOps.get(i)));
+ }
+ }
+
/** @hide */
public Map<IBinder, Change> getChanges() {
return mChanges;
@@ -359,6 +382,41 @@ public final class WindowContainerTransaction implements Parcelable {
mActivityWindowingMode = in.readInt();
}
+ /**
+ * @param transfer When true, this will transfer other into this leaving other in an
+ * undefined state. Use this if you don't intend to use other. When false,
+ * SurfaceFlinger Transactions will not merge.
+ */
+ public void merge(Change other, boolean transfer) {
+ mConfiguration.setTo(other.mConfiguration, other.mConfigSetMask, other.mWindowSetMask);
+ mConfigSetMask |= other.mConfigSetMask;
+ mWindowSetMask |= other.mWindowSetMask;
+ if ((other.mChangeMask & CHANGE_FOCUSABLE) != 0) {
+ mFocusable = other.mFocusable;
+ }
+ if (transfer && (other.mChangeMask & CHANGE_BOUNDS_TRANSACTION) != 0) {
+ mBoundsChangeTransaction = other.mBoundsChangeTransaction;
+ other.mBoundsChangeTransaction = null;
+ }
+ if ((other.mChangeMask & CHANGE_PIP_CALLBACK) != 0) {
+ mPinnedBounds = transfer ? other.mPinnedBounds : new Rect(other.mPinnedBounds);
+ }
+ if ((other.mChangeMask & CHANGE_HIDDEN) != 0) {
+ mHidden = other.mHidden;
+ }
+ mChangeMask |= other.mChangeMask;
+ if (other.mActivityWindowingMode >= 0) {
+ mActivityWindowingMode = other.mActivityWindowingMode;
+ }
+ if (other.mWindowingMode >= 0) {
+ mWindowingMode = other.mWindowingMode;
+ }
+ if (other.mBoundsChangeSurfaceBounds != null) {
+ mBoundsChangeSurfaceBounds = transfer ? other.mBoundsChangeSurfaceBounds
+ : new Rect(other.mBoundsChangeSurfaceBounds);
+ }
+ }
+
public int getWindowingMode() {
return mWindowingMode;
}
@@ -522,6 +580,12 @@ public final class WindowContainerTransaction implements Parcelable {
mToTop = toTop;
}
+ public HierarchyOp(@NonNull HierarchyOp copy) {
+ mContainer = copy.mContainer;
+ mReparent = copy.mReparent;
+ mToTop = copy.mToTop;
+ }
+
protected HierarchyOp(Parcel in) {
mContainer = in.readStrongBinder();
mReparent = in.readStrongBinder();
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
index 1b7517840650..508deacb49d7 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityShortcutChooserActivity.java
@@ -23,6 +23,7 @@ import static com.android.internal.accessibility.common.ShortcutConstants.Shortc
import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.createEnableDialogContentView;
import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getInstalledTargets;
import static com.android.internal.accessibility.dialog.AccessibilityTargetHelper.getTargets;
+import static com.android.internal.accessibility.util.AccessibilityUtils.isUserSetupCompleted;
import android.annotation.Nullable;
import android.app.Activity;
@@ -61,18 +62,8 @@ public class AccessibilityShortcutChooserActivity extends Activity {
}
mTargets.addAll(getTargets(this, mShortcutType));
-
- final String selectDialogTitle =
- getString(R.string.accessibility_select_shortcut_menu_title);
mTargetAdapter = new ShortcutTargetAdapter(mTargets);
- mMenuDialog = new AlertDialog.Builder(this)
- .setTitle(selectDialogTitle)
- .setAdapter(mTargetAdapter, /* listener= */ null)
- .setPositiveButton(
- getString(R.string.edit_accessibility_shortcut_menu_button),
- /* listener= */ null)
- .setOnDismissListener(dialog -> finish())
- .create();
+ mMenuDialog = createMenuDialog();
mMenuDialog.setOnShowListener(dialog -> updateDialogListeners());
mMenuDialog.show();
}
@@ -154,4 +145,22 @@ public class AccessibilityShortcutChooserActivity extends Activity {
mMenuDialog.getListView().setOnItemClickListener(
isEditMenuMode ? this::onTargetChecked : this::onTargetSelected);
}
+
+ private AlertDialog createMenuDialog() {
+ final String dialogTitle =
+ getString(R.string.accessibility_select_shortcut_menu_title);
+
+ final AlertDialog.Builder builder = new AlertDialog.Builder(this)
+ .setTitle(dialogTitle)
+ .setAdapter(mTargetAdapter, /* listener= */ null)
+ .setOnDismissListener(dialog -> finish());
+
+ if (isUserSetupCompleted(this)) {
+ final String positiveButtonText =
+ getString(R.string.edit_accessibility_shortcut_menu_button);
+ builder.setPositiveButton(positiveButtonText, /* listener= */ null);
+ }
+
+ return builder.create();
+ }
}
diff --git a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
index 9ee0b0ea1891..4b4e20f9181b 100644
--- a/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
+++ b/core/java/com/android/internal/accessibility/util/AccessibilityUtils.java
@@ -156,4 +156,16 @@ public final class AccessibilityUtils {
return false;
}
+
+ /**
+ * Indicates whether the current user has completed setup via the setup wizard.
+ * {@link android.provider.Settings.Secure#USER_SETUP_COMPLETE}
+ *
+ * @return {@code true} if the setup is completed.
+ */
+ public static boolean isUserSetupCompleted(Context context) {
+ return Settings.Secure.getIntForUser(context.getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE, /* def= */ 0, UserHandle.USER_CURRENT)
+ != /* false */ 0;
+ }
}
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
index 493865ac563f..b723db287823 100644
--- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -151,6 +151,13 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
mOnProfileSelectedListener.onProfileSelected(position);
}
}
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ if (mOnProfileSelectedListener != null) {
+ mOnProfileSelectedListener.onProfilePageStateChanged(state);
+ }
+ }
});
viewPager.setAdapter(this);
viewPager.setCurrentItem(mCurrentPage);
@@ -606,6 +613,17 @@ public abstract class AbstractMultiProfilePagerAdapter extends PagerAdapter {
* {@link #PROFILE_WORK} if the work profile was selected.
*/
void onProfileSelected(int profileIndex);
+
+
+ /**
+ * Callback for when the scroll state changes. Useful for discovering when the user begins
+ * dragging, when the pager is automatically settling to the current page, or when it is
+ * fully stopped/idle.
+ * @param state {@link ViewPager#SCROLL_STATE_IDLE}, {@link ViewPager#SCROLL_STATE_DRAGGING}
+ * or {@link ViewPager#SCROLL_STATE_SETTLING}
+ * @see ViewPager.OnPageChangeListener#onPageScrollStateChanged
+ */
+ void onProfilePageStateChanged(int state);
}
/**
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 5533e1eda52d..b36c71f6c7a8 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -102,6 +102,7 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewTreeObserver;
+import android.view.WindowInsets;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.widget.Button;
@@ -129,6 +130,7 @@ import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.widget.GridLayoutManager;
import com.android.internal.widget.RecyclerView;
import com.android.internal.widget.ResolverDrawerLayout;
+import com.android.internal.widget.ViewPager;
import com.google.android.collect.Lists;
@@ -204,6 +206,10 @@ public class ChooserActivity extends ResolverActivity implements
public static final int SELECTION_TYPE_STANDARD = 3;
public static final int SELECTION_TYPE_COPY = 4;
+ private static final int SCROLL_STATUS_IDLE = 0;
+ private static final int SCROLL_STATUS_SCROLLING_VERTICAL = 1;
+ private static final int SCROLL_STATUS_SCROLLING_HORIZONTAL = 2;
+
// statsd logger wrapper
protected ChooserActivityLogger mChooserActivityLogger;
@@ -293,6 +299,7 @@ public class ChooserActivity extends ResolverActivity implements
protected MetricsLogger mMetricsLogger;
private ContentPreviewCoordinator mPreviewCoord;
+ private int mScrollStatus = SCROLL_STATUS_IDLE;
@VisibleForTesting
protected ChooserMultiProfilePagerAdapter mChooserMultiProfilePagerAdapter;
@@ -786,7 +793,6 @@ public class ChooserActivity extends ResolverActivity implements
private AppPredictor.Callback createAppPredictorCallback(
ChooserListAdapter chooserListAdapter) {
return resultList -> {
- //TODO(arangelov) Take care of edge case when callback called after swiping tabs
if (isFinishing() || isDestroyed()) {
return;
}
@@ -795,8 +801,6 @@ public class ChooserActivity extends ResolverActivity implements
}
if (resultList.isEmpty()) {
// APS may be disabled, so try querying targets ourselves.
- //TODO(arangelov) queryDirectShareTargets indirectly uses mIntents.
- // Investigate implications for work tab.
queryDirectShareTargets(chooserListAdapter, true);
return;
}
@@ -1802,7 +1806,8 @@ public class ChooserActivity extends ResolverActivity implements
}
}
- void queryTargetServices(ChooserListAdapter adapter) {
+ @VisibleForTesting
+ protected void queryTargetServices(ChooserListAdapter adapter) {
mQueriedTargetServicesTimeMs = System.currentTimeMillis();
Context selectedProfileContext = createContextAsUser(
@@ -1955,7 +1960,8 @@ public class ChooserActivity extends ResolverActivity implements
return driList;
}
- private void queryDirectShareTargets(
+ @VisibleForTesting
+ protected void queryDirectShareTargets(
ChooserListAdapter adapter, boolean skipAppPredictionService) {
mQueriedSharingShortcutsTimeMs = System.currentTimeMillis();
UserHandle userHandle = adapter.getUserHandle();
@@ -1967,7 +1973,6 @@ public class ChooserActivity extends ResolverActivity implements
}
}
// Default to just querying ShortcutManager if AppPredictor not present.
- //TODO(arangelov) we're using mIntents here, investicate possible implications on work tab
final IntentFilter filter = getTargetIntentFilter();
if (filter == null) {
return;
@@ -2182,6 +2187,9 @@ public class ChooserActivity extends ResolverActivity implements
}
void updateModelAndChooserCounts(TargetInfo info) {
+ if (info != null && info instanceof MultiDisplayResolveInfo) {
+ info = ((MultiDisplayResolveInfo) info).getSelectedTarget();
+ }
if (info != null) {
sendClickToAppPredictor(info);
final ResolveInfo ri = info.getResolveInfo();
@@ -2644,6 +2652,7 @@ public class ChooserActivity extends ResolverActivity implements
if (recyclerView.getVisibility() == View.VISIBLE) {
int directShareHeight = 0;
rowsToShow = Math.min(4, rowsToShow);
+ boolean shouldShowExtraRow = shouldShowExtraRow(rowsToShow);
mLastNumberOfChildren = recyclerView.getChildCount();
for (int i = 0, childCount = recyclerView.getChildCount();
i < childCount && rowsToShow > 0; i++) {
@@ -2654,6 +2663,9 @@ public class ChooserActivity extends ResolverActivity implements
}
int height = child.getHeight();
offset += height;
+ if (shouldShowExtraRow) {
+ offset += height;
+ }
if (gridAdapter.getTargetType(
recyclerView.getChildAdapterPosition(child))
@@ -2677,7 +2689,7 @@ public class ChooserActivity extends ResolverActivity implements
offset = Math.min(offset, minHeight);
}
} else {
- ViewGroup currentEmptyStateView = getCurrentEmptyStateView();
+ ViewGroup currentEmptyStateView = getActiveEmptyStateView();
if (currentEmptyStateView.getVisibility() == View.VISIBLE) {
offset += currentEmptyStateView.getHeight();
}
@@ -2689,6 +2701,18 @@ public class ChooserActivity extends ResolverActivity implements
}
/**
+ * If we have a tabbed view and are showing 1 row in the current profile and an empty
+ * state screen in the other profile, to prevent cropping of the empty state screen we show
+ * a second row in the current profile.
+ */
+ private boolean shouldShowExtraRow(int rowsToShow) {
+ return shouldShowTabs()
+ && rowsToShow == 1
+ && mChooserMultiProfilePagerAdapter.shouldShowEmptyStateScreen(
+ mChooserMultiProfilePagerAdapter.getInactiveListAdapter());
+ }
+
+ /**
* Returns {@link #PROFILE_PERSONAL}, {@link #PROFILE_WORK}, or -1 if the given user handle
* does not match either the personal or work user handle.
**/
@@ -2702,7 +2726,7 @@ public class ChooserActivity extends ResolverActivity implements
return -1;
}
- private ViewGroup getCurrentEmptyStateView() {
+ private ViewGroup getActiveEmptyStateView() {
int currentPage = mChooserMultiProfilePagerAdapter.getCurrentPage();
return mChooserMultiProfilePagerAdapter.getItem(currentPage).getEmptyStateView();
}
@@ -2784,6 +2808,13 @@ public class ChooserActivity extends ResolverActivity implements
return;
}
+ // no need to query direct share for work profile when its turned off
+ UserManager userManager = getSystemService(UserManager.class);
+ if (userManager.isQuietModeEnabled(chooserListAdapter.getUserHandle())) {
+ getChooserActivityLogger().logSharesheetAppLoadComplete();
+ return;
+ }
+
if (ChooserFlags.USE_SHORTCUT_MANAGER_FOR_DIRECT_TARGETS
|| ChooserFlags.USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) {
if (DEBUG) {
@@ -2812,10 +2843,20 @@ public class ChooserActivity extends ResolverActivity implements
final float defaultElevation = elevatedView.getElevation();
final float chooserHeaderScrollElevation =
getResources().getDimensionPixelSize(R.dimen.chooser_header_scroll_elevation);
-
mChooserMultiProfilePagerAdapter.getActiveAdapterView().addOnScrollListener(
new RecyclerView.OnScrollListener() {
public void onScrollStateChanged(RecyclerView view, int scrollState) {
+ if (scrollState == RecyclerView.SCROLL_STATE_IDLE) {
+ if (mScrollStatus == SCROLL_STATUS_SCROLLING_VERTICAL) {
+ mScrollStatus = SCROLL_STATUS_IDLE;
+ setHorizontalScrollingEnabled(true);
+ }
+ } else if (scrollState == RecyclerView.SCROLL_STATE_DRAGGING) {
+ if (mScrollStatus == SCROLL_STATUS_IDLE) {
+ mScrollStatus = SCROLL_STATUS_SCROLLING_VERTICAL;
+ setHorizontalScrollingEnabled(false);
+ }
+ }
}
public void onScrolled(RecyclerView view, int dx, int dy) {
@@ -3016,6 +3057,44 @@ public class ChooserActivity extends ResolverActivity implements
currentRootAdapter.updateDirectShareExpansion();
}
+ @Override
+ protected WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
+ if (shouldShowTabs()) {
+ mChooserMultiProfilePagerAdapter
+ .setEmptyStateBottomOffset(insets.getSystemWindowInsetBottom());
+ mChooserMultiProfilePagerAdapter.setupContainerPadding(
+ getActiveEmptyStateView().findViewById(R.id.resolver_empty_state_container));
+ }
+ return super.onApplyWindowInsets(v, insets);
+ }
+
+ private void setHorizontalScrollingEnabled(boolean enabled) {
+ ResolverViewPager viewPager = findViewById(R.id.profile_pager);
+ viewPager.setSwipingEnabled(enabled);
+ }
+
+ private void setVerticalScrollEnabled(boolean enabled) {
+ ChooserGridLayoutManager layoutManager =
+ (ChooserGridLayoutManager) mChooserMultiProfilePagerAdapter.getActiveAdapterView()
+ .getLayoutManager();
+ layoutManager.setVerticalScrollEnabled(enabled);
+ }
+
+ @Override
+ void onHorizontalSwipeStateChanged(int state) {
+ if (state == ViewPager.SCROLL_STATE_DRAGGING) {
+ if (mScrollStatus == SCROLL_STATUS_IDLE) {
+ mScrollStatus = SCROLL_STATUS_SCROLLING_HORIZONTAL;
+ setVerticalScrollEnabled(false);
+ }
+ } else if (state == ViewPager.SCROLL_STATE_IDLE) {
+ if (mScrollStatus == SCROLL_STATUS_SCROLLING_VERTICAL) {
+ mScrollStatus = SCROLL_STATUS_IDLE;
+ setVerticalScrollEnabled(true);
+ }
+ }
+ }
+
/**
* Adapter for all types of items and targets in ShareSheet.
* Note that ranked sections like Direct Share - while appearing grid-like - are handled on the
diff --git a/core/java/com/android/internal/app/ChooserGridLayoutManager.java b/core/java/com/android/internal/app/ChooserGridLayoutManager.java
index 317a987cf359..c50ebd9562c9 100644
--- a/core/java/com/android/internal/app/ChooserGridLayoutManager.java
+++ b/core/java/com/android/internal/app/ChooserGridLayoutManager.java
@@ -28,6 +28,8 @@ import com.android.internal.widget.RecyclerView;
*/
public class ChooserGridLayoutManager extends GridLayoutManager {
+ private boolean mVerticalScrollEnabled = true;
+
/**
* Constructor used when layout manager is set in XML by RecyclerView attribute
* "layoutManager". If spanCount is not specified in the XML, it defaults to a
@@ -67,4 +69,13 @@ public class ChooserGridLayoutManager extends GridLayoutManager {
// Do not count the footer view in the official count
return super.getRowCountForAccessibility(recycler, state) - 1;
}
+
+ void setVerticalScrollEnabled(boolean verticalScrollEnabled) {
+ mVerticalScrollEnabled = verticalScrollEnabled;
+ }
+
+ @Override
+ public boolean canScrollVertically() {
+ return mVerticalScrollEnabled && super.canScrollVertically();
+ }
}
diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java
index a87f8477bcf4..f4fb993fbb93 100644
--- a/core/java/com/android/internal/app/ChooserListAdapter.java
+++ b/core/java/com/android/internal/app/ChooserListAdapter.java
@@ -80,6 +80,7 @@ public class ChooserListAdapter extends ResolverListAdapter {
private static final int MAX_SUGGESTED_APP_TARGETS = 4;
private static final int MAX_CHOOSER_TARGETS_PER_APP = 2;
private static final int MAX_SERVICE_TARGET_APP = 8;
+ private static final int DEFAULT_DIRECT_SHARE_RANKING_SCORE = 1000;
static final int MAX_SERVICE_TARGETS = 8;
@@ -564,11 +565,13 @@ public class ChooserListAdapter extends ResolverListAdapter {
}
Map<String, Integer> scores = mChooserTargetScores.get(componentName);
Collections.sort(mParkingDirectShareTargets.get(componentName).first, (o1, o2) -> {
- // The score has been normalized between 0 and 2, the default is 1.
+ // The score has been normalized between 0 and 2000, the default is 1000.
int score1 = scores.getOrDefault(
- ChooserUtil.md5(o1.getChooserTarget().getTitle().toString()), 1);
+ ChooserUtil.md5(o1.getChooserTarget().getTitle().toString()),
+ DEFAULT_DIRECT_SHARE_RANKING_SCORE);
int score2 = scores.getOrDefault(
- ChooserUtil.md5(o2.getChooserTarget().getTitle().toString()), 1);
+ ChooserUtil.md5(o2.getChooserTarget().getTitle().toString()),
+ DEFAULT_DIRECT_SHARE_RANKING_SCORE);
return score2 - score1;
});
}
diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
index 774be3c9c4b8..ffa6041721c6 100644
--- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
@@ -38,6 +38,7 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd
private final ChooserProfileDescriptor[] mItems;
private final boolean mIsSendAction;
+ private int mBottomOffset;
ChooserMultiProfilePagerAdapter(Context context,
ChooserActivity.ChooserGridAdapter adapter,
@@ -245,6 +246,16 @@ public class ChooserMultiProfilePagerAdapter extends AbstractMultiProfilePagerAd
}
}
+ void setEmptyStateBottomOffset(int bottomOffset) {
+ mBottomOffset = bottomOffset;
+ }
+
+ @Override
+ protected void setupContainerPadding(View container) {
+ container.setPadding(container.getPaddingLeft(), container.getPaddingTop(),
+ container.getPaddingRight(), container.getPaddingBottom() + mBottomOffset);
+ }
+
class ChooserProfileDescriptor extends ProfileDescriptor {
private ChooserActivity.ChooserGridAdapter chooserGridAdapter;
private RecyclerView recyclerView;
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 71ee8af8b11a..15ba8e8c11f7 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -265,4 +265,16 @@ interface IVoiceInteractionManagerService {
void performDirectAction(in IBinder token, String actionId, in Bundle arguments, int taskId,
IBinder assistToken, in RemoteCallback cancellationCallback,
in RemoteCallback resultCallback);
+
+ /**
+ * Temporarily disables voice interaction (for example, on Automotive when the display is off).
+ *
+ * It will shutdown the service, and only re-enable it after it's called again (or after a
+ * system restart).
+ *
+ * NOTE: it's only effective when the service itself is available / enabled in the device, so
+ * calling setDisable(false) would be a no-op when it isn't.
+ */
+ void setDisabled(boolean disabled);
+
}
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index e65d1fe9ce53..61a52bcc03f9 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -18,6 +18,7 @@ package com.android.internal.app;
import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
+import static com.android.internal.app.ResolverActivity.EXTRA_CALLING_USER;
import static com.android.internal.app.ResolverActivity.EXTRA_SELECTED_PROFILE;
import android.annotation.Nullable;
@@ -246,6 +247,7 @@ public class IntentForwarderActivity extends Activity {
int selectedProfile = findSelectedProfile(className);
sanitizeIntent(intentReceived);
intentReceived.putExtra(EXTRA_SELECTED_PROFILE, selectedProfile);
+ intentReceived.putExtra(EXTRA_CALLING_USER, UserHandle.of(callingUserId));
startActivityAsCaller(intentReceived, null, null, false, userId);
finish();
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index b82f0dfcbe12..daacd459a1a7 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -159,9 +159,6 @@ public class ResolverActivity extends Activity implements
protected static final String METRICS_CATEGORY_RESOLVER = "intent_resolver";
protected static final String METRICS_CATEGORY_CHOOSER = "intent_chooser";
- /**
- * TODO(arangelov): Remove a couple of weeks after work/personal tabs are finalized.
- */
@VisibleForTesting
public static boolean ENABLE_TABBED_VIEW = true;
private static final String TAB_TAG_PERSONAL = "personal";
@@ -184,6 +181,18 @@ public class ResolverActivity extends Activity implements
static final String EXTRA_SELECTED_PROFILE =
"com.android.internal.app.ResolverActivity.EXTRA_SELECTED_PROFILE";
+ /**
+ * {@link UserHandle} extra to indicate the user of the user that the starting intent
+ * originated from.
+ * <p>This is not necessarily the same as {@link #getUserId()} or {@link UserHandle#myUserId()},
+ * as there are edge cases when the intent resolver is launched in the other profile.
+ * For example, when we have 0 resolved apps in current profile and multiple resolved
+ * apps in the other profile, opening a link from the current profile launches the intent
+ * resolver in the other one. b/148536209 for more info.
+ */
+ static final String EXTRA_CALLING_USER =
+ "com.android.internal.app.ResolverActivity.EXTRA_CALLING_USER";
+
static final int PROFILE_PERSONAL = AbstractMultiProfilePagerAdapter.PROFILE_PERSONAL;
static final int PROFILE_WORK = AbstractMultiProfilePagerAdapter.PROFILE_WORK;
@@ -470,17 +479,20 @@ public class ResolverActivity extends Activity implements
// the intent resolver is started in the other profile. Since this is the only case when
// this happens, we check for it here and set the current profile's tab.
int selectedProfile = getCurrentProfile();
- UserHandle intentUser = UserHandle.of(getLaunchingUserId());
+ UserHandle intentUser = getIntent().hasExtra(EXTRA_CALLING_USER)
+ ? getIntent().getParcelableExtra(EXTRA_CALLING_USER)
+ : getUser();
if (!getUser().equals(intentUser)) {
if (getPersonalProfileUserHandle().equals(intentUser)) {
selectedProfile = PROFILE_PERSONAL;
} else if (getWorkProfileUserHandle().equals(intentUser)) {
selectedProfile = PROFILE_WORK;
}
- }
- int selectedProfileExtra = getSelectedProfileExtra();
- if (selectedProfileExtra != -1) {
- selectedProfile = selectedProfileExtra;
+ } else {
+ int selectedProfileExtra = getSelectedProfileExtra();
+ if (selectedProfileExtra != -1) {
+ selectedProfile = selectedProfileExtra;
+ }
}
// We only show the default app for the profile of the current user. The filterLastUsed
// flag determines whether to show a default app and that app is not shown in the
@@ -535,22 +547,6 @@ public class ResolverActivity extends Activity implements
return selectedProfile;
}
- /**
- * Returns the user id of the user that the starting intent originated from.
- * <p>This is not necessarily equal to {@link #getUserId()} or {@link UserHandle#myUserId()},
- * as there are edge cases when the intent resolver is launched in the other profile.
- * For example, when we have 0 resolved apps in current profile and multiple resolved apps
- * in the other profile, opening a link from the current profile launches the intent resolver
- * in the other one. b/148536209 for more info.
- */
- private int getLaunchingUserId() {
- int contentUserHint = getIntent().getContentUserHint();
- if (contentUserHint == UserHandle.USER_CURRENT) {
- return UserHandle.myUserId();
- }
- return contentUserHint;
- }
-
protected @Profile int getCurrentProfile() {
return (UserHandle.myUserId() == UserHandle.USER_SYSTEM ? PROFILE_PERSONAL : PROFILE_WORK);
}
@@ -1235,8 +1231,8 @@ public class ResolverActivity extends Activity implements
}
if (target != null) {
- if (intent != null) {
- intent.fixUris(UserHandle.myUserId());
+ if (intent != null && isLaunchingTargetInOtherProfile()) {
+ prepareIntentForCrossProfileLaunch(intent);
}
safelyStartActivity(target);
@@ -1250,6 +1246,15 @@ public class ResolverActivity extends Activity implements
return true;
}
+ private void prepareIntentForCrossProfileLaunch(Intent intent) {
+ intent.fixUris(UserHandle.myUserId());
+ }
+
+ private boolean isLaunchingTargetInOtherProfile() {
+ return mMultiProfilePagerAdapter.getCurrentUserHandle().getIdentifier()
+ != UserHandle.myUserId();
+ }
+
@VisibleForTesting
public void safelyStartActivity(TargetInfo cti) {
// We're dispatching intents that might be coming from legacy apps, so
@@ -1646,10 +1651,18 @@ public class ResolverActivity extends Activity implements
viewPager.setVisibility(View.VISIBLE);
tabHost.setCurrentTab(mMultiProfilePagerAdapter.getCurrentPage());
mMultiProfilePagerAdapter.setOnProfileSelectedListener(
- index -> {
- tabHost.setCurrentTab(index);
- resetButtonBar();
- resetCheckedItem();
+ new AbstractMultiProfilePagerAdapter.OnProfileSelectedListener() {
+ @Override
+ public void onProfileSelected(int index) {
+ tabHost.setCurrentTab(index);
+ resetButtonBar();
+ resetCheckedItem();
+ }
+
+ @Override
+ public void onProfilePageStateChanged(int state) {
+ onHorizontalSwipeStateChanged(state);
+ }
});
mMultiProfilePagerAdapter.setOnSwitchOnWorkSelectedListener(
() -> {
@@ -1661,6 +1674,8 @@ public class ResolverActivity extends Activity implements
findViewById(R.id.resolver_tab_divider).setVisibility(View.VISIBLE);
}
+ void onHorizontalSwipeStateChanged(int state) {}
+
private void maybeHideDivider() {
if (!isIntentPicker()) {
return;
@@ -1801,6 +1816,12 @@ public class ResolverActivity extends Activity implements
ResolverListAdapter activeListAdapter =
mMultiProfilePagerAdapter.getActiveListAdapter();
View buttonBarDivider = findViewById(R.id.resolver_button_bar_divider);
+ if (!useLayoutWithDefault()) {
+ int inset = mSystemWindowInsets != null ? mSystemWindowInsets.bottom : 0;
+ buttonLayout.setPadding(buttonLayout.getPaddingLeft(), buttonLayout.getPaddingTop(),
+ buttonLayout.getPaddingRight(), getResources().getDimensionPixelSize(
+ R.dimen.resolver_button_bar_spacing) + inset);
+ }
if (activeListAdapter.isTabLoaded()
&& mMultiProfilePagerAdapter.shouldShowEmptyStateScreen(activeListAdapter)
&& !useLayoutWithDefault()) {
@@ -1817,12 +1838,6 @@ public class ResolverActivity extends Activity implements
buttonLayout.setVisibility(View.VISIBLE);
setButtonBarIgnoreOffset(/* ignoreOffset */ true);
- if (!useLayoutWithDefault()) {
- int inset = mSystemWindowInsets != null ? mSystemWindowInsets.bottom : 0;
- buttonLayout.setPadding(buttonLayout.getPaddingLeft(), buttonLayout.getPaddingTop(),
- buttonLayout.getPaddingRight(), getResources().getDimensionPixelSize(
- R.dimen.resolver_button_bar_spacing) + inset);
- }
mOnceButton = (Button) buttonLayout.findViewById(R.id.button_once);
mAlwaysButton = (Button) buttonLayout.findViewById(R.id.button_always);
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index 97f43d27a9ce..b1e8ed1f943e 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -423,7 +423,6 @@ public class ResolverListAdapter extends BaseAdapter {
// We assume that at this point we've already filtered out the only intent for a different
// targetUserId which we're going to use.
private void addResolveInfo(DisplayResolveInfo dri) {
- // TODO(arangelov): Is that UserHandle.USER_CURRENT check okay?
if (dri != null && dri.getResolveInfo() != null
&& dri.getResolveInfo().targetUserId == UserHandle.USER_CURRENT) {
if (shouldAddResolveInfo(dri)) {
diff --git a/core/java/com/android/internal/app/ResolverViewPager.java b/core/java/com/android/internal/app/ResolverViewPager.java
index 4eb6e3bd2071..9cdfc2f5c763 100644
--- a/core/java/com/android/internal/app/ResolverViewPager.java
+++ b/core/java/com/android/internal/app/ResolverViewPager.java
@@ -18,6 +18,7 @@ package com.android.internal.app;
import android.content.Context;
import android.util.AttributeSet;
+import android.view.MotionEvent;
import android.view.View;
import com.android.internal.widget.ViewPager;
@@ -30,6 +31,8 @@ import com.android.internal.widget.ViewPager;
*/
public class ResolverViewPager extends ViewPager {
+ private boolean mSwipingEnabled = true;
+
public ResolverViewPager(Context context) {
super(context);
}
@@ -70,4 +73,13 @@ public class ResolverViewPager extends ViewPager {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
+
+ void setSwipingEnabled(boolean swipingEnabled) {
+ mSwipingEnabled = swipingEnabled;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ return mSwipingEnabled && super.onInterceptTouchEvent(ev);
+ }
}
diff --git a/core/java/com/android/internal/app/chooser/MultiDisplayResolveInfo.java b/core/java/com/android/internal/app/chooser/MultiDisplayResolveInfo.java
index e58258352106..cf921d734d48 100644
--- a/core/java/com/android/internal/app/chooser/MultiDisplayResolveInfo.java
+++ b/core/java/com/android/internal/app/chooser/MultiDisplayResolveInfo.java
@@ -70,6 +70,13 @@ public class MultiDisplayResolveInfo extends DisplayResolveInfo {
}
/**
+ * Return selected target.
+ */
+ public DisplayResolveInfo getSelectedTarget() {
+ return hasSelected() ? mTargetInfos.get(mSelected) : null;
+ }
+
+ /**
* Whether or not the user has selected a specific target for this MultiInfo.
*/
public boolean hasSelected() {
diff --git a/core/java/com/android/internal/logging/UiEventLogger.java b/core/java/com/android/internal/logging/UiEventLogger.java
index 67ffd4d93404..5212265f6c8a 100644
--- a/core/java/com/android/internal/logging/UiEventLogger.java
+++ b/core/java/com/android/internal/logging/UiEventLogger.java
@@ -60,4 +60,28 @@ public interface UiEventLogger {
*/
void logWithInstanceId(@NonNull UiEventEnum event, int uid, @Nullable String packageName,
@Nullable InstanceId instance);
+
+ /**
+ * Log an event with ranked-choice information along with package.
+ * Does nothing if event.getId() <= 0.
+ * @param event an enum implementing UiEventEnum interface.
+ * @param uid the uid of the relevant app, if known (0 otherwise).
+ * @param packageName the package name of the relevant app, if known (null otherwise).
+ * @param position the position picked.
+ */
+ void logWithPosition(@NonNull UiEventEnum event, int uid, @Nullable String packageName,
+ int position);
+
+ /**
+ * Log an event with ranked-choice information along with package and instance ID.
+ * Does nothing if event.getId() <= 0.
+ * @param event an enum implementing UiEventEnum interface.
+ * @param uid the uid of the relevant app, if known (0 otherwise).
+ * @param packageName the package name of the relevant app, if known (null otherwise).
+ * @param instance An identifier obtained from an InstanceIdSequence. If null, reduces to
+ * logWithPosition().
+ * @param position the position picked.
+ */
+ void logWithInstanceIdAndPosition(@NonNull UiEventEnum event, int uid,
+ @Nullable String packageName, @Nullable InstanceId instance, int position);
}
diff --git a/core/java/com/android/internal/logging/UiEventLoggerImpl.java b/core/java/com/android/internal/logging/UiEventLoggerImpl.java
index 4d171ec8a3a8..c9156c13aae3 100644
--- a/core/java/com/android/internal/logging/UiEventLoggerImpl.java
+++ b/core/java/com/android/internal/logging/UiEventLoggerImpl.java
@@ -48,4 +48,31 @@ public class UiEventLoggerImpl implements UiEventLogger {
log(event, uid, packageName);
}
}
+
+ @Override
+ public void logWithPosition(UiEventEnum event, int uid, String packageName, int position) {
+ final int eventID = event.getId();
+ if (eventID > 0) {
+ FrameworkStatsLog.write(FrameworkStatsLog.RANKING_SELECTED,
+ /* event_id = 1 */ eventID,
+ /* package_name = 2 */ packageName,
+ /* instance_id = 3 */ 0,
+ /* position_picked = 4 */ position);
+ }
+ }
+
+ @Override
+ public void logWithInstanceIdAndPosition(UiEventEnum event, int uid, String packageName,
+ InstanceId instance, int position) {
+ final int eventID = event.getId();
+ if ((eventID > 0) && (instance != null)) {
+ FrameworkStatsLog.write(FrameworkStatsLog.RANKING_SELECTED,
+ /* event_id = 1 */ eventID,
+ /* package_name = 2 */ packageName,
+ /* instance_id = 3 */ instance.getId(),
+ /* position_picked = 4 */ position);
+ } else {
+ logWithPosition(event, uid, packageName, position);
+ }
+ }
}
diff --git a/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java b/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java
index 180ab0810f5b..2d09434807a6 100644
--- a/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java
+++ b/core/java/com/android/internal/logging/testing/UiEventLoggerFake.java
@@ -35,13 +35,15 @@ public class UiEventLoggerFake implements UiEventLogger {
public final int eventId;
public final int uid;
public final String packageName;
- public final InstanceId instanceId; // Used only for WithInstanceId variant
+ public final InstanceId instanceId; // Used only for WithInstanceId variants
+ public final int position; // Used only for Position variants
FakeUiEvent(int eventId, int uid, String packageName) {
this.eventId = eventId;
this.uid = uid;
this.packageName = packageName;
this.instanceId = null;
+ this.position = 0;
}
FakeUiEvent(int eventId, int uid, String packageName, InstanceId instanceId) {
@@ -49,6 +51,15 @@ public class UiEventLoggerFake implements UiEventLogger {
this.uid = uid;
this.packageName = packageName;
this.instanceId = instanceId;
+ this.position = 0;
+ }
+
+ FakeUiEvent(int eventId, int uid, String packageName, InstanceId instanceId, int position) {
+ this.eventId = eventId;
+ this.uid = uid;
+ this.packageName = packageName;
+ this.instanceId = instanceId;
+ this.position = position;
}
}
@@ -92,4 +103,21 @@ public class UiEventLoggerFake implements UiEventLogger {
mLogs.add(new FakeUiEvent(eventId, uid, packageName, instance));
}
}
+
+ @Override
+ public void logWithPosition(UiEventEnum event, int uid, String packageName, int position) {
+ final int eventId = event.getId();
+ if (eventId > 0) {
+ mLogs.add(new FakeUiEvent(eventId, uid, packageName, null, position));
+ }
+ }
+
+ @Override
+ public void logWithInstanceIdAndPosition(UiEventEnum event, int uid, String packageName,
+ InstanceId instance, int position) {
+ final int eventId = event.getId();
+ if (eventId > 0) {
+ mLogs.add(new FakeUiEvent(eventId, uid, packageName, instance, position));
+ }
+ }
}
diff --git a/core/java/com/android/internal/util/ScreenshotHelper.java b/core/java/com/android/internal/util/ScreenshotHelper.java
index ad6c7e8f7f60..adc7ba30c157 100644
--- a/core/java/com/android/internal/util/ScreenshotHelper.java
+++ b/core/java/com/android/internal/util/ScreenshotHelper.java
@@ -8,10 +8,10 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.Rect;
import android.net.Uri;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -37,10 +37,12 @@ public class ScreenshotHelper {
private int mSource;
private boolean mHasStatusBar;
private boolean mHasNavBar;
- private Bitmap mBitmap;
+ private Bundle mBitmapBundle;
private Rect mBoundsInScreen;
private Insets mInsets;
private int mTaskId;
+ private int mUserId;
+ private ComponentName mTopComponent;
ScreenshotRequest(int source, boolean hasStatus, boolean hasNav) {
mSource = source;
@@ -48,24 +50,29 @@ public class ScreenshotHelper {
mHasNavBar = hasNav;
}
- ScreenshotRequest(
- int source, Bitmap bitmap, Rect boundsInScreen, Insets insets, int taskId) {
+ ScreenshotRequest(int source, Bundle bitmapBundle, Rect boundsInScreen, Insets insets,
+ int taskId, int userId, ComponentName topComponent) {
mSource = source;
- mBitmap = bitmap;
+ mBitmapBundle = bitmapBundle;
mBoundsInScreen = boundsInScreen;
mInsets = insets;
mTaskId = taskId;
+ mUserId = userId;
+ mTopComponent = topComponent;
}
ScreenshotRequest(Parcel in) {
mSource = in.readInt();
mHasStatusBar = in.readBoolean();
mHasNavBar = in.readBoolean();
+
if (in.readInt() == 1) {
- mBitmap = in.readParcelable(Bitmap.class.getClassLoader());
+ mBitmapBundle = in.readBundle(getClass().getClassLoader());
mBoundsInScreen = in.readParcelable(Rect.class.getClassLoader());
mInsets = in.readParcelable(Insets.class.getClassLoader());
mTaskId = in.readInt();
+ mUserId = in.readInt();
+ mTopComponent = in.readParcelable(ComponentName.class.getClassLoader());
}
}
@@ -81,8 +88,8 @@ public class ScreenshotHelper {
return mHasNavBar;
}
- public Bitmap getBitmap() {
- return mBitmap;
+ public Bundle getBitmapBundle() {
+ return mBitmapBundle;
}
public Rect getBoundsInScreen() {
@@ -97,6 +104,15 @@ public class ScreenshotHelper {
return mTaskId;
}
+
+ public int getUserId() {
+ return mUserId;
+ }
+
+ public ComponentName getTopComponent() {
+ return mTopComponent;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -107,14 +123,16 @@ public class ScreenshotHelper {
dest.writeInt(mSource);
dest.writeBoolean(mHasStatusBar);
dest.writeBoolean(mHasNavBar);
- if (mBitmap == null) {
+ if (mBitmapBundle == null) {
dest.writeInt(0);
} else {
dest.writeInt(1);
- dest.writeParcelable(mBitmap, 0);
+ dest.writeBundle(mBitmapBundle);
dest.writeParcelable(mBoundsInScreen, 0);
dest.writeParcelable(mInsets, 0);
dest.writeInt(mTaskId);
+ dest.writeInt(mUserId);
+ dest.writeParcelable(mTopComponent, 0);
}
}
@@ -234,19 +252,22 @@ public class ScreenshotHelper {
/**
* Request that provided image be handled as if it was a screenshot.
*
- * @param screenshot The bitmap to treat as the screen shot.
+ * @param screenshotBundle Bundle containing the buffer and color space of the screenshot.
* @param boundsInScreen The bounds in screen coordinates that the bitmap orginated from.
* @param insets The insets that the image was shown with, inside the screenbounds.
* @param taskId The taskId of the task that the screen shot was taken of.
+ * @param userId The userId of user running the task provided in taskId.
+ * @param topComponent The component name of the top component running in the task.
* @param handler A handler used in case the screenshot times out
* @param completionConsumer Consumes `false` if a screenshot was not taken, and `true` if the
* screenshot was taken.
*/
- public void provideScreenshot(@NonNull Bitmap screenshot, @NonNull Rect boundsInScreen,
- @NonNull Insets insets, int taskId, int source,
+ public void provideScreenshot(@NonNull Bundle screenshotBundle, @NonNull Rect boundsInScreen,
+ @NonNull Insets insets, int taskId, int userId, ComponentName topComponent, int source,
@NonNull Handler handler, @Nullable Consumer<Uri> completionConsumer) {
ScreenshotRequest screenshotRequest =
- new ScreenshotRequest(source, screenshot, boundsInScreen, insets, taskId);
+ new ScreenshotRequest(source, screenshotBundle, boundsInScreen, insets, taskId,
+ userId, topComponent);
takeScreenshot(WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE, SCREENSHOT_TIMEOUT_MS,
handler, screenshotRequest, completionConsumer);
}
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 688e00bc5a29..0d2dbefb9cd7 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -480,23 +480,25 @@ public class ConversationLayout extends FrameLayout
// (This usually happens for most 1:1 conversations)
conversationText = messagingGroup.getSenderName();
}
- Icon avatarIcon = messagingGroup.getAvatarIcon();
- if (avatarIcon == null) {
- avatarIcon = createAvatarSymbol(conversationText, "", mLayoutColor);
+ if (mConversationIcon == null) {
+ Icon avatarIcon = messagingGroup.getAvatarIcon();
+ if (avatarIcon == null) {
+ avatarIcon = createAvatarSymbol(conversationText, "", mLayoutColor);
+ }
+ mConversationIcon = avatarIcon;
}
- mConversationIcon = avatarIcon;
- mConversationIconView.setImageIcon(mConversationIcon);
break;
}
}
} else {
- if (mLargeIcon != null) {
+ if (mConversationIcon == null && mLargeIcon != null) {
mConversationIcon = mLargeIcon;
+ }
+ if (mConversationIcon != null) {
mConversationIconView.setVisibility(VISIBLE);
mConversationFacePile.setVisibility(GONE);
- mConversationIconView.setImageIcon(mLargeIcon);
+ mConversationIconView.setImageIcon(mConversationIcon);
} else {
- mConversationIcon = null;
mConversationIconView.setVisibility(GONE);
// This will also inflate it!
mConversationFacePile.setVisibility(VISIBLE);
@@ -709,6 +711,11 @@ public class ConversationLayout extends FrameLayout
mLargeIcon = largeIcon;
}
+ @RemotableViewMethod
+ public void setConversationIcon(Icon conversationIcon) {
+ mConversationIcon = conversationIcon;
+ }
+
/**
* Sets the conversation title of this conversation.
*
@@ -1216,7 +1223,6 @@ public class ConversationLayout extends FrameLayout
mExpandButtonContainer.setVisibility(VISIBLE);
mExpandButtonInnerContainer.setOnClickListener(onClickListener);
} else {
- // TODO: handle content paddings to end of layout
mExpandButtonContainer.setVisibility(GONE);
}
updateContentEndPaddings();
diff --git a/core/jni/android_media_AudioEffectDescriptor.cpp b/core/jni/android_media_AudioEffectDescriptor.cpp
index 37d8114052b8..1435e879053c 100644
--- a/core/jni/android_media_AudioEffectDescriptor.cpp
+++ b/core/jni/android_media_AudioEffectDescriptor.cpp
@@ -102,9 +102,9 @@ void convertAudioEffectDescriptorVectorFromNative(JNIEnv *env, jobjectArray *jDe
*jDescriptors = env->NewObjectArray(actualSize, audioEffectDescriptorClass(), NULL);
for (size_t i = 0; i < actualSize; i++) {
- env->SetObjectArrayElement(*jDescriptors,
- i,
- env->GetObjectArrayElement(temp, i));
+ jobject jdesc = env->GetObjectArrayElement(temp, i);
+ env->SetObjectArrayElement(*jDescriptors, i, jdesc);
+ env->DeleteLocalRef(jdesc);
}
env->DeleteLocalRef(temp);
}
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index fc2005a31696..5c444bda1838 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -526,8 +526,16 @@ static void UnsetChldSignalHandler() {
// Calls POSIX setgroups() using the int[] object as an argument.
// A nullptr argument is tolerated.
-static void SetGids(JNIEnv* env, jintArray managed_gids, fail_fn_t fail_fn) {
+static void SetGids(JNIEnv* env, jintArray managed_gids, jboolean is_child_zygote,
+ fail_fn_t fail_fn) {
if (managed_gids == nullptr) {
+ if (is_child_zygote) {
+ // For child zygotes like webview and app zygote, we want to clear out
+ // any supplemental groups the parent zygote had.
+ if (setgroups(0, NULL) == -1) {
+ fail_fn(CREATE_ERROR("Failed to remove supplementary groups for child zygote"));
+ }
+ }
return;
}
@@ -1665,7 +1673,7 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
}
}
- SetGids(env, gids, fail_fn);
+ SetGids(env, gids, is_child_zygote, fail_fn);
SetRLimits(env, rlimits, fail_fn);
if (need_pre_initialize_native_bridge) {
@@ -1736,6 +1744,8 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE;
}
android_mallopt(M_SET_HEAP_TAGGING_LEVEL, &heap_tagging_level, sizeof(heap_tagging_level));
+ // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART runtime.
+ runtime_flags &= ~RuntimeFlags::MEMORY_TAG_LEVEL_MASK;
bool forceEnableGwpAsan = false;
switch (runtime_flags & RuntimeFlags::GWP_ASAN_LEVEL_MASK) {
@@ -1748,6 +1758,8 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
case RuntimeFlags::GWP_ASAN_LEVEL_LOTTERY:
android_mallopt(M_INITIALIZE_GWP_ASAN, &forceEnableGwpAsan, sizeof(forceEnableGwpAsan));
}
+ // Now that we've used the flag, clear it so that we don't pass unknown flags to the ART runtime.
+ runtime_flags &= ~RuntimeFlags::GWP_ASAN_LEVEL_MASK;
if (NeedsNoRandomizeWorkaround()) {
// Work around ARM kernel ASLR lossage (http://b/5817320).
diff --git a/core/proto/android/server/connectivity/data_stall_event.proto b/core/proto/android/server/connectivity/data_stall_event.proto
index 23fcf6ebc2cc..787074ba494e 100644
--- a/core/proto/android/server/connectivity/data_stall_event.proto
+++ b/core/proto/android/server/connectivity/data_stall_event.proto
@@ -32,6 +32,7 @@ enum ApBand {
AP_BAND_UNKNOWN = 0;
AP_BAND_2GHZ = 1;
AP_BAND_5GHZ = 2;
+ AP_BAND_6GHZ = 3;
}
// Refer to definition in TelephonyManager.java.
diff --git a/core/proto/android/stats/mediametrics/mediametrics.proto b/core/proto/android/stats/mediametrics/mediametrics.proto
index e1af9622adb3..9f0ff591a506 100644
--- a/core/proto/android/stats/mediametrics/mediametrics.proto
+++ b/core/proto/android/stats/mediametrics/mediametrics.proto
@@ -131,7 +131,7 @@ message AudioTrackData {
* Logged from:
* frameworks/av/media/libstagefright/MediaCodec.cpp
* frameworks/av/services/mediaanalytics/statsd_codec.cpp
- * Next Tag: 21
+ * Next Tag: 26
*/
message CodecData {
optional string codec = 1;
@@ -156,6 +156,9 @@ message CodecData {
optional int64 latency_unknown = 20;
optional int32 queue_input_buffer_error = 21;
optional int32 queue_secure_input_buffer_error = 22;
+ optional string bitrate_mode = 23;
+ optional int32 bitrate = 24;
+ optional int64 lifetime_millis = 25;
}
/**
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index fd8460f9c478..464a47002b17 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3656,7 +3656,8 @@
<p>The package installer v2 APIs are still a work in progress and we're
currently validating they work in all scenarios.
<p>Not for use by third-party applications.
- TODO(b/152310230): remove this permission once the APIs are confirmed to be sufficient.
+ TODO(b/152310230): use this permission to protect only Incremental installations
+ once the APIs are confirmed to be sufficient.
@hide
-->
<permission android:name="com.android.permission.USE_INSTALLER_V2"
diff --git a/core/res/res/layout/notification_material_action_list.xml b/core/res/res/layout/notification_material_action_list.xml
index ec54091e5a20..3615b9e2f9cb 100644
--- a/core/res/res/layout/notification_material_action_list.xml
+++ b/core/res/res/layout/notification_material_action_list.xml
@@ -22,10 +22,11 @@
android:layout_gravity="bottom">
<LinearLayout
+ android:id="@+id/actions_container_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:paddingEnd="12dp"
+ android:paddingEnd="@dimen/bubble_gone_padding_end"
>
<com.android.internal.widget.NotificationActionListLayout
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 65872f43f46e..afeceb775524 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1309,7 +1309,7 @@
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Εντοπίστηκε αναλογικό αξεσουάρ ήχου"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Η συνδεδεμένη συσκευή δεν είναι συμβατή με αυτό το τηλέφωνο. Πατήστε για να μάθετε περισσότερα."</string>
<string name="adb_active_notification_title" msgid="408390247354560331">"Συνδέθηκε ο εντοπισμός σφαλμάτων USB"</string>
- <string name="adb_active_notification_message" msgid="5617264033476778211">"Απενεργοποιήστε τον εντοπισμό/διόρθ. σφαλμάτων USB"</string>
+ <string name="adb_active_notification_message" msgid="5617264033476778211">"Πατήστε για απενεργοποίηση εντοπισμού/διόρθ. σφαλμάτων USB"</string>
<string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Επιλογή για απενεργοποίηση του εντοπισμού σφαλμάτων USB."</string>
<string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Συνδέθηκε ο ασύρματος εντοπισμός σφαλμάτων"</string>
<string name="adbwifi_active_notification_message" msgid="930987922852867972">"Πατήστε, για να απενεργοποιήσετε τον ασύρματο εντοπισμό σφαλμάτων"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 36380b822864..31abd8235bf4 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -202,10 +202,8 @@
<string name="printing_disabled_by" msgid="3517499806528864633">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‏‎‎‎‎‏‎‏‎‏‎‏‏‎‏‏‏‎‎‎‎‎‎‎‎‎‎‎‏‏‎‏‎‏‎‎‎‏‎‎‎‎‎‎‏‎‏‏‏‏‎‎‏‎Printing disabled by ‎‏‎‎‏‏‎<xliff:g id="OWNER_APP">%s</xliff:g>‎‏‎‎‏‏‏‎.‎‏‎‎‏‎"</string>
<string name="personal_apps_suspension_title" msgid="7561416677884286600">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‎‏‏‎‎‎‏‏‎‏‎‎‎‎‎‎‎‏‏‎‎‎‎‎‎‎‎‎‏‏‏‎‏‎‏‏‎‏‎‎‎‏‎‎‎‎Turn on your work profile‎‏‎‎‏‎"</string>
<string name="personal_apps_suspension_text" msgid="6115455688932935597">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‎‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‏‎‏‎‏‎‎‎‏‏‏‏‎‏‎‏‏‎‏‎Your personal apps are blocked until you turn on your work profile‎‏‎‎‏‎"</string>
- <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
- <skip />
+ <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‎‏‏‎‎‏‎‏‎‎‏‏‎‎Personal apps will be blocked on ‎‏‎‎‏‏‎<xliff:g id="DATE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ at ‎‏‎‎‏‏‎<xliff:g id="TIME">%2$s</xliff:g>‎‏‎‎‏‏‏‎. Your IT admin doesn’t allow your work profile to stay off for more than ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%3$d</xliff:g>‎‏‎‎‏‏‏‎ days.‎‏‎‎‏‎"</string>
+ <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‎‎‏‏‎‎‏‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‎‏‎‎‎‎‎‏‏‎‏‎‏‎‎‎‏‎‏‏‎‏‎‏‏‎‎‏‎Turn on‎‏‎‎‏‎"</string>
<string name="me" msgid="6207584824693813140">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‎‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‏‏‎‎‏‎‏‎‎‎Me‎‏‎‎‏‎"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‎‏‏‎‎‎‎‎‎‎‎‏‎‎‏‏‏‏‏‏‎‎‏‎‎‎‎‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‏‎‏‏‎‏‎Tablet options‎‏‎‎‏‎"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‏‎‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‏‎‎‏‏‏‎‏‎‏‎‎‏‎‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‏‎Android TV options‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 91a8d0585709..bb06173918d7 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -2032,7 +2032,7 @@
<item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ficheiros</item>
<item quantity="one"><xliff:g id="FILE_NAME_0">%s</xliff:g> + <xliff:g id="COUNT_1">%d</xliff:g> ficheiro</item>
</plurals>
- <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Non hai persoas recomendadas coas que compartir contido"</string>
+ <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Non hai recomendacións de persoas coas que compartir contido"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Lista de aplicacións"</string>
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Esta aplicación non está autorizada a realizar gravacións, pero pode capturar audio a través deste dispositivo USB."</string>
<string name="accessibility_system_action_home_label" msgid="3234748160850301870">"Inicio"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 3fe076695642..5161fdc65446 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1230,7 +1230,7 @@
<string name="volume_unknown" msgid="4041914008166576293">"កម្រិត​សំឡេង"</string>
<string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"កម្រិត​សំឡេង​ប៊្លូធូស"</string>
<string name="volume_icon_description_ringer" msgid="2187800636867423459">"កម្រិត​សំឡេង​រោទ៍"</string>
- <string name="volume_icon_description_incall" msgid="4491255105381227919">"កម្រិត​សំឡេង​ហៅ"</string>
+ <string name="volume_icon_description_incall" msgid="4491255105381227919">"កម្រិត​សំឡេង​ហៅទូរសព្ទ"</string>
<string name="volume_icon_description_media" msgid="4997633254078171233">"កម្រិត​សំឡេង​មេឌៀ"</string>
<string name="volume_icon_description_notification" msgid="579091344110747279">"កម្រិត​សំឡេង​ការ​ជូន​ដំណឹង"</string>
<string name="ringtone_default" msgid="9118299121288174597">"សំឡេង​រោទ៍​លំនាំដើម"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index bc896d61a43b..25aa3b5eaf94 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1308,7 +1308,7 @@
<string name="usb_power_notification_message" msgid="7284765627437897702">"ಸಂಪರ್ಕಗೊಂಡಿರುವ ಸಾಧನವನ್ನು ಚಾರ್ಜ್ ಮಾಡಲಾಗುತ್ತಿದೆ. ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"ಅನ್‌ಲಾಗ್ ಆಡಿಯೋ ಪರಿಕರ ಪತ್ತೆಯಾಗಿದೆ"</string>
<string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"ಲಗತ್ತಿಸಲಾದ ಸಾಧನವು ಈ ಫೋನಿನೊಂದಿಗೆ ಹೊಂದಿಕೆಯಾಗುವುದಿಲ್ಲ. ಇನ್ನಷ್ಟು ತಿಳಿಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
- <string name="adb_active_notification_title" msgid="408390247354560331">"USB ಡೀಬಗಿಂಗ್‌‌ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
+ <string name="adb_active_notification_title" msgid="408390247354560331">"USB ಡೀಬಗ್‌ ಮಾಡುವಿಕೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
<string name="adb_active_notification_message" msgid="5617264033476778211">"USB ಡೀಬಗ್‌ ಮಾಡುವಿಕೆಯನ್ನು ಆಫ್‌ ಮಾಡಲು ಟ್ಯಾಪ್‌ ಮಾಡಿ"</string>
<string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB ಡೀಬಗ್‌ ಮಾಡುವಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಆಯ್ಕೆ ಮಾಡಿ."</string>
<string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ವೈರ್‌ಲೆಸ್ ಡೀಬಗ್‌ ಮಾಡುವಿಕೆಯನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
@@ -2032,7 +2032,7 @@
<item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ಫೈಲ್‌ಗಳು</item>
<item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ಫೈಲ್‌ಗಳು</item>
</plurals>
- <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"ಹಂಚಿಕೊಳ್ಳಲು, ಯಾವುದೇ ಶಿಫಾರಸು ಮಾಡಲಾದ ಜನರಿಲ್ಲ"</string>
+ <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"ಹಂಚಿಕೊಳ್ಳಲು ಶಿಫಾರಸು ಮಾಡಲಾದವರು ಯಾರೂ ಇಲ್ಲ"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"ಆ್ಯಪ್‌ಗಳ ಪಟ್ಟಿ"</string>
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"ಈ ಆ್ಯಪ್‌ಗೆ ರೆಕಾರ್ಡ್ ಅನುಮತಿಯನ್ನು ನೀಡಲಾಗಿಲ್ಲ, ಆದರೆ ಈ USB ಸಾಧನದ ಮೂಲಕ ಆಡಿಯೊವನ್ನು ಸೆರೆಹಿಡಿಯಬಲ್ಲದು."</string>
<string name="accessibility_system_action_home_label" msgid="3234748160850301870">"ಹೋಮ್"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index a7e6f99ba8fd..a5a0f9e587ec 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -2032,7 +2032,7 @@
<item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> फाइल</item>
<item quantity="one"><xliff:g id="FILE_NAME_0">%s</xliff:g> + <xliff:g id="COUNT_1">%d</xliff:g> फाइल</item>
</plurals>
- <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"शेअर करण्यासाठी कोणतीही शिफारस केलेले लोक नाहीत"</string>
+ <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"शेअर करण्यासाठी शिफारस केलेल्या कोणत्याही व्यक्ती नाहीत"</string>
<string name="chooser_all_apps_button_label" msgid="3230427756238666328">"अ‍ॅप्स सूची"</string>
<string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"या अ‍ॅपला रेकॉर्ड करण्याची परवानगी दिली गेली नाही पण हे USB डिव्हाइस वापरून ऑडिओ कॅप्चर केला जाऊ शकतो."</string>
<string name="accessibility_system_action_home_label" msgid="3234748160850301870">"होम"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index cc8137cc244c..64302dab7ce9 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1912,7 +1912,7 @@
<string name="demo_starting_message" msgid="6577581216125805905">"Demo starten…"</string>
<string name="demo_restarting_message" msgid="1160053183701746766">"Apparaat resetten…"</string>
<string name="suspended_widget_accessibility" msgid="6331451091851326101">"<xliff:g id="LABEL">%1$s</xliff:g> uitgeschakeld"</string>
- <string name="conference_call" msgid="5731633152336490471">"Telefonische vergadering"</string>
+ <string name="conference_call" msgid="5731633152336490471">"Conferencecall"</string>
<string name="tooltip_popup_title" msgid="7863719020269945722">"Knopinfo"</string>
<string name="app_category_game" msgid="4534216074910244790">"Games"</string>
<string name="app_category_audio" msgid="8296029904794676222">"Muziek en audio"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index f803f02e92bc..4becdaa16ef3 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -60,7 +60,7 @@
<string name="ClirMmi" msgid="4702929460236547156">"ଆଉଟଗୋଇଙ୍ଗ୍ କଲର୍ ଆଇଡି"</string>
<string name="ColpMmi" msgid="4736462893284419302">"ସଂଯୁକ୍ତ ଲାଇନ୍ ID"</string>
<string name="ColrMmi" msgid="5889782479745764278">"ସଂଯୁକ୍ତ ଲାଇନ୍ ID କଟକଣା"</string>
- <string name="CfMmi" msgid="8390012691099787178">"କଲ୍‌ ଫରୱାର୍ଡିଙ୍ଗ"</string>
+ <string name="CfMmi" msgid="8390012691099787178">"କଲ୍‌ ଫରୱାର୍ଡିଂ"</string>
<string name="CwMmi" msgid="3164609577675404761">"କଲ୍‌ ଅପେକ୍ଷାରତ"</string>
<string name="BaMmi" msgid="7205614070543372167">"କଲ୍‌ ବ୍ୟାରିଙ୍ଗ୍"</string>
<string name="PwdMmi" msgid="3360991257288638281">"ପାସ୍‌ୱର୍ଡ ପରିବର୍ତ୍ତନ"</string>
@@ -88,7 +88,7 @@
<string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ଜରୁରୀକାଳୀନ କଲ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"ୱାଇ-ଫାଇ ସାହାଯ୍ୟରେ ଜରୁରୀକାଳୀନ କଲ୍ କରାଯାଇପାରିବ ନାହିଁ"</string>
<string name="notification_channel_network_alert" msgid="4788053066033851841">"ଆଲର୍ଟ"</string>
- <string name="notification_channel_call_forward" msgid="8230490317314272406">"କଲ୍‌ ଫରୱାର୍ଡିଙ୍ଗ"</string>
+ <string name="notification_channel_call_forward" msgid="8230490317314272406">"କଲ୍‌ ଫରୱାର୍ଡିଂ"</string>
<string name="notification_channel_emergency_callback" msgid="54074839059123159">"ଜରୁରୀକାଳୀନ କଲବ୍ୟାକ୍‍ ମୋଡ୍‍"</string>
<string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"ମୋବାଇଲ୍‍ ଡାଟା ଷ୍ଟାଟସ୍‌"</string>
<string name="notification_channel_sms" msgid="1243384981025535724">"SMS ମେସେଜ୍‌"</string>
diff --git a/core/res/res/values-television/themes_device_defaults.xml b/core/res/res/values-television/themes_device_defaults.xml
index cb3d32815ea9..d6bdeee00a9f 100644
--- a/core/res/res/values-television/themes_device_defaults.xml
+++ b/core/res/res/values-television/themes_device_defaults.xml
@@ -33,5 +33,6 @@
<style name="Theme.DeviceDefault.Autofill.Light" parent="Theme.DeviceDefault.Autofill"/>
<style name="Theme.DeviceDefault.Light.Autofill.Save" parent="Theme.DeviceDefault.Autofill.Save"/>
- <style name="Theme.DeviceDefault.Resolver" parent="Theme.Leanback.Resolver" />
+ <style name="Theme.DeviceDefault.ResolverCommon" parent="Theme.Leanback.Resolver" />
+ <style name="Theme.DeviceDefault.Resolver" parent="Theme.DeviceDefault.ResolverCommon" />
</resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index c962256e477c..f42b248f4670 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1830,30 +1830,13 @@
<!-- @hide no longer used, kept to preserve padding -->
<attr name="allowAutoRevokePermissionsExemption" format="boolean" />
- <!-- Declare the app's tolerance to having its permissions automatically revoked when unused for an extended
- period of time -->
+ <!-- No longer used. Declaring this does nothing -->
<attr name="autoRevokePermissions">
- <!-- App supports re-requesting its permissions if revoked.
- Revoking app's permissions doesn't cause user experience issues, aside from a repeated permission request.
-
- Permissions may be automatically revoked from an app if unused. The app must check and possibly request the
- necessary permission on each permission-gated call-->
+ <!-- No longer used -->
<enum name="allowed" value="0" />
- <!-- App may experience degraded functionality when its previously-granted permissions are revoked.
- Revoking app's permissions may cause user experience issues, that are not critical to the user.
-
- Apps with this declaration can choose to request an exemption from auto revoke from user by starting
- an activity with {@code Intent.ACTION_AUTO_REVOKE_PERMISSIONS}. -->
+ <!-- No longer used -->
<enum name="discouraged" value="1" />
- <!-- User may experience severe consequences if this app's permissions are revoked unexpectedly.
-
- E.g. app may fail to do a user-critical background job that may likely impact user's
- safety/security/device accessibility.
-
- This declaration may cause an additional review when publishing your app.
-
- Apps with this declaration are exempt from auto revoke by default, though the user has the final say
- in both revoking the permissions as well as the app's auto revoke exemption status. -->
+ <!-- No longer used -->
<enum name="disallowed" value="2" />
</attr>
</declare-styleable>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 2cad9e6888a6..b79c9e804f89 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -4456,11 +4456,4 @@
<bool name="config_pdp_reject_enable_retry">false</bool>
<!-- pdp data reject retry delay in ms -->
<integer name="config_pdp_reject_retry_delay_ms">-1</integer>
-
- <!-- Package name that is recognized as an actor for the packages listed in
- @array/config_overlayableConfiguratorTargets. If an overlay targeting one of the listed
- targets is signed with the same signature as the configurator, the overlay will be granted
- the "actor" policy. -->
- <string name="config_overlayableConfigurator" translatable="false" />
- <string-array name="config_overlayableConfiguratorTargets" translatable="false" />
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index ad3d20ee5f24..59bb052cbdf5 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -312,6 +312,12 @@
<!-- The margin of the content to an image-->
<dimen name="notification_content_image_margin_end">8dp</dimen>
+ <!-- The padding at the end of actions when the bubble button is visible-->
+ <dimen name="bubble_visible_padding_end">3dp</dimen>
+
+ <!-- The padding at the end of actions when the bubble button is gone-->
+ <dimen name="bubble_gone_padding_end">12dp</dimen>
+
<!-- The spacing between messages in Notification.MessagingStyle -->
<dimen name="notification_messaging_spacing">6dp</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index dc21e878d132..a1c2450be153 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1613,15 +1613,15 @@
<string name="face_error_no_space">Can\u2019t store new face data. Delete an old one first.</string>
<!-- Generic error message shown when the face operation (e.g. enrollment or authentication) is canceled. Generally not shown to the user. [CHAR LIMIT=50] -->
<string name="face_error_canceled">Face operation canceled.</string>
- <!-- Generic error message shown when the face unlock operation is canceled due to user input. Generally not shown to the user [CHAR LIMIT=54] -->
+ <!-- Generic error message shown when the face unlock operation is canceled due to user input. Generally not shown to the user [CHAR LIMIT=68] -->
<string name="face_error_user_canceled">Face unlock canceled by user.</string>
<!-- Generic error message shown when the face operation fails because too many attempts have been made. [CHAR LIMIT=50] -->
<string name="face_error_lockout">Too many attempts. Try again later.</string>
- <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=71] -->
+ <!-- Generic error message shown when the face operation fails because strong authentication is required. [CHAR LIMIT=77] -->
<string name="face_error_lockout_permanent">Too many attempts. Face unlock disabled.</string>
<!-- Generic error message shown when the face hardware can't recognize the face. [CHAR LIMIT=50] -->
<string name="face_error_unable_to_process">Can\u2019t verify face. Try again.</string>
- <!-- Generic error message shown when the user has no enrolled face. [CHAR LIMIT=52] -->
+ <!-- Generic error message shown when the user has no enrolled face. [CHAR LIMIT=59] -->
<string name="face_error_not_enrolled">You haven\u2019t set up face unlock.</string>
<!-- Generic error message shown when the app requests face unlock on a device without a sensor. [CHAR LIMIT=61] -->
<string name="face_error_hw_not_present">Face unlock is not supported on this device.</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f30d482e06b2..051bf7cca2d4 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1785,6 +1785,7 @@
<java-symbol type="string" name="faceunlock_multiple_failures" />
<java-symbol type="string" name="global_actions" />
<java-symbol type="string" name="global_action_power_off" />
+ <java-symbol type="string" name="global_action_power_options" />
<java-symbol type="string" name="global_action_restart" />
<java-symbol type="string" name="global_actions_airplane_mode_off_status" />
<java-symbol type="string" name="global_actions_airplane_mode_on_status" />
@@ -2766,6 +2767,7 @@
<java-symbol type="bool" name="config_mainBuiltInDisplayIsRound" />
<java-symbol type="id" name="actions_container" />
+ <java-symbol type="id" name="actions_container_layout" />
<java-symbol type="id" name="smart_reply_container" />
<java-symbol type="id" name="remote_input_tag" />
<java-symbol type="id" name="pending_intent_tag" />
@@ -3533,6 +3535,8 @@
<java-symbol type="id" name="clip_to_padding_tag" />
<java-symbol type="id" name="clip_children_tag" />
<java-symbol type="id" name="bubble_button" />
+ <java-symbol type="dimen" name="bubble_visible_padding_end" />
+ <java-symbol type="dimen" name="bubble_gone_padding_end" />
<java-symbol type="dimen" name="messaging_avatar_size" />
<java-symbol type="dimen" name="messaging_group_sending_progress_size" />
<java-symbol type="dimen" name="messaging_image_rounding" />
@@ -4033,8 +4037,5 @@
<java-symbol type="string" name="config_pdp_reject_service_not_subscribed" />
<java-symbol type="string" name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" />
- <java-symbol type="string" name="config_overlayableConfigurator" />
- <java-symbol type="array" name="config_overlayableConfiguratorTargets" />
-
<java-symbol type="array" name="config_notificationMsgPkgsAllowedAsConvos" />
</resources>
diff --git a/core/res/res/values/themes_leanback.xml b/core/res/res/values/themes_leanback.xml
index a80725c2758b..9dca9128e362 100644
--- a/core/res/res/values/themes_leanback.xml
+++ b/core/res/res/values/themes_leanback.xml
@@ -128,6 +128,10 @@
<!-- Toolbar attributes -->
<item name="toolbarStyle">@style/Widget.DeviceDefault.Toolbar</item>
+
+ <!-- Icon sizes -->
+ <item name="iconfactoryIconSize">@dimen/resolver_icon_size</item>
+ <item name="iconfactoryBadgeSize">@dimen/resolver_badge_size</item>
</style>
<!-- @hide Special theme for the default system Activity-based Alert dialogs. -->
diff --git a/core/tests/PackageInstallerSessions/Android.bp b/core/tests/PackageInstallerSessions/Android.bp
new file mode 100644
index 000000000000..e74f30ee10a4
--- /dev/null
+++ b/core/tests/PackageInstallerSessions/Android.bp
@@ -0,0 +1,42 @@
+//
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+android_test {
+ name: "FrameworksCorePackageInstallerSessionsTests",
+
+ srcs: [
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "androidx.test.rules",
+ "compatibility-device-util-axt",
+ "frameworks-base-testutils",
+ "platform-test-annotations",
+ "testng",
+ "truth-prebuilt",
+ ],
+
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "framework",
+ "framework-res",
+ ],
+
+ platform_apis: true,
+ sdk_version: "core_platform",
+ test_suites: ["device-tests"],
+}
diff --git a/core/tests/PackageInstallerSessions/AndroidManifest.xml b/core/tests/PackageInstallerSessions/AndroidManifest.xml
new file mode 100644
index 000000000000..5b22d2b4f3e3
--- /dev/null
+++ b/core/tests/PackageInstallerSessions/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.coretests.package_installer_sessions"
+ >
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.coretests.package_installer_sessions"/>
+</manifest>
diff --git a/core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt b/core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt
new file mode 100644
index 000000000000..494c92a8aa3f
--- /dev/null
+++ b/core/tests/PackageInstallerSessions/src/android/content/pm/PackageSessionTests.kt
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm
+
+import android.content.Context
+import android.content.pm.PackageInstaller.SessionParams
+import android.platform.test.annotations.Presubmit
+import androidx.test.InstrumentationRegistry
+import androidx.test.filters.LargeTest
+import com.android.compatibility.common.util.ShellIdentityUtils
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.testng.Assert.assertThrows
+import kotlin.random.Random
+
+/**
+ * For verifying public [PackageInstaller] session APIs. This differs from
+ * [com.android.server.pm.PackageInstallerSessionTest] in services because that mocks the session,
+ * whereas this test uses the installer on device.
+ */
+@Presubmit
+class PackageSessionTests {
+
+ companion object {
+ /**
+ * Permissions marked "hardRestricted" or "softRestricted" in core/res/AndroidManifest.xml.
+ */
+ private val RESTRICTED_PERMISSIONS = listOf(
+ "android.permission.SEND_SMS",
+ "android.permission.RECEIVE_SMS",
+ "android.permission.READ_SMS",
+ "android.permission.RECEIVE_WAP_PUSH",
+ "android.permission.RECEIVE_MMS",
+ "android.permission.READ_CELL_BROADCASTS",
+ "android.permission.ACCESS_BACKGROUND_LOCATION",
+ "android.permission.READ_CALL_LOG",
+ "android.permission.WRITE_CALL_LOG",
+ "android.permission.PROCESS_OUTGOING_CALLS"
+ )
+ }
+
+ private val context: Context = InstrumentationRegistry.getContext()
+
+ private val installer = context.packageManager.packageInstaller
+
+ @Before
+ @After
+ fun abandonAllSessions() {
+ installer.mySessions.asSequence()
+ .map { it.sessionId }
+ .forEach {
+ try {
+ installer.abandonSession(it)
+ } catch (ignored: Exception) {
+ // Querying for sessions checks by calling package name, but abandoning
+ // checks by UID, which won't match if this test failed to clean up
+ // on a previous install + run + uninstall, so ignore these failures.
+ }
+ }
+ }
+
+ @Test
+ fun truncateAppLabel() {
+ val longLabel = invalidAppLabel()
+ val params = SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
+ setAppLabel(longLabel)
+ }
+
+ createSession(params) {
+ assertThat(installer.getSessionInfo(it)?.appLabel)
+ .isEqualTo(longLabel.take(PackageItemInfo.MAX_SAFE_LABEL_LENGTH))
+ }
+ }
+
+ @Test
+ fun removeInvalidAppPackageName() {
+ val longName = invalidPackageName()
+ val params = SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
+ setAppPackageName(longName)
+ }
+
+ createSession(params) {
+ assertThat(installer.getSessionInfo(it)?.appPackageName)
+ .isEqualTo(null)
+ }
+ }
+
+ @Test
+ fun removeInvalidInstallerPackageName() {
+ val longName = invalidPackageName()
+ val params = SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
+ setInstallerPackageName(longName)
+ }
+
+ createSession(params) {
+ // If a custom installer name is dropped, it defaults to the caller
+ assertThat(installer.getSessionInfo(it)?.installerPackageName)
+ .isEqualTo(context.packageName)
+ }
+ }
+
+ @Test
+ fun truncateWhitelistPermissions() {
+ val params = SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
+ setWhitelistedRestrictedPermissions(invalidPermissions())
+ }
+
+ createSession(params) {
+ assertThat(installer.getSessionInfo(it)?.whitelistedRestrictedPermissions!!)
+ .containsExactlyElementsIn(RESTRICTED_PERMISSIONS)
+ }
+ }
+
+ @LargeTest
+ @Test
+ fun allocateMaxSessionsWithPermission() {
+ ShellIdentityUtils.invokeWithShellPermissions {
+ repeat(1024) { createDummySession() }
+ assertThrows(IllegalStateException::class.java) { createDummySession() }
+ }
+ }
+
+ @LargeTest
+ @Test
+ fun allocateMaxSessionsNoPermission() {
+ repeat(50) { createDummySession() }
+ assertThrows(IllegalStateException::class.java) { createDummySession() }
+ }
+
+ private fun createDummySession() {
+ installer.createSession(SessionParams(SessionParams.MODE_FULL_INSTALL)
+ .apply {
+ setAppPackageName(invalidPackageName())
+ setAppLabel(invalidAppLabel())
+ setWhitelistedRestrictedPermissions(invalidPermissions())
+ })
+ }
+
+ private fun invalidPackageName(maxLength: Int = SessionParams.MAX_PACKAGE_NAME_LENGTH): String {
+ return (0 until (maxLength + 10))
+ .asSequence()
+ .mapIndexed { index, _ ->
+ // A package name needs at least one separator
+ if (index == 2) {
+ '.'
+ } else {
+ Random.nextInt('z' - 'a').toChar() + 'a'.toInt()
+ }
+ }
+ .joinToString(separator = "")
+ }
+
+ private fun invalidAppLabel() = (0 until PackageItemInfo.MAX_SAFE_LABEL_LENGTH + 10)
+ .asSequence()
+ .map { Random.nextInt(Char.MAX_VALUE.toInt()).toChar() }
+ .joinToString(separator = "")
+
+ private fun invalidPermissions() = RESTRICTED_PERMISSIONS.toMutableSet()
+ .apply {
+ // Add some invalid permission names
+ repeat(10) { add(invalidPackageName(300)) }
+ }
+
+ private fun createSession(params: SessionParams, block: (Int) -> Unit = {}) {
+ val sessionId = installer.createSession(params)
+ try {
+ block(sessionId)
+ } finally {
+ installer.abandonSession(sessionId)
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/content/ContextTest.java b/core/tests/coretests/src/android/content/ContextTest.java
index f13a11e9edfb..17d1389a6602 100644
--- a/core/tests/coretests/src/android/content/ContextTest.java
+++ b/core/tests/coretests/src/android/content/ContextTest.java
@@ -23,12 +23,14 @@ import static android.view.Display.DEFAULT_DISPLAY;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import android.app.ActivityThread;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
+import android.inputmethodservice.InputMethodService;
import android.media.ImageReader;
import android.os.UserHandle;
import android.view.Display;
@@ -136,6 +138,13 @@ public class ContextTest {
}
@Test
+ public void testIsUiContext_InputMethodService_returnsTrue() {
+ final InputMethodService ims = new InputMethodService();
+
+ assertTrue(ims.isUiContext());
+ }
+
+ @Test
public void testGetDisplayFromDisplayContextDerivedContextOnPrimaryDisplay() {
verifyGetDisplayFromDisplayContextDerivedContext(false /* onSecondaryDisplay */);
}
diff --git a/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java b/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java
index a8ca6f048a11..b329e55b569f 100644
--- a/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java
+++ b/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java
@@ -126,6 +126,32 @@ public class AutofillIdTest {
}
@Test
+ public void testVirtual_Long_withoutSession() {
+ final AutofillId id = new AutofillId(new AutofillId(42), 108L, 666);
+ final AutofillId idWithoutSession = AutofillId.withoutSession(id);
+ assertThat(idWithoutSession.getViewId()).isEqualTo(42);
+ assertThat(idWithoutSession.isVirtualLong()).isTrue();
+ assertThat(idWithoutSession.isVirtualInt()).isFalse();
+ assertThat(idWithoutSession.isNonVirtual()).isFalse();
+ assertThat(idWithoutSession.getVirtualChildLongId()).isEqualTo(108L);
+ assertThat(idWithoutSession.getVirtualChildIntId()).isEqualTo(View.NO_ID);
+ assertThat(idWithoutSession.getSessionId()).isEqualTo(NO_SESSION);
+ }
+
+ @Test
+ public void testVirtual_Int_withoutSession() {
+ final AutofillId id = new AutofillId(42, 108);
+ final AutofillId idWithoutSession = AutofillId.withoutSession(id);
+ assertThat(idWithoutSession.getViewId()).isEqualTo(42);
+ assertThat(idWithoutSession.isVirtualLong()).isFalse();
+ assertThat(idWithoutSession.isVirtualInt()).isTrue();
+ assertThat(idWithoutSession.isNonVirtual()).isFalse();
+ assertThat(idWithoutSession.getVirtualChildIntId()).isEqualTo(108);
+ assertThat(idWithoutSession.getVirtualChildLongId()).isEqualTo(View.NO_ID);
+ assertThat(idWithoutSession.getSessionId()).isEqualTo(NO_SESSION);
+ }
+
+ @Test
public void testSetResetSession() {
final AutofillId id = new AutofillId(42);
assertNonVirtual(id, 42, NO_SESSION);
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index dcecb5f32096..547176855f32 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -34,9 +34,11 @@ import static com.android.internal.app.ChooserListAdapter.SHORTCUT_TARGET_SCORE_
import static com.android.internal.app.ChooserWrapperActivity.sOverrides;
import static com.android.internal.app.MatcherUtils.first;
+import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNull;
import static junit.framework.Assert.assertTrue;
+import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.notNullValue;
@@ -1327,7 +1329,6 @@ public class ChooserActivityTest {
assertThat(activity.getWorkListAdapter().getCount(), is(workProfileTargets));
}
- @Ignore // b/148156663
@Test
public void testWorkTab_selectingWorkTabAppOpensAppInWorkProfile() throws InterruptedException {
// enable the work tab feature flag
@@ -1354,8 +1355,10 @@ public class ChooserActivityTest {
// wait for the share sheet to expand
Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS);
- onView(first(withText(workResolvedComponentInfos.get(0)
- .getResolveInfoAt(0).activityInfo.applicationInfo.name)))
+ onView(first(allOf(
+ withText(workResolvedComponentInfos.get(0)
+ .getResolveInfoAt(0).activityInfo.applicationInfo.name),
+ isDisplayed())))
.perform(click());
waitForIdle();
assertThat(chosen[0], is(workResolvedComponentInfos.get(0).getResolveInfoAt(0)));
@@ -1953,6 +1956,45 @@ public class ChooserActivityTest {
assertThat(activity.getAdapter().getRankedTargetCount(), is(3));
}
+ @Test
+ public void testWorkTab_selectingWorkTabWithPausedWorkProfile_directShareTargetsNotQueried() {
+ // enable the work tab feature flag
+ ResolverActivity.ENABLE_TABBED_VIEW = true;
+ markWorkProfileUserAvailable();
+ List<ResolvedComponentInfo> personalResolvedComponentInfos =
+ createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10);
+ List<ResolvedComponentInfo> workResolvedComponentInfos =
+ createResolvedComponentsForTest(3);
+ setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
+ sOverrides.isQuietModeEnabled = true;
+ boolean[] isQueryDirectShareCalledOnWorkProfile = new boolean[] { false };
+ sOverrides.onQueryDirectShareTargets = chooserListAdapter -> {
+ isQueryDirectShareCalledOnWorkProfile[0] =
+ (chooserListAdapter.getUserHandle().getIdentifier() == 10);
+ return null;
+ };
+ boolean[] isQueryTargetServicesCalledOnWorkProfile = new boolean[] { false };
+ sOverrides.onQueryTargetServices = chooserListAdapter -> {
+ isQueryTargetServicesCalledOnWorkProfile[0] =
+ (chooserListAdapter.getUserHandle().getIdentifier() == 10);
+ return null;
+ };
+ Intent sendIntent = createSendTextIntent();
+ sendIntent.setType("TestType");
+
+ mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test"));
+ waitForIdle();
+ onView(withId(R.id.contentPanel))
+ .perform(swipeUp());
+ onView(withText(R.string.resolver_work_tab)).perform(click());
+ waitForIdle();
+
+ assertFalse("Direct share targets were queried on a paused work profile",
+ isQueryDirectShareCalledOnWorkProfile[0]);
+ assertFalse("Target services were queried on a paused work profile",
+ isQueryTargetServicesCalledOnWorkProfile[0]);
+ }
+
private Intent createChooserIntent(Intent intent, Intent[] initialIntents) {
Intent chooserIntent = new Intent();
chooserIntent.setAction(Intent.ACTION_CHOOSER);
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index 749b0e54b880..44a52639bd35 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -205,6 +205,23 @@ public class ChooserWrapperActivity extends ChooserActivity {
return getApplicationContext();
}
+ @Override
+ protected void queryDirectShareTargets(ChooserListAdapter adapter,
+ boolean skipAppPredictionService) {
+ if (sOverrides.onQueryDirectShareTargets != null) {
+ sOverrides.onQueryDirectShareTargets.apply(adapter);
+ }
+ super.queryDirectShareTargets(adapter, skipAppPredictionService);
+ }
+
+ @Override
+ protected void queryTargetServices(ChooserListAdapter adapter) {
+ if (sOverrides.onQueryTargetServices != null) {
+ sOverrides.onQueryTargetServices.apply(adapter);
+ }
+ super.queryTargetServices(adapter);
+ }
+
/**
* We cannot directly mock the activity created since instrumentation creates it.
* <p>
@@ -214,6 +231,8 @@ public class ChooserWrapperActivity extends ChooserActivity {
@SuppressWarnings("Since15")
public Function<PackageManager, PackageManager> createPackageManager;
public Function<TargetInfo, Boolean> onSafelyStartCallback;
+ public Function<ChooserListAdapter, Void> onQueryDirectShareTargets;
+ public Function<ChooserListAdapter, Void> onQueryTargetServices;
public ResolverListController resolverListController;
public ResolverListController workResolverListController;
public Boolean isVoiceInteraction;
@@ -233,6 +252,8 @@ public class ChooserWrapperActivity extends ChooserActivity {
public void reset() {
onSafelyStartCallback = null;
+ onQueryDirectShareTargets = null;
+ onQueryTargetServices = null;
isVoiceInteraction = null;
createPackageManager = null;
previewThumbnail = null;
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
index 8bee1e5cab3b..7dc5a8b58f91 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityTest.java
@@ -592,7 +592,6 @@ public class ResolverActivityTest {
TextUtils.equals(initialText, currentText));
}
- @Ignore // b/148156663
@Test
public void testWorkTab_noPersonalApps_canStartWorkApps()
throws InterruptedException {
@@ -617,8 +616,10 @@ public class ResolverActivityTest {
waitForIdle();
// wait for the share sheet to expand
Thread.sleep(ChooserActivity.LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS);
- onView(first(allOf(withText(workResolvedComponentInfos.get(0)
- .getResolveInfoAt(0).activityInfo.applicationInfo.name), isCompletelyDisplayed())))
+ onView(first(allOf(
+ withText(workResolvedComponentInfos.get(0)
+ .getResolveInfoAt(0).activityInfo.applicationInfo.name),
+ isDisplayed())))
.perform(click());
onView(withId(R.id.button_once))
.perform(click());
diff --git a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
index 7cd2f3b4c2ab..a4f206586625 100644
--- a/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
+++ b/core/tests/hdmitests/src/android/hardware/hdmi/HdmiAudioSystemClientTest.java
@@ -363,6 +363,16 @@ public class HdmiAudioSystemClientTest {
public boolean isHdmiCecVolumeControlEnabled() {
return true;
}
+
+ @Override
+ public void addHdmiCecVolumeControlFeatureListener(
+ IHdmiCecVolumeControlFeatureListener listener) {
+ }
+
+ @Override
+ public void removeHdmiCecVolumeControlFeatureListener(
+ IHdmiCecVolumeControlFeatureListener listener) {
+ }
}
}
diff --git a/core/tests/overlaytests/remount/Android.bp b/core/tests/overlaytests/remount/Android.bp
index 5757cfe75514..4e79a4574af4 100644
--- a/core/tests/overlaytests/remount/Android.bp
+++ b/core/tests/overlaytests/remount/Android.bp
@@ -28,5 +28,6 @@ java_test_host {
":OverlayRemountedTest_Target",
":OverlayRemountedTest_TargetUpgrade",
":OverlayRemountedTest_Overlay",
+ ":OverlayRemountedTest_Overlay_SameCert",
],
}
diff --git a/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/PackagedUpgradedTest.java b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/RegenerateIdmapTest.java
index a4656403b03f..2b68015536ed 100644
--- a/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/PackagedUpgradedTest.java
+++ b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/RegenerateIdmapTest.java
@@ -22,7 +22,9 @@ import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
-public class PackagedUpgradedTest extends OverlayRemountedTestBase {
+public class RegenerateIdmapTest extends OverlayRemountedTestBase {
+ private static final String OVERLAY_SIGNATURE_APK =
+ "OverlayRemountedTest_Overlay_SameCert.apk";
private static final String TARGET_UPGRADE_APK = "OverlayRemountedTest_TargetUpgrade.apk";
@Test
@@ -66,4 +68,32 @@ public class PackagedUpgradedTest extends OverlayRemountedTestBase {
assertResource(targetReference, "@" + 0x7f0100ff + " -> true");
assertResource(targetOverlaid, "true");
}
+
+ @Test
+ public void testIdmapPoliciesChanged() throws Exception {
+ final String targetResource = resourceName(TARGET_PACKAGE, "bool",
+ "signature_policy_overlaid");
+
+ mPreparer.pushResourceFile(TARGET_APK, "/product/app/OverlayTarget.apk")
+ .pushResourceFile(OVERLAY_APK, "/product/overlay/TestOverlay.apk")
+ .reboot()
+ .setOverlayEnabled(OVERLAY_PACKAGE, false);
+
+ assertResource(targetResource, "false");
+
+ // The overlay is not signed with the same signature as the target.
+ mPreparer.setOverlayEnabled(OVERLAY_PACKAGE, true);
+ assertResource(targetResource, "false");
+
+ // Replace the overlay with a version of the overlay that is signed with the same signature
+ // as the target.
+ mPreparer.pushResourceFile(OVERLAY_SIGNATURE_APK, "/product/overlay/TestOverlay.apk")
+ .reboot();
+
+ // The idmap should have been recreated with the signature policy fulfilled.
+ assertResource(targetResource, "true");
+
+ mPreparer.setOverlayEnabled(OVERLAY_PACKAGE, false);
+ assertResource(targetResource, "false");
+ }
}
diff --git a/core/tests/overlaytests/remount/test-apps/Overlay/Android.bp b/core/tests/overlaytests/remount/test-apps/Overlay/Android.bp
index a1fdbfd3542c..032a0cdcb50d 100644
--- a/core/tests/overlaytests/remount/test-apps/Overlay/Android.bp
+++ b/core/tests/overlaytests/remount/test-apps/Overlay/Android.bp
@@ -19,3 +19,9 @@ android_test_helper_app {
"com.android.overlaytest.overlay",
],
}
+
+android_test_helper_app {
+ name: "OverlayRemountedTest_Overlay_SameCert",
+ certificate: ":rro-remounted-test-a",
+ sdk_version: "current",
+} \ No newline at end of file
diff --git a/core/tests/overlaytests/remount/test-apps/Overlay/res/values/values.xml b/core/tests/overlaytests/remount/test-apps/Overlay/res/values/values.xml
index 675e44f19f95..927d37fc60b9 100644
--- a/core/tests/overlaytests/remount/test-apps/Overlay/res/values/values.xml
+++ b/core/tests/overlaytests/remount/test-apps/Overlay/res/values/values.xml
@@ -17,4 +17,5 @@
<resources>
<bool name="target_overlaid">true</bool>
+ <bool name="signature_policy_overlaid">true</bool>
</resources>
diff --git a/core/tests/overlaytests/remount/test-apps/Target/Android.bp b/core/tests/overlaytests/remount/test-apps/Target/Android.bp
index 19947b1ea51a..e4b4eaa8d220 100644
--- a/core/tests/overlaytests/remount/test-apps/Target/Android.bp
+++ b/core/tests/overlaytests/remount/test-apps/Target/Android.bp
@@ -15,6 +15,7 @@
android_test_helper_app {
name: "OverlayRemountedTest_Target",
sdk_version: "test_current",
+ certificate: ":rro-remounted-test-a",
apex_available: [
"com.android.overlaytest.overlaid",
],
@@ -23,6 +24,7 @@ android_test_helper_app {
android_test_helper_app {
name: "OverlayRemountedTest_TargetUpgrade",
+ certificate: ":rro-remounted-test-a",
resource_dirs: ["res_upgrade"],
sdk_version: "test_current",
}
diff --git a/core/tests/overlaytests/remount/test-apps/Target/res/values/overlayable.xml b/core/tests/overlaytests/remount/test-apps/Target/res/values/overlayable.xml
index 4aa5bcee8f3d..79c9a675a6dd 100644
--- a/core/tests/overlaytests/remount/test-apps/Target/res/values/overlayable.xml
+++ b/core/tests/overlaytests/remount/test-apps/Target/res/values/overlayable.xml
@@ -20,5 +20,8 @@
<policy type="public">
<item type="bool" name="target_overlaid" />
</policy>
+ <policy type="signature">
+ <item type="bool" name="signature_policy_overlaid" />
+ </policy>
</overlayable>
</resources>
diff --git a/core/tests/overlaytests/remount/test-apps/Target/res/values/values.xml b/core/tests/overlaytests/remount/test-apps/Target/res/values/values.xml
index 76253a95b766..64a1683e14be 100644
--- a/core/tests/overlaytests/remount/test-apps/Target/res/values/values.xml
+++ b/core/tests/overlaytests/remount/test-apps/Target/res/values/values.xml
@@ -23,4 +23,6 @@
<bool name="target_overlaid">false</bool>
<public type="bool" name="target_overlaid" id="0x7f010000" />
<bool name="target_reference">@bool/target_overlaid</bool>
+
+ <bool name="signature_policy_overlaid">false</bool>
</resources>
diff --git a/core/tests/overlaytests/remount/test-apps/certs/Android.bp b/core/tests/overlaytests/remount/test-apps/certs/Android.bp
new file mode 100644
index 000000000000..06114efc1249
--- /dev/null
+++ b/core/tests/overlaytests/remount/test-apps/certs/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// development/tools/make_key rro-remounted-test-a '/CN=rro_test_a'
+android_app_certificate {
+ name: "rro-remounted-test-a",
+ certificate: "rro-remounted-test-a",
+}
diff --git a/core/tests/overlaytests/remount/test-apps/certs/rro-remounted-test-a.pk8 b/core/tests/overlaytests/remount/test-apps/certs/rro-remounted-test-a.pk8
new file mode 100644
index 000000000000..aa6cc97d07f6
--- /dev/null
+++ b/core/tests/overlaytests/remount/test-apps/certs/rro-remounted-test-a.pk8
Binary files differ
diff --git a/core/tests/overlaytests/remount/test-apps/certs/rro-remounted-test-a.x509.pem b/core/tests/overlaytests/remount/test-apps/certs/rro-remounted-test-a.x509.pem
new file mode 100644
index 000000000000..be491c7029fe
--- /dev/null
+++ b/core/tests/overlaytests/remount/test-apps/certs/rro-remounted-test-a.x509.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDCzCCAfOgAwIBAgIUfphI+C6W6V6RomsP7+CW5dO5cGcwDQYJKoZIhvcNAQEL
+BQAwFTETMBEGA1UEAwwKcnJvX3Rlc3RfYTAeFw0yMDA1MTQxNjM4MDBaFw00NzA5
+MzAxNjM4MDBaMBUxEzARBgNVBAMMCnJyb190ZXN0X2EwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCvXM8tcqQFwH7iQG6+8mAx2ADhwbtq+8Rcmiz7wviW
+Yf/eFDRuvZ/ma6lxeVJ7mcbF7A5rinEKdgN5hlW2UlbTmuX5YOiXnX3Y2J5t+8Pi
+aq787IvWxkawwkj0Oy1Hk01Z4w3HTYntYqi36bq4QyNpwh515VqgvEyCHT7IPtQi
+XjfwcTW0thUlSDyDkgxq9NxNEJgaHHOamKkeMCO8CkBWkhlcPXvjcM8DPFmyzDI9
+Czv8IYFZQbcG/N2GPH9hSteMnuC+zyoMio0V/VRctQGlAA8ATsheBkng0zcNRu9Z
+GIavk5AaClmBFTeQx01j3HFSO8UDdDJ5Hk8uDTqecPLpAgMBAAGjUzBRMB0GA1Ud
+DgQWBBSPbIdzSkPbzltj3qIS13LNDiyIiDAfBgNVHSMEGDAWgBSPbIdzSkPbzltj
+3qIS13LNDiyIiDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCH
+QvvMGyMvVJaWMEJwVdUnszdXiAlUtDd/2HpdGOxW6xVVAvveP8hJ71gWFQ7Qs3Mr
+3jxclbC37qVAPiQb8kkD8qUgoQYMC43asif6Jn65OU1QkDRF3bFHP+rZVSPEwtvl
+YMbOzHPOLr7HESwlM7TB6EoZ4oOso++jTYI/OSif1MOKOMbOt4X/DE/PXf81ayFs
+uRjpocBqnLwOourABMcaKbA92jB0LRTtgv5ngOJ3+5P1cTiHktFbnqVWa8/A3uSA
+dNR5dpOUjH+nCHTwPl64b7R70PgDxnoqMs0xI7VtJovXor64OZy9P8WTdurz5V/z
+k2IVSi032bf0aTxamvqV
+-----END CERTIFICATE-----
diff --git a/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java b/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java
index fe33cd80f735..4b8173732b4d 100644
--- a/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java
+++ b/core/tests/screenshothelpertests/src/com/android/internal/util/ScreenshotHelperTest.java
@@ -29,11 +29,12 @@ import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.Bitmap;
import android.graphics.Insets;
import android.graphics.Rect;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.WindowManager;
@@ -91,8 +92,7 @@ public final class ScreenshotHelperTest {
@Test
public void testProvidedImageScreenshot() {
mScreenshotHelper.provideScreenshot(
- Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888), new Rect(),
- Insets.of(0, 0, 0, 0), 1,
+ new Bundle(), new Rect(), Insets.of(0, 0, 0, 0), 1, 1, new ComponentName("", ""),
WindowManager.ScreenshotSource.SCREENSHOT_OTHER, mHandler, null);
}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index e00813ce2aaf..9b503eba5c68 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -378,6 +378,9 @@ applications that come with the platform
<permission name="android.permission.SET_WALLPAPER" />
<permission name="android.permission.SET_WALLPAPER_COMPONENT" />
<permission name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" />
+ <!-- Permissions required for Incremental CTS tests -->
+ <permission name="com.android.permission.USE_INSTALLER_V2"/>
+ <permission name="android.permission.LOADER_USAGE_STATS"/>
<!-- Permission required to test system only camera devices. -->
<permission name="android.permission.SYSTEM_CAMERA" />
<!-- Permission required to test ExplicitHealthCheckServiceImpl. -->
@@ -418,6 +421,8 @@ applications that come with the platform
<permission name="android.permission.TV_INPUT_HARDWARE" />
<!-- Permission required for CTS test - PrivilegedLocationPermissionTest -->
<permission name="android.permission.LOCATION_HARDWARE" />
+ <!-- Permissions required for GTS test - GtsDialerAudioTestCases -->
+ <permission name="android.permission.CAPTURE_AUDIO_OUTPUT" />
</privapp-permissions>
<privapp-permissions package="com.android.statementservice">
diff --git a/data/keyboards/Vendor_045e_Product_0b12.kl b/data/keyboards/Vendor_045e_Product_0b12.kl
new file mode 100644
index 000000000000..0b44c7434af2
--- /dev/null
+++ b/data/keyboards/Vendor_045e_Product_0b12.kl
@@ -0,0 +1,59 @@
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# XBox USB Controller
+#
+
+key 304 BUTTON_A
+key 305 BUTTON_B
+key 307 BUTTON_X
+key 308 BUTTON_Y
+key 310 BUTTON_L1
+key 311 BUTTON_R1
+
+key 317 BUTTON_THUMBL
+key 318 BUTTON_THUMBR
+
+# Left and right stick.
+# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
+# This confuses applications that rely on the flat value because the joystick actually
+# settles in a flat range of +/- 4096 or so.
+axis 0x00 X flat 4096
+axis 0x01 Y flat 4096
+axis 0x03 Z flat 4096
+axis 0x04 RZ flat 4096
+
+# Triggers.
+axis 0x02 LTRIGGER
+axis 0x05 RTRIGGER
+
+# Hat.
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+
+# Two overlapping rectangles
+key 314 BUTTON_SELECT
+
+# The branded "X" button in the center of the controller
+key 316 BUTTON_MODE
+
+# Three parallel horizontal lines (hamburger menu)
+key 315 BUTTON_START
+
+#Button below the "X" button
+key 167 MEDIA_RECORD
+
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 2bfc7fc38d1c..21be81cb85bd 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -41,7 +41,7 @@
namespace android {
constexpr const static uint32_t kIdmapMagic = 0x504D4449u;
-constexpr const static uint32_t kIdmapCurrentVersion = 0x00000003u;
+constexpr const static uint32_t kIdmapCurrentVersion = 0x00000004u;
/**
* In C++11, char16_t is defined as *at least* 16 bits. We do a lot of
@@ -1746,6 +1746,9 @@ struct Idmap_header {
uint32_t target_crc32;
uint32_t overlay_crc32;
+ uint32_t fulfilled_policies;
+ uint8_t enforce_overlayable;
+
uint8_t target_path[256];
uint8_t overlay_path[256];
diff --git a/libs/androidfw/tests/data/overlay/overlay.apk b/libs/androidfw/tests/data/overlay/overlay.apk
index 62e98662e68d..f1ed59279fdb 100644
--- a/libs/androidfw/tests/data/overlay/overlay.apk
+++ b/libs/androidfw/tests/data/overlay/overlay.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/overlay/overlay.idmap b/libs/androidfw/tests/data/overlay/overlay.idmap
index 3759ed650033..29c5eb6a9ccf 100644
--- a/libs/androidfw/tests/data/overlay/overlay.idmap
+++ b/libs/androidfw/tests/data/overlay/overlay.idmap
Binary files differ
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
index c652628eb425..590def4d4ced 100644
--- a/media/java/android/media/MediaCas.java
+++ b/media/java/android/media/MediaCas.java
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
+import android.app.ActivityManager;
import android.content.Context;
import android.hardware.cas.V1_0.HidlCasPluginDescriptor;
import android.hardware.cas.V1_0.ICas;
@@ -43,6 +44,8 @@ import android.os.RemoteException;
import android.util.Log;
import android.util.Singleton;
+import com.android.internal.util.FrameworkStatsLog;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -122,6 +125,7 @@ public final class MediaCas implements AutoCloseable {
private String mTvInputServiceSessionId;
private int mClientId;
private int mCasSystemId;
+ private int mUserId;
private TunerResourceManager mTunerResourceManager = null;
private final Map<Session, Integer> mSessionMap = new HashMap<>();
@@ -673,6 +677,8 @@ public final class MediaCas implements AutoCloseable {
*/
public MediaCas(int CA_system_id) throws UnsupportedCasException {
try {
+ mCasSystemId = CA_system_id;
+ mUserId = ActivityManager.getCurrentUser();
IMediaCasService service = getService();
android.hardware.cas.V1_2.IMediaCasService serviceV12 =
android.hardware.cas.V1_2.IMediaCasService.castFrom(service);
@@ -721,7 +727,6 @@ public final class MediaCas implements AutoCloseable {
this(casSystemId);
Objects.requireNonNull(context, "context must not be null");
- mCasSystemId = casSystemId;
mTunerResourceManager = (TunerResourceManager)
context.getSystemService(Context.TV_TUNER_RESOURCE_MGR_SERVICE);
if (mTunerResourceManager != null) {
@@ -925,10 +930,18 @@ public final class MediaCas implements AutoCloseable {
mICas.openSession(cb);
MediaCasException.throwExceptionIfNeeded(cb.mStatus);
addSessionToResourceMap(cb.mSession, sessionResourceHandle);
+ Log.d(TAG, "Write Stats Log for succeed to Open Session.");
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS, mUserId, mCasSystemId,
+ FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS__STATE__SUCCEEDED);
return cb.mSession;
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
+ Log.d(TAG, "Write Stats Log for fail to Open Session.");
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS, mUserId, mCasSystemId,
+ FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS__STATE__FAILED);
return null;
}
@@ -964,10 +977,18 @@ public final class MediaCas implements AutoCloseable {
mICasV12.openSession_1_2(sessionUsage, scramblingMode, cb);
MediaCasException.throwExceptionIfNeeded(cb.mStatus);
addSessionToResourceMap(cb.mSession, sessionResourceHandle);
+ Log.d(TAG, "Write Stats Log for succeed to Open Session.");
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS, mUserId, mCasSystemId,
+ FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS__STATE__SUCCEEDED);
return cb.mSession;
} catch (RemoteException e) {
cleanupAndRethrowIllegalState();
}
+ Log.d(TAG, "Write Stats Log for fail to Open Session.");
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS, mUserId, mCasSystemId,
+ FrameworkStatsLog.TV_CAS_SESSION_OPEN_STATUS__STATE__FAILED);
return null;
}
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 72162c44ec29..05c6e3ad9392 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -137,7 +137,7 @@ public abstract class MediaRoute2ProviderService extends Service {
private final AtomicBoolean mStatePublishScheduled = new AtomicBoolean(false);
private MediaRoute2ProviderServiceStub mStub;
private IMediaRoute2ProviderServiceCallback mRemoteCallback;
- private MediaRoute2ProviderInfo mProviderInfo;
+ private volatile MediaRoute2ProviderInfo mProviderInfo;
@GuardedBy("mSessionLock")
private ArrayMap<String, RoutingSessionInfo> mSessionInfo = new ArrayMap<>();
@@ -167,8 +167,8 @@ public abstract class MediaRoute2ProviderService extends Service {
/**
* Called when a volume setting is requested on a route of the provider
*
- * @param requestId the id of this request
- * @param routeId the id of the route
+ * @param requestId the ID of this request
+ * @param routeId the ID of the route
* @param volume the target volume
* @see MediaRoute2Info.Builder#setVolume(int)
*/
@@ -178,8 +178,8 @@ public abstract class MediaRoute2ProviderService extends Service {
* Called when {@link MediaRouter2.RoutingController#setVolume(int)} is called on
* a routing session of the provider
*
- * @param requestId the id of this request
- * @param sessionId the id of the routing session
+ * @param requestId the ID of this request
+ * @param sessionId the ID of the routing session
* @param volume the target volume
* @see RoutingSessionInfo.Builder#setVolume(int)
*/
@@ -188,7 +188,7 @@ public abstract class MediaRoute2ProviderService extends Service {
/**
* Gets information of the session with the given id.
*
- * @param sessionId id of the session
+ * @param sessionId the ID of the session
* @return information of the session with the given id.
* null if the session is released or ID is not valid.
*/
@@ -218,7 +218,7 @@ public abstract class MediaRoute2ProviderService extends Service {
* If this session is created without any creation request, use {@link #REQUEST_ID_NONE}
* as the request ID.
*
- * @param requestId id of the previous request to create this session provided in
+ * @param requestId the ID of the previous request to create this session provided in
* {@link #onCreateSession(long, String, String, Bundle)}. Can be
* {@link #REQUEST_ID_NONE} if this session is created without any request.
* @param sessionInfo information of the new session.
@@ -233,23 +233,19 @@ public abstract class MediaRoute2ProviderService extends Service {
String sessionId = sessionInfo.getId();
synchronized (mSessionLock) {
if (mSessionInfo.containsKey(sessionId)) {
- // TODO: Notify failure to the requester, and throw exception if needed.
Log.w(TAG, "Ignoring duplicate session id.");
return;
}
mSessionInfo.put(sessionInfo.getId(), sessionInfo);
- }
- if (mRemoteCallback == null) {
- return;
- }
- try {
- // TODO: Calling binder calls in multiple thread may cause timing issue.
- // Consider to change implementations to avoid the problems.
- // For example, post binder calls, always send all sessions at once, etc.
- mRemoteCallback.notifySessionCreated(requestId, sessionInfo);
- } catch (RemoteException ex) {
- Log.w(TAG, "Failed to notify session created.");
+ if (mRemoteCallback == null) {
+ return;
+ }
+ try {
+ mRemoteCallback.notifySessionCreated(requestId, sessionInfo);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Failed to notify session created.");
+ }
}
}
@@ -268,22 +264,22 @@ public abstract class MediaRoute2ProviderService extends Service {
Log.w(TAG, "Ignoring unknown session info.");
return;
}
- }
- if (mRemoteCallback == null) {
- return;
- }
- try {
- mRemoteCallback.notifySessionUpdated(sessionInfo);
- } catch (RemoteException ex) {
- Log.w(TAG, "Failed to notify session info changed.");
+ if (mRemoteCallback == null) {
+ return;
+ }
+ try {
+ mRemoteCallback.notifySessionUpdated(sessionInfo);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Failed to notify session info changed.");
+ }
}
}
/**
* Notifies that the session is released.
*
- * @param sessionId id of the released session.
+ * @param sessionId the ID of the released session.
* @see #onReleaseSession(long, String)
*/
public final void notifySessionReleased(@NonNull String sessionId) {
@@ -293,20 +289,20 @@ public abstract class MediaRoute2ProviderService extends Service {
RoutingSessionInfo sessionInfo;
synchronized (mSessionLock) {
sessionInfo = mSessionInfo.remove(sessionId);
- }
- if (sessionInfo == null) {
- Log.w(TAG, "Ignoring unknown session info.");
- return;
- }
+ if (sessionInfo == null) {
+ Log.w(TAG, "Ignoring unknown session info.");
+ return;
+ }
- if (mRemoteCallback == null) {
- return;
- }
- try {
- mRemoteCallback.notifySessionReleased(sessionInfo);
- } catch (RemoteException ex) {
- Log.w(TAG, "Failed to notify session info changed.");
+ if (mRemoteCallback == null) {
+ return;
+ }
+ try {
+ mRemoteCallback.notifySessionReleased(sessionInfo);
+ } catch (RemoteException ex) {
+ Log.w(TAG, "Failed to notify session info changed.");
+ }
}
}
@@ -349,9 +345,9 @@ public abstract class MediaRoute2ProviderService extends Service {
* If you can't create the session or want to reject the request, call
* {@link #notifyRequestFailed(long, int)} with the given {@code requestId}.
*
- * @param requestId the id of this request
+ * @param requestId the ID of this request
* @param packageName the package name of the application that selected the route
- * @param routeId the id of the route initially being connected
+ * @param routeId the ID of the route initially being connected
* @param sessionHints an optional bundle of app-specific arguments sent by
* {@link MediaRouter2}, or null if none. The contents of this bundle
* may affect the result of session creation.
@@ -373,8 +369,8 @@ public abstract class MediaRoute2ProviderService extends Service {
* Note: Calling {@link #notifySessionReleased(String)} will <em>NOT</em> trigger
* this method to be called.
*
- * @param requestId the id of this request
- * @param sessionId id of the session being released.
+ * @param requestId the ID of this request
+ * @param sessionId the ID of the session being released.
* @see #notifySessionReleased(String)
* @see #getSessionInfo(String)
*/
@@ -385,9 +381,9 @@ public abstract class MediaRoute2ProviderService extends Service {
* After the route is selected, call {@link #notifySessionUpdated(RoutingSessionInfo)}
* to update session info.
*
- * @param requestId the id of this request
- * @param sessionId id of the session
- * @param routeId id of the route
+ * @param requestId the ID of this request
+ * @param sessionId the ID of the session
+ * @param routeId the ID of the route
*/
public abstract void onSelectRoute(long requestId, @NonNull String sessionId,
@NonNull String routeId);
@@ -397,9 +393,9 @@ public abstract class MediaRoute2ProviderService extends Service {
* After the route is deselected, call {@link #notifySessionUpdated(RoutingSessionInfo)}
* to update session info.
*
- * @param requestId the id of this request
- * @param sessionId id of the session
- * @param routeId id of the route
+ * @param requestId the ID of this request
+ * @param sessionId the ID of the session
+ * @param routeId the ID of the route
*/
public abstract void onDeselectRoute(long requestId, @NonNull String sessionId,
@NonNull String routeId);
@@ -409,9 +405,9 @@ public abstract class MediaRoute2ProviderService extends Service {
* After the transfer is finished, call {@link #notifySessionUpdated(RoutingSessionInfo)}
* to update session info.
*
- * @param requestId the id of this request
- * @param sessionId id of the session
- * @param routeId id of the route
+ * @param requestId the ID of this request
+ * @param sessionId the ID of the session
+ * @param routeId the ID of the route
*/
public abstract void onTransferToRoute(long requestId, @NonNull String sessionId,
@NonNull String routeId);
@@ -476,13 +472,39 @@ public abstract class MediaRoute2ProviderService extends Service {
final class MediaRoute2ProviderServiceStub extends IMediaRoute2ProviderService.Stub {
MediaRoute2ProviderServiceStub() { }
- boolean checkCallerisSystem() {
+ private boolean checkCallerIsSystem() {
return Binder.getCallingUid() == Process.SYSTEM_UID;
}
+ private boolean checkSessionIdIsValid(String sessionId, String description) {
+ if (TextUtils.isEmpty(sessionId)) {
+ Log.w(TAG, description + ": Ignoring empty sessionId from system service.");
+ return false;
+ }
+ if (getSessionInfo(sessionId) == null) {
+ Log.w(TAG, description + ": Ignoring unknown session from system service. "
+ + "sessionId=" + sessionId);
+ return false;
+ }
+ return true;
+ }
+
+ private boolean checkRouteIdIsValid(String routeId, String description) {
+ if (TextUtils.isEmpty(routeId)) {
+ Log.w(TAG, description + ": Ignoring empty routeId from system service.");
+ return false;
+ }
+ if (mProviderInfo == null || mProviderInfo.getRoute(routeId) == null) {
+ Log.w(TAG, description + ": Ignoring unknown route from system service. "
+ + "routeId=" + routeId);
+ return false;
+ }
+ return true;
+ }
+
@Override
public void setCallback(IMediaRoute2ProviderServiceCallback callback) {
- if (!checkCallerisSystem()) {
+ if (!checkCallerIsSystem()) {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::setCallback,
@@ -491,7 +513,7 @@ public abstract class MediaRoute2ProviderService extends Service {
@Override
public void updateDiscoveryPreference(RouteDiscoveryPreference discoveryPreference) {
- if (!checkCallerisSystem()) {
+ if (!checkCallerIsSystem()) {
return;
}
mHandler.sendMessage(obtainMessage(
@@ -501,7 +523,10 @@ public abstract class MediaRoute2ProviderService extends Service {
@Override
public void setRouteVolume(long requestId, String routeId, int volume) {
- if (!checkCallerisSystem()) {
+ if (!checkCallerIsSystem()) {
+ return;
+ }
+ if (!checkRouteIdIsValid(routeId, "setRouteVolume")) {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSetRouteVolume,
@@ -511,7 +536,10 @@ public abstract class MediaRoute2ProviderService extends Service {
@Override
public void requestCreateSession(long requestId, String packageName, String routeId,
@Nullable Bundle requestCreateSession) {
- if (!checkCallerisSystem()) {
+ if (!checkCallerIsSystem()) {
+ return;
+ }
+ if (!checkRouteIdIsValid(routeId, "requestCreateSession")) {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onCreateSession,
@@ -519,14 +547,13 @@ public abstract class MediaRoute2ProviderService extends Service {
requestCreateSession));
}
- //TODO: Ignore requests with unknown session ID.
@Override
public void selectRoute(long requestId, String sessionId, String routeId) {
- if (!checkCallerisSystem()) {
+ if (!checkCallerIsSystem()) {
return;
}
- if (TextUtils.isEmpty(sessionId)) {
- Log.w(TAG, "selectRoute: Ignoring empty sessionId from system service.");
+ if (!checkSessionIdIsValid(sessionId, "selectRoute")
+ || !checkRouteIdIsValid(routeId, "selectRoute")) {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSelectRoute,
@@ -535,11 +562,11 @@ public abstract class MediaRoute2ProviderService extends Service {
@Override
public void deselectRoute(long requestId, String sessionId, String routeId) {
- if (!checkCallerisSystem()) {
+ if (!checkCallerIsSystem()) {
return;
}
- if (TextUtils.isEmpty(sessionId)) {
- Log.w(TAG, "deselectRoute: Ignoring empty sessionId from system service.");
+ if (!checkSessionIdIsValid(sessionId, "deselectRoute")
+ || !checkRouteIdIsValid(routeId, "deselectRoute")) {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onDeselectRoute,
@@ -548,11 +575,11 @@ public abstract class MediaRoute2ProviderService extends Service {
@Override
public void transferToRoute(long requestId, String sessionId, String routeId) {
- if (!checkCallerisSystem()) {
+ if (!checkCallerIsSystem()) {
return;
}
- if (TextUtils.isEmpty(sessionId)) {
- Log.w(TAG, "transferToRoute: Ignoring empty sessionId from system service.");
+ if (!checkSessionIdIsValid(sessionId, "transferToRoute")
+ || !checkRouteIdIsValid(routeId, "transferToRoute")) {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onTransferToRoute,
@@ -561,7 +588,10 @@ public abstract class MediaRoute2ProviderService extends Service {
@Override
public void setSessionVolume(long requestId, String sessionId, int volume) {
- if (!checkCallerisSystem()) {
+ if (!checkCallerIsSystem()) {
+ return;
+ }
+ if (!checkSessionIdIsValid(sessionId, "setSessionVolume")) {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSetSessionVolume,
@@ -570,11 +600,10 @@ public abstract class MediaRoute2ProviderService extends Service {
@Override
public void releaseSession(long requestId, String sessionId) {
- if (!checkCallerisSystem()) {
+ if (!checkCallerIsSystem()) {
return;
}
- if (TextUtils.isEmpty(sessionId)) {
- Log.w(TAG, "releaseSession: Ignoring empty sessionId from system service.");
+ if (!checkSessionIdIsValid(sessionId, "releaseSession")) {
return;
}
mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onReleaseSession,
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 6179b483ca53..6634d4b4190e 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -54,7 +54,7 @@ import java.util.stream.Collectors;
* Media Router 2 allows applications to control the routing of media channels
* and streams from the current device to remote speakers and devices.
*/
-// TODO: Add method names at the beginning of log messages. (e.g. updateControllerOnHandler)
+// TODO(b/157873330): Add method names at the beginning of log messages. (e.g. selectRoute)
// Not only MediaRouter2, but also to service / manager / provider.
// TODO: ensure thread-safe and document it
public final class MediaRouter2 {
@@ -399,7 +399,7 @@ public final class MediaRouter2 {
Objects.requireNonNull(controller, "controller must not be null");
Objects.requireNonNull(route, "route must not be null");
- // TODO: Check thread-safety
+ // TODO(b/157873496): Check thread-safety, at least check "sRouterLock" for every variable
if (!mRoutes.containsKey(route.getId())) {
notifyTransferFailure(route);
return;
@@ -501,7 +501,7 @@ public final class MediaRouter2 {
}
void addRoutesOnHandler(List<MediaRoute2Info> routes) {
- // TODO: When onRoutesAdded is first called,
+ // TODO(b/157874065): When onRoutesAdded is first called,
// 1) clear mRoutes before adding the routes
// 2) Call onRouteSelected(system_route, reason_fallback) if previously selected route
// does not exist anymore. => We may need 'boolean MediaRoute2Info#isSystemRoute()'.
@@ -1214,7 +1214,7 @@ public final class MediaRouter2 {
* Any operations on this controller after calling this method will be ignored.
* The devices that are playing media will stop playing it.
*/
- // TODO: Add tests using {@link MediaRouter2Manager#getActiveSessions()}.
+ // TODO(b/157872573): Add tests using {@link MediaRouter2Manager#getActiveSessions()}.
public void release() {
releaseInternal(/* shouldReleaseSession= */ true, /* shouldNotifyStop= */ true);
}
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 4ebfce830a70..a382c2de223e 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -151,8 +151,6 @@ public final class MediaRouter2Manager {
return null;
}
- //TODO: Use cache not to create array. For now, it's unclear when to purge the cache.
- //Do this when we finalize how to set control categories.
/**
* Gets available routes for an application.
*
@@ -339,7 +337,7 @@ public final class MediaRouter2Manager {
Objects.requireNonNull(sessionInfo, "sessionInfo must not be null");
Objects.requireNonNull(route, "route must not be null");
- //TODO: Ignore unknown route.
+ //TODO(b/157875504): Ignore unknown route.
if (sessionInfo.getTransferableRoutes().contains(route.getId())) {
transferToRoute(sessionInfo, route);
return;
@@ -355,7 +353,7 @@ public final class MediaRouter2Manager {
if (client != null) {
try {
int requestId = mNextRequestId.getAndIncrement();
- //TODO: Ensure that every request is eventually removed.
+ //TODO(b/157875723): Ensure that every request is eventually removed. (Memory leak)
mTransferRequests.add(new TransferRequest(requestId, sessionInfo, route));
mMediaRouterService.requestCreateSessionWithManager(
diff --git a/media/java/android/media/projection/MediaProjectionManager.java b/media/java/android/media/projection/MediaProjectionManager.java
index c4d27eca02f8..e719b2a04720 100644
--- a/media/java/android/media/projection/MediaProjectionManager.java
+++ b/media/java/android/media/projection/MediaProjectionManager.java
@@ -90,6 +90,17 @@ public final class MediaProjectionManager {
* projection is stopped. This allows for user controls to be displayed on top of the screen
* being captured.
*
+ * <p>
+ * Apps targeting SDK version {@link android.os.Build.VERSION_CODES#Q} or later should specify
+ * the foreground service type using the attribute {@link android.R.attr#foregroundServiceType}
+ * in the service element of the app's manifest file.
+ * The {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION} attribute
+ * should be specified.
+ * </p>
+ *
+ * @see <a href="https://developer.android.com/preview/privacy/foreground-service-types">
+ * Foregroud Service Types</a>
+ *
* @param resultCode The result code from {@link android.app.Activity#onActivityResult(int,
* int, android.content.Intent)}
* @param resultData The resulting data from {@link android.app.Activity#onActivityResult(int,
diff --git a/media/java/android/media/tv/TvRecordingClient.java b/media/java/android/media/tv/TvRecordingClient.java
index 8ae98ae5e937..23fadac8a72b 100644
--- a/media/java/android/media/tv/TvRecordingClient.java
+++ b/media/java/android/media/tv/TvRecordingClient.java
@@ -146,6 +146,8 @@ public class TvRecordingClient {
mPendingAppPrivateCommands.clear();
if (mSession != null) {
mSession.release();
+ mIsTuned = false;
+ mIsRecordingStarted = false;
mSession = null;
}
}
diff --git a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
index 68071b0b0fe3..bb00bb3b8d56 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
@@ -20,12 +20,16 @@ import android.annotation.BytesLong;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.app.ActivityManager;
import android.hardware.tv.tuner.V1_0.Constants;
import android.media.tv.tuner.Tuner;
import android.media.tv.tuner.Tuner.Result;
import android.media.tv.tuner.TunerUtils;
import android.media.tv.tuner.filter.Filter;
import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import com.android.internal.util.FrameworkStatsLog;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -72,9 +76,15 @@ public class DvrPlayback implements AutoCloseable {
*/
public static final int PLAYBACK_STATUS_FULL = Constants.PlaybackStatus.SPACE_FULL;
+ private static final String TAG = "TvTunerPlayback";
+
private long mNativeContext;
private OnPlaybackStatusChangedListener mListener;
private Executor mExecutor;
+ private int mUserId;
+ private static int sInstantId = 0;
+ private int mSegmentId = 0;
+ private int mUnderflow;
private native int nativeAttachFilter(Filter filter);
private native int nativeDetachFilter(Filter filter);
@@ -88,6 +98,9 @@ public class DvrPlayback implements AutoCloseable {
private native long nativeRead(byte[] bytes, long offset, long size);
private DvrPlayback() {
+ mUserId = ActivityManager.getCurrentUser();
+ mSegmentId = (sInstantId & 0x0000ffff) << 16;
+ sInstantId++;
}
/** @hide */
@@ -98,6 +111,9 @@ public class DvrPlayback implements AutoCloseable {
}
private void onPlaybackStatusChanged(int status) {
+ if (status == PLAYBACK_STATUS_EMPTY) {
+ mUnderflow++;
+ }
if (mExecutor != null && mListener != null) {
mExecutor.execute(() -> mListener.onPlaybackStatusChanged(status));
}
@@ -154,6 +170,13 @@ public class DvrPlayback implements AutoCloseable {
*/
@Result
public int start() {
+ mSegmentId = (mSegmentId & 0xffff0000) | (((mSegmentId & 0x0000ffff) + 1) & 0x0000ffff);
+ mUnderflow = 0;
+ Log.d(TAG, "Write Stats Log for Playback.");
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId,
+ FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__PLAYBACK,
+ FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STARTED, mSegmentId, 0);
return nativeStartDvr();
}
@@ -167,6 +190,11 @@ public class DvrPlayback implements AutoCloseable {
*/
@Result
public int stop() {
+ Log.d(TAG, "Write Stats Log for Playback.");
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId,
+ FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__PLAYBACK,
+ FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STOPPED, mSegmentId, mUnderflow);
return nativeStopDvr();
}
diff --git a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
index 198bd0f4e78e..887116725961 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
@@ -19,14 +19,19 @@ package android.media.tv.tuner.dvr;
import android.annotation.BytesLong;
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.app.ActivityManager;
import android.media.tv.tuner.Tuner;
import android.media.tv.tuner.Tuner.Result;
import android.media.tv.tuner.TunerUtils;
import android.media.tv.tuner.filter.Filter;
import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import com.android.internal.util.FrameworkStatsLog;
import java.util.concurrent.Executor;
+
/**
* Digital Video Record (DVR) recorder class which provides record control on Demux's output buffer.
*
@@ -34,9 +39,14 @@ import java.util.concurrent.Executor;
*/
@SystemApi
public class DvrRecorder implements AutoCloseable {
+ private static final String TAG = "TvTunerRecord";
private long mNativeContext;
private OnRecordStatusChangedListener mListener;
private Executor mExecutor;
+ private int mUserId;
+ private static int sInstantId = 0;
+ private int mSegmentId = 0;
+ private int mOverflow;
private native int nativeAttachFilter(Filter filter);
private native int nativeDetachFilter(Filter filter);
@@ -50,6 +60,9 @@ public class DvrRecorder implements AutoCloseable {
private native long nativeWrite(byte[] bytes, long offset, long size);
private DvrRecorder() {
+ mUserId = ActivityManager.getCurrentUser();
+ mSegmentId = (sInstantId & 0x0000ffff) << 16;
+ sInstantId++;
}
/** @hide */
@@ -60,6 +73,9 @@ public class DvrRecorder implements AutoCloseable {
}
private void onRecordStatusChanged(int status) {
+ if (status == Filter.STATUS_OVERFLOW) {
+ mOverflow++;
+ }
if (mExecutor != null && mListener != null) {
mExecutor.execute(() -> mListener.onRecordStatusChanged(status));
}
@@ -112,6 +128,13 @@ public class DvrRecorder implements AutoCloseable {
*/
@Result
public int start() {
+ mSegmentId = (mSegmentId & 0xffff0000) | (((mSegmentId & 0x0000ffff) + 1) & 0x0000ffff);
+ mOverflow = 0;
+ Log.d(TAG, "Write Stats Log for Record.");
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId,
+ FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__RECORD,
+ FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STARTED, mSegmentId, 0);
return nativeStartDvr();
}
@@ -124,6 +147,11 @@ public class DvrRecorder implements AutoCloseable {
*/
@Result
public int stop() {
+ Log.d(TAG, "Write Stats Log for Playback.");
+ FrameworkStatsLog
+ .write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId,
+ FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__RECORD,
+ FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STOPPED, mSegmentId, mOverflow);
return nativeStopDvr();
}
diff --git a/media/jni/soundpool/Sound.cpp b/media/jni/soundpool/Sound.cpp
index c3abdc22b19d..f8b4bdb1f4d5 100644
--- a/media/jni/soundpool/Sound.cpp
+++ b/media/jni/soundpool/Sound.cpp
@@ -31,7 +31,7 @@ constexpr size_t kDefaultHeapSize = 1024 * 1024; // 1MB (compatible with low m
Sound::Sound(int32_t soundID, int fd, int64_t offset, int64_t length)
: mSoundID(soundID)
- , mFd(fcntl(fd, F_DUPFD_CLOEXEC)) // like dup(fd) but closes on exec to prevent leaks.
+ , mFd(fcntl(fd, F_DUPFD_CLOEXEC, (int)0 /* arg */)) // dup(fd) + close on exec to prevent leaks.
, mOffset(offset)
, mLength(length)
{
diff --git a/media/jni/soundpool/SoundDecoder.cpp b/media/jni/soundpool/SoundDecoder.cpp
index 6614fdb5af53..5ed10b0d785f 100644
--- a/media/jni/soundpool/SoundDecoder.cpp
+++ b/media/jni/soundpool/SoundDecoder.cpp
@@ -107,7 +107,8 @@ void SoundDecoder::loadSound(int32_t soundID)
}
// Launch threads as needed. The "as needed" is weakly consistent as we release mLock.
if (pendingSounds > mThreadPool->getActiveThreadCount()) {
- const int32_t id __unused = mThreadPool->launch([this](int32_t id) { run(id); });
+ const int32_t id = mThreadPool->launch([this](int32_t id) { run(id); });
+ (void)id; // avoid clang warning -Wunused-variable -Wused-but-marked-unused
ALOGV_IF(id != 0, "%s: launched thread %d", __func__, id);
}
}
diff --git a/media/jni/soundpool/Stream.cpp b/media/jni/soundpool/Stream.cpp
index a6d975851619..e7042d0562a4 100644
--- a/media/jni/soundpool/Stream.cpp
+++ b/media/jni/soundpool/Stream.cpp
@@ -203,7 +203,7 @@ void Stream::stop()
void Stream::stop_l()
{
if (mState != IDLE) {
- ALOGV("%s: track streamID: %d", __func__, (int)mStreamID);
+ ALOGV("%s: track(%p) streamID: %d", __func__, mAudioTrack.get(), (int)mStreamID);
if (mAudioTrack != nullptr) {
mAudioTrack->stop();
}
@@ -232,7 +232,7 @@ Stream* Stream::playPairStream() {
LOG_ALWAYS_FATAL_IF(pairStream == nullptr, "No pair stream!");
sp<AudioTrack> releaseTracks[2];
{
- ALOGV("%s: track streamID: %d", __func__, (int)mStreamID);
+ ALOGV("%s: track streamID: %d", __func__, (int)getStreamID());
// TODO: Do we really want to force a simultaneous synchronization between
// the stream and its pair?
@@ -390,10 +390,10 @@ void Stream::staticCallback(int event, void* user, void* info)
void Stream::callback(int event, void* info, int toggle, int tries)
{
- ALOGV("%s streamID %d", __func__, (int)mStreamID);
int32_t activeStreamIDToRestart = 0;
{
std::unique_lock lock(mLock);
+ ALOGV("%s track(%p) streamID %d", __func__, mAudioTrack.get(), (int)mStreamID);
if (mAudioTrack == nullptr) {
// The AudioTrack is either with this stream or its pair.
@@ -403,6 +403,7 @@ void Stream::callback(int event, void* info, int toggle, int tries)
// logic here.
if (tries < 3) {
lock.unlock();
+ ALOGV("%s streamID %d going to pair stream", __func__, (int)mStreamID);
getPairStream()->callback(event, info, toggle, tries + 1);
} else {
ALOGW("%s streamID %d cannot find track", __func__, (int)mStreamID);
@@ -449,8 +450,9 @@ void Stream::callback(int event, void* info, int toggle, int tries)
void Stream::dump() const
{
+ // TODO: consider std::try_lock() - ok for now for ALOGV.
ALOGV("mPairStream=%p, mState=%d, mStreamID=%d, mSoundID=%d, mPriority=%d, mLoop=%d",
- getPairStream(), mState, (int)mStreamID, mSoundID, mPriority, mLoop);
+ getPairStream(), mState, (int)getStreamID(), getSoundID(), mPriority, mLoop);
}
} // namespace android::soundpool
diff --git a/media/jni/soundpool/Stream.h b/media/jni/soundpool/Stream.h
index fd929210eb46..d4e5c9fe7f8a 100644
--- a/media/jni/soundpool/Stream.h
+++ b/media/jni/soundpool/Stream.h
@@ -88,7 +88,7 @@ public:
void resume(int32_t streamID);
void autoResume();
void mute(bool muting);
- void dump() const;
+ void dump() const NO_THREAD_SAFETY_ANALYSIS; // disable for ALOGV (see func for details).
// returns the pair stream if successful, nullptr otherwise
Stream* playPairStream();
diff --git a/media/jni/soundpool/StreamManager.cpp b/media/jni/soundpool/StreamManager.cpp
index 9ff4254284dc..5b6494d4947e 100644
--- a/media/jni/soundpool/StreamManager.cpp
+++ b/media/jni/soundpool/StreamManager.cpp
@@ -249,7 +249,8 @@ int32_t StreamManager::queueForPlay(const std::shared_ptr<Sound> &sound,
} // lock
if (launchThread) {
- const int32_t id __unused = mThreadPool->launch([this](int32_t id) { run(id); });
+ const int32_t id = mThreadPool->launch([this](int32_t id) { run(id); });
+ (void)id; // avoid clang warning -Wunused-variable -Wused-but-marked-unused
ALOGV_IF(id != 0, "%s: launched thread %d", __func__, id);
}
ALOGV("%s: returning %d", __func__, streamID);
@@ -277,7 +278,8 @@ void StreamManager::moveToRestartQueue(
sanityCheckQueue_l();
}
if (restart) {
- const int32_t id __unused = mThreadPool->launch([this](int32_t id) { run(id); });
+ const int32_t id = mThreadPool->launch([this](int32_t id) { run(id); });
+ (void)id; // avoid clang warning -Wunused-variable -Wused-but-marked-unused
ALOGV_IF(id != 0, "%s: launched thread %d", __func__, id);
}
}
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
index c05c21cf2752..1e49f49b37bc 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java
@@ -109,7 +109,7 @@ public class MediaRouter2ManagerTest {
mContext = InstrumentationRegistry.getTargetContext();
mManager = MediaRouter2Manager.getInstance(mContext);
mRouter2 = MediaRouter2.getInstance(mContext);
- //TODO: If we need to support thread pool executors, change this to thread pool executor.
+ // If we need to support thread pool executors, change this to thread pool executor.
mExecutor = Executors.newSingleThreadExecutor();
mPackageName = mContext.getPackageName();
}
@@ -253,7 +253,6 @@ public class MediaRouter2ManagerTest {
CountDownLatch latch = new CountDownLatch(1);
addManagerCallback(new MediaRouter2Manager.Callback());
- //TODO: remove this when it's not necessary.
addRouterCallback(new MediaRouter2.RouteCallback() {});
addTransferCallback(new MediaRouter2.TransferCallback() {
@Override
diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp
index 2a8a39a1fe1a..32b33a758535 100644
--- a/packages/CarSystemUI/Android.bp
+++ b/packages/CarSystemUI/Android.bp
@@ -32,6 +32,7 @@ android_library {
"SystemUIPluginLib",
"SystemUISharedLib",
"SettingsLib",
+ "car-ui-lib",
"android.car.userlib",
"androidx.legacy_legacy-support-v4",
"androidx.recyclerview_recyclerview",
@@ -95,6 +96,7 @@ android_library {
"androidx.slice_slice-builders",
"androidx.arch.core_core-runtime",
"androidx.lifecycle_lifecycle-extensions",
+ "car-ui-lib",
"SystemUI-tags",
"SystemUI-proto",
"metrics-helper-lib",
diff --git a/packages/CarSystemUI/res/layout/car_left_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_left_navigation_bar.xml
index a8c70989253e..94816f81a4c5 100644
--- a/packages/CarSystemUI/res/layout/car_left_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_left_navigation_bar.xml
@@ -79,7 +79,7 @@
android:gravity="bottom"
android:orientation="vertical">
- <com.android.keyguard.AlphaOptimizedImageButton
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
android:id="@+id/note"
android:layout_height="wrap_content"
android:layout_width="match_parent"
diff --git a/packages/CarSystemUI/res/layout/car_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
index 2a715d0c3494..93174983b116 100644
--- a/packages/CarSystemUI/res/layout/car_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_navigation_bar.xml
@@ -29,9 +29,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:paddingStart="20dp"
+ android:gravity="center"
+ android:layoutDirection="ltr"
android:paddingEnd="20dp"
- android:gravity="center">
+ android:paddingStart="20dp">
<com.android.systemui.car.navigationbar.CarNavigationButton
android:id="@+id/home"
@@ -135,9 +136,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:paddingStart="@dimen/car_keyline_1"
- android:paddingEnd="@dimen/car_keyline_1"
android:gravity="center"
+ android:layoutDirection="ltr"
+ android:paddingEnd="@dimen/car_keyline_1"
+ android:paddingStart="@dimen/car_keyline_1"
android:visibility="gone"
/>
diff --git a/packages/CarSystemUI/res/layout/car_navigation_button.xml b/packages/CarSystemUI/res/layout/car_navigation_button.xml
index ca4e76ee104b..a8f115742023 100644
--- a/packages/CarSystemUI/res/layout/car_navigation_button.xml
+++ b/packages/CarSystemUI/res/layout/car_navigation_button.xml
@@ -27,7 +27,7 @@
android:animateLayoutChanges="true"
android:orientation="vertical">
- <com.android.keyguard.AlphaOptimizedImageButton
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
android:id="@+id/car_nav_button_icon_image"
android:layout_height="@dimen/car_navigation_button_icon_height"
android:layout_width="match_parent"
@@ -40,7 +40,7 @@
android:clickable="false"
/>
- <com.android.keyguard.AlphaOptimizedImageButton
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
android:id="@+id/car_nav_button_more_icon"
android:layout_height="wrap_content"
android:layout_width="match_parent"
diff --git a/packages/CarSystemUI/res/layout/car_right_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_right_navigation_bar.xml
index fd75570e759c..dc9583382921 100644
--- a/packages/CarSystemUI/res/layout/car_right_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_right_navigation_bar.xml
@@ -82,7 +82,7 @@
android:gravity="bottom"
android:orientation="vertical">
- <com.android.keyguard.AlphaOptimizedImageButton
+ <com.android.systemui.statusbar.AlphaOptimizedImageView
android:id="@+id/note"
android:layout_height="wrap_content"
android:layout_width="match_parent"
diff --git a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
index 60e0d7e430df..cdc29eec21cd 100644
--- a/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
+++ b/packages/CarSystemUI/res/layout/car_top_navigation_bar.xml
@@ -27,7 +27,8 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_weight="1">
+ android:layout_weight="1"
+ android:layoutDirection="ltr">
<FrameLayout
android:id="@+id/left_hvac_container"
diff --git a/packages/CarSystemUI/res/layout/headsup_container_bottom.xml b/packages/CarSystemUI/res/layout/headsup_container_bottom.xml
index caf1677234d0..1782d2536035 100644
--- a/packages/CarSystemUI/res/layout/headsup_container_bottom.xml
+++ b/packages/CarSystemUI/res/layout/headsup_container_bottom.xml
@@ -29,6 +29,15 @@
android:orientation="horizontal"
app:layout_constraintGuide_begin="@dimen/headsup_scrim_height"/>
+ <!-- Include a FocusParkingView at the beginning or end. The rotary controller "parks" the
+ focus here when the user navigates to another window. This is also used to prevent
+ wrap-around which is why it must be first or last in Tab order. -->
+ <com.android.car.ui.FocusParkingView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:layout_constraintLeft_toLeftOf="parent"
+ app:layout_constraintTop_toTopOf="parent"/>
+
<View
android:id="@+id/scrim"
android:layout_width="match_parent"
diff --git a/packages/CarSystemUI/res/values/styles.xml b/packages/CarSystemUI/res/values/styles.xml
index 371bebdebc86..7fc69e6d5d8f 100644
--- a/packages/CarSystemUI/res/values/styles.xml
+++ b/packages/CarSystemUI/res/values/styles.xml
@@ -44,6 +44,6 @@
<style name="NavigationBarButton">
<item name="android:layout_height">96dp</item>
<item name="android:layout_width">96dp</item>
- <item name="android:background">@drawable/nav_button_background</item>
+ <item name="android:background">@*android:drawable/item_background_material</item>
</style>
</resources> \ No newline at end of file
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
index ab61b443df97..2dad5f872e73 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java
@@ -219,6 +219,14 @@ public class CarKeyguardViewController extends OverlayViewController implements
}
@Override
+ public void setOccluded(boolean occluded, boolean animate) {
+ getOverlayViewGlobalStateController().setOccluded(occluded);
+ if (!occluded) {
+ reset(/* hideBouncerWhenShowing= */ false);
+ }
+ }
+
+ @Override
public void onCancelClicked() {
if (mBouncer == null) return;
@@ -315,11 +323,6 @@ public class CarKeyguardViewController extends OverlayViewController implements
}
@Override
- public void setOccluded(boolean occluded, boolean animate) {
- // no-op
- }
-
- @Override
public boolean shouldDisableWindowAnimationsForUnlock() {
return false;
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
index 20fc1bcd6013..0ced4021ce38 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarView.java
@@ -74,8 +74,10 @@ public class CarNavigationBarView extends LinearLayout {
mDarkIconManager.setShouldLog(true);
Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
}
- // needs to be clickable so that it will receive ACTION_MOVE events
+ // Needs to be clickable so that it will receive ACTION_MOVE events.
setClickable(true);
+ // Needs to not be focusable so rotary won't highlight the entire nav bar.
+ setFocusable(false);
}
@Override
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java
index 5e113d6366a1..e7e33a5439f9 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java
@@ -32,8 +32,8 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.keyguard.AlphaOptimizedImageButton;
import com.android.systemui.R;
+import com.android.systemui.statusbar.AlphaOptimizedImageView;
import java.net.URISyntaxException;
@@ -53,8 +53,8 @@ public class CarNavigationButton extends LinearLayout {
private static final String EXTRA_BUTTON_PACKAGES = "packages";
private Context mContext;
- private AlphaOptimizedImageButton mIcon;
- private AlphaOptimizedImageButton mMoreIcon;
+ private AlphaOptimizedImageView mIcon;
+ private AlphaOptimizedImageView mMoreIcon;
private ImageView mUnseenIcon;
private String mIntent;
private String mLongIntent;
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/NavigationBarViewFactory.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/NavigationBarViewFactory.java
index 3b7b48a77186..d60bc418ece2 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/NavigationBarViewFactory.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/NavigationBarViewFactory.java
@@ -24,6 +24,7 @@ import android.view.ViewGroup;
import androidx.annotation.LayoutRes;
+import com.android.car.ui.FocusParkingView;
import com.android.systemui.R;
import javax.inject.Inject;
@@ -146,6 +147,12 @@ public class NavigationBarViewFactory {
CarNavigationBarView view = (CarNavigationBarView) View.inflate(mContext, barLayout,
/* root= */ null);
+
+ // Include a FocusParkingView at the end. The rotary controller "parks" the focus here when
+ // the user navigates to another window. This is also used to prevent wrap-around which is
+ // why it must be first or last in Tab order.
+ view.addView(new FocusParkingView(mContext));
+
mCachedViewMap.put(type, view);
return mCachedViewMap.get(type);
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java
index aeb1d39599db..d4f720715a69 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java
@@ -24,7 +24,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
-import android.widget.FrameLayout;
import com.android.car.notification.R;
import com.android.car.notification.headsup.CarHeadsUpNotificationContainer;
@@ -44,7 +43,7 @@ public class CarHeadsUpNotificationSystemContainer implements CarHeadsUpNotifica
private final OverlayViewGlobalStateController mOverlayViewGlobalStateController;
private final ViewGroup mWindow;
- private final FrameLayout mHeadsUpContentFrame;
+ private final ViewGroup mHeadsUpContentFrame;
@Inject
CarHeadsUpNotificationSystemContainer(Context context,
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java
index 30e26578bd73..3969f92c690a 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java
@@ -138,4 +138,11 @@ public class OverlayViewController {
protected boolean shouldShowNavigationBar() {
return false;
}
+
+ /**
+ * Returns {@code true} if this view should be hidden during the occluded state.
+ */
+ protected boolean shouldShowWhenOccluded() {
+ return false;
+ }
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java
index 70260b0d4cef..8e9410964313 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java
@@ -24,7 +24,9 @@ import androidx.annotation.VisibleForTesting;
import com.android.systemui.car.navigationbar.CarNavigationBarController;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
@@ -47,11 +49,16 @@ public class OverlayViewGlobalStateController {
private static final int UNKNOWN_Z_ORDER = -1;
private final SystemUIOverlayWindowController mSystemUIOverlayWindowController;
private final CarNavigationBarController mCarNavigationBarController;
+
+ private boolean mIsOccluded;
+
@VisibleForTesting
Map<OverlayViewController, Integer> mZOrderMap;
@VisibleForTesting
SortedMap<Integer, OverlayViewController> mZOrderVisibleSortedMap;
@VisibleForTesting
+ Set<OverlayViewController> mViewsHiddenForOcclusion;
+ @VisibleForTesting
OverlayViewController mHighestZOrder;
@Inject
@@ -63,6 +70,7 @@ public class OverlayViewGlobalStateController {
mCarNavigationBarController = carNavigationBarController;
mZOrderMap = new HashMap<>();
mZOrderVisibleSortedMap = new TreeMap<>();
+ mViewsHiddenForOcclusion = new HashSet<>();
}
/**
@@ -91,6 +99,10 @@ public class OverlayViewGlobalStateController {
*/
public void showView(OverlayViewController viewController, @Nullable Runnable show) {
debugLog();
+ if (mIsOccluded && !viewController.shouldShowWhenOccluded()) {
+ mViewsHiddenForOcclusion.add(viewController);
+ return;
+ }
if (mZOrderVisibleSortedMap.isEmpty()) {
setWindowVisible(true);
}
@@ -147,6 +159,10 @@ public class OverlayViewGlobalStateController {
*/
public void hideView(OverlayViewController viewController, @Nullable Runnable hide) {
debugLog();
+ if (mIsOccluded && mViewsHiddenForOcclusion.contains(viewController)) {
+ mViewsHiddenForOcclusion.remove(viewController);
+ return;
+ }
if (!viewController.isInflated()) {
Log.d(TAG, "Content cannot be hidden since it isn't inflated: "
+ viewController.getClass().getName());
@@ -240,6 +256,43 @@ public class OverlayViewGlobalStateController {
return mZOrderVisibleSortedMap.isEmpty() || mHighestZOrder.shouldShowHUN();
}
+ /**
+ * Set the OverlayViewWindow to be in occluded or unoccluded state. When OverlayViewWindow is
+ * occluded, all views mounted to it that are not configured to be shown during occlusion will
+ * be hidden.
+ */
+ public void setOccluded(boolean occluded) {
+ if (occluded) {
+ // Hide views before setting mIsOccluded to true so the regular hideView logic is used,
+ // not the one used during occlusion.
+ hideViewsForOcclusion();
+ mIsOccluded = true;
+ } else {
+ mIsOccluded = false;
+ // show views after setting mIsOccluded to false so the regular showView logic is used,
+ // not the one used during occlusion.
+ showViewsHiddenForOcclusion();
+ }
+ }
+
+ private void hideViewsForOcclusion() {
+ HashSet<OverlayViewController> viewsCurrentlyShowing = new HashSet<>(
+ mZOrderVisibleSortedMap.values());
+ viewsCurrentlyShowing.forEach(overlayController -> {
+ if (!overlayController.shouldShowWhenOccluded()) {
+ hideView(overlayController, overlayController::hideInternal);
+ mViewsHiddenForOcclusion.add(overlayController);
+ }
+ });
+ }
+
+ private void showViewsHiddenForOcclusion() {
+ mViewsHiddenForOcclusion.forEach(overlayViewController -> {
+ showView(overlayViewController, overlayViewController::showInternal);
+ });
+ mViewsHiddenForOcclusion.clear();
+ }
+
private void debugLog() {
if (!DEBUG) {
return;
@@ -250,5 +303,8 @@ public class OverlayViewGlobalStateController {
Log.d(TAG, "mZOrderVisibleSortedMap: " + mZOrderVisibleSortedMap);
Log.d(TAG, "mZOrderMap.size(): " + mZOrderMap.size());
Log.d(TAG, "mZOrderMap: " + mZOrderMap);
+ Log.d(TAG, "mIsOccluded: " + mIsOccluded);
+ Log.d(TAG, "mViewsHiddenForOcclusion: " + mViewsHiddenForOcclusion);
+ Log.d(TAG, "mViewsHiddenForOcclusion.size(): " + mViewsHiddenForOcclusion.size());
}
}
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
index 38836d85e8d4..189e240169c3 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java
@@ -22,6 +22,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -169,6 +170,18 @@ public class CarKeyguardViewControllerTest extends SysuiTestCase {
}
@Test
+ public void setOccludedFalse_currentlyOccluded_bouncerReset() {
+ when(mBouncer.isSecure()).thenReturn(true);
+ mCarKeyguardViewController.show(/* options= */ null);
+ mCarKeyguardViewController.setOccluded(/* occluded= */ true, /* animate= */ false);
+ reset(mBouncer);
+
+ mCarKeyguardViewController.setOccluded(/* occluded= */ false, /* animate= */ false);
+
+ verify(mBouncer).show(/* resetSecuritySelection= */ true);
+ }
+
+ @Test
public void onCancelClicked_callsCancelClickedListener() {
when(mBouncer.isSecure()).thenReturn(true);
mCarKeyguardViewController.show(/* options= */ null);
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java
index 54282d39998b..bcaa5e9a03ee 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java
@@ -36,8 +36,8 @@ import android.widget.LinearLayout;
import androidx.test.filters.SmallTest;
-import com.android.keyguard.AlphaOptimizedImageButton;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.AlphaOptimizedImageView;
import com.android.systemui.tests.R;
import org.junit.Before;
@@ -74,7 +74,7 @@ public class CarNavigationButtonTest extends SysuiTestCase {
@Test
public void onCreate_iconIsVisible() {
- AlphaOptimizedImageButton icon = mDefaultButton.findViewById(
+ AlphaOptimizedImageView icon = mDefaultButton.findViewById(
R.id.car_nav_button_icon_image);
assertThat(icon.getDrawable()).isNotNull();
@@ -83,12 +83,12 @@ public class CarNavigationButtonTest extends SysuiTestCase {
@Test
public void onSelected_selectedIconDefined_togglesIcon() {
mDefaultButton.setSelected(true);
- Drawable selectedIconDrawable = ((AlphaOptimizedImageButton) mDefaultButton.findViewById(
+ Drawable selectedIconDrawable = ((AlphaOptimizedImageView) mDefaultButton.findViewById(
R.id.car_nav_button_icon_image)).getDrawable();
mDefaultButton.setSelected(false);
- Drawable unselectedIconDrawable = ((AlphaOptimizedImageButton) mDefaultButton.findViewById(
+ Drawable unselectedIconDrawable = ((AlphaOptimizedImageView) mDefaultButton.findViewById(
R.id.car_nav_button_icon_image)).getDrawable();
assertThat(selectedIconDrawable).isNotEqualTo(unselectedIconDrawable);
@@ -100,12 +100,12 @@ public class CarNavigationButtonTest extends SysuiTestCase {
R.id.selected_icon_undefined);
selectedIconUndefinedButton.setSelected(true);
- Drawable selectedIconDrawable = ((AlphaOptimizedImageButton) mDefaultButton.findViewById(
+ Drawable selectedIconDrawable = ((AlphaOptimizedImageView) mDefaultButton.findViewById(
R.id.car_nav_button_icon_image)).getDrawable();
selectedIconUndefinedButton.setSelected(false);
- Drawable unselectedIconDrawable = ((AlphaOptimizedImageButton) mDefaultButton.findViewById(
+ Drawable unselectedIconDrawable = ((AlphaOptimizedImageView) mDefaultButton.findViewById(
R.id.car_nav_button_icon_image)).getDrawable();
assertThat(selectedIconDrawable).isEqualTo(unselectedIconDrawable);
@@ -150,7 +150,7 @@ public class CarNavigationButtonTest extends SysuiTestCase {
@Test
public void onSelected_doesNotShowMoreWhenSelected_doesNotShowMoreIcon() {
mDefaultButton.setSelected(true);
- AlphaOptimizedImageButton moreIcon = mDefaultButton.findViewById(
+ AlphaOptimizedImageView moreIcon = mDefaultButton.findViewById(
R.id.car_nav_button_more_icon);
assertThat(moreIcon.getVisibility()).isEqualTo(View.GONE);
@@ -161,7 +161,7 @@ public class CarNavigationButtonTest extends SysuiTestCase {
CarNavigationButton showMoreWhenSelected = mTestView.findViewById(
R.id.not_highlightable_more_button);
showMoreWhenSelected.setSelected(true);
- AlphaOptimizedImageButton moreIcon = showMoreWhenSelected.findViewById(
+ AlphaOptimizedImageView moreIcon = showMoreWhenSelected.findViewById(
R.id.car_nav_button_more_icon);
assertThat(moreIcon.getVisibility()).isEqualTo(View.VISIBLE);
@@ -173,7 +173,7 @@ public class CarNavigationButtonTest extends SysuiTestCase {
R.id.highlightable_no_more_button);
showMoreWhenSelected.setSelected(true);
showMoreWhenSelected.setSelected(false);
- AlphaOptimizedImageButton moreIcon = showMoreWhenSelected.findViewById(
+ AlphaOptimizedImageView moreIcon = showMoreWhenSelected.findViewById(
R.id.car_nav_button_more_icon);
assertThat(moreIcon.getVisibility()).isEqualTo(View.GONE);
@@ -187,7 +187,7 @@ public class CarNavigationButtonTest extends SysuiTestCase {
roleBasedButton.setSelected(false);
roleBasedButton.setAppIcon(appIcon);
- Drawable currentDrawable = ((AlphaOptimizedImageButton) roleBasedButton.findViewById(
+ Drawable currentDrawable = ((AlphaOptimizedImageView) roleBasedButton.findViewById(
R.id.car_nav_button_icon_image)).getDrawable();
assertThat(currentDrawable).isEqualTo(appIcon);
@@ -212,7 +212,7 @@ public class CarNavigationButtonTest extends SysuiTestCase {
roleBasedButton.setSelected(true);
roleBasedButton.setAppIcon(appIcon);
- Drawable currentDrawable = ((AlphaOptimizedImageButton) roleBasedButton.findViewById(
+ Drawable currentDrawable = ((AlphaOptimizedImageView) roleBasedButton.findViewById(
R.id.car_nav_button_icon_image)).getDrawable();
assertThat(currentDrawable).isEqualTo(appIcon);
diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
index 9e6e616e3ccf..cba42e5a9be4 100644
--- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java
@@ -491,6 +491,81 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
}
@Test
+ public void setOccludedTrue_viewToHideWhenOccludedVisible_viewHidden() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(false);
+
+ mOverlayViewGlobalStateController.setOccluded(true);
+
+ assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
+ mOverlayViewController1)).isFalse();
+ }
+
+ @Test
+ public void setOccludedTrue_viewToNotHideWhenOccludedVisible_viewShown() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(true);
+
+ mOverlayViewGlobalStateController.setOccluded(true);
+
+ assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
+ mOverlayViewController1)).isTrue();
+ }
+
+ @Test
+ public void hideViewAndThenSetOccludedTrue_viewHiddenForOcclusion_viewHiddenAfterOcclusion() {
+ setupOverlayViewController1();
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+ when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(false);
+ mOverlayViewGlobalStateController.setOccluded(true);
+
+ mOverlayViewGlobalStateController.hideView(mOverlayViewController1, /* runnable= */ null);
+ mOverlayViewGlobalStateController.setOccluded(false);
+
+ assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
+ mOverlayViewController1)).isFalse();
+ }
+
+ @Test
+ public void setOccludedTrueAndThenShowView_viewToNotHideForOcclusion_viewShown() {
+ setupOverlayViewController1();
+ when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(true);
+
+ mOverlayViewGlobalStateController.setOccluded(true);
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+
+ assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
+ mOverlayViewController1)).isTrue();
+ }
+
+ @Test
+ public void setOccludedTrueAndThenShowView_viewToHideForOcclusion_viewHidden() {
+ setupOverlayViewController1();
+ when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(false);
+
+ mOverlayViewGlobalStateController.setOccluded(true);
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+
+ assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
+ mOverlayViewController1)).isFalse();
+ }
+
+ @Test
+ public void setOccludedFalse_viewShownAfterSetOccludedTrue_viewToHideForOcclusion_viewShown() {
+ setupOverlayViewController1();
+ when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(false);
+ mOverlayViewGlobalStateController.setOccluded(true);
+ setOverlayViewControllerAsShowing(mOverlayViewController1);
+
+ mOverlayViewGlobalStateController.setOccluded(false);
+
+ assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue(
+ mOverlayViewController1)).isTrue();
+ }
+
+ @Test
public void inflateView_notInflated_inflates() {
when(mOverlayViewController2.isInflated()).thenReturn(false);
diff --git a/packages/SettingsLib/AdaptiveIcon/res/values/colors.xml b/packages/SettingsLib/AdaptiveIcon/res/values/colors.xml
index 76d106a067dd..8f5b2ed3aaaf 100644
--- a/packages/SettingsLib/AdaptiveIcon/res/values/colors.xml
+++ b/packages/SettingsLib/AdaptiveIcon/res/values/colors.xml
@@ -18,4 +18,8 @@
<color name="homepage_generic_icon_background">#1A73E8</color>
<color name="bt_outline_color">#1f000000</color> <!-- icon outline color -->
+
+ <color name="advanced_outline_color">#BDC1C6</color> <!-- icon outline color -->
+
+ <color name="advanced_icon_color">#3C4043</color>
</resources>
diff --git a/packages/SettingsLib/AdaptiveIcon/res/values/dimens.xml b/packages/SettingsLib/AdaptiveIcon/res/values/dimens.xml
index 7f5b58c48abb..8f6e358cd9b6 100644
--- a/packages/SettingsLib/AdaptiveIcon/res/values/dimens.xml
+++ b/packages/SettingsLib/AdaptiveIcon/res/values/dimens.xml
@@ -18,6 +18,8 @@
<resources>
<!-- Dashboard foreground image inset (from background edge to foreground edge) -->
<dimen name="dashboard_tile_foreground_image_inset">6dp</dimen>
+ <!-- Advanced dashboard foreground image inset (from background edge to foreground edge) -->
+ <dimen name="advanced_dashboard_tile_foreground_image_inset">9dp</dimen>
<!-- Stroke size of adaptive outline -->
<dimen name="adaptive_outline_stroke">1dp</dimen>
diff --git a/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java b/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java
index 1c65bc248961..4438893dabfc 100644
--- a/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java
+++ b/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java
@@ -16,6 +16,10 @@
package com.android.settingslib.widget;
+import static com.android.settingslib.widget.AdaptiveOutlineDrawable.AdaptiveOutlineIconType.TYPE_ADVANCED;
+import static com.android.settingslib.widget.AdaptiveOutlineDrawable.AdaptiveOutlineIconType.TYPE_DEFAULT;
+
+import android.annotation.ColorInt;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -27,35 +31,90 @@ import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.DrawableWrapper;
import android.util.PathParser;
+import androidx.annotation.IntDef;
import androidx.annotation.VisibleForTesting;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Adaptive outline drawable with white plain background color and black outline
*/
public class AdaptiveOutlineDrawable extends DrawableWrapper {
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({TYPE_DEFAULT, TYPE_ADVANCED})
+ public @interface AdaptiveOutlineIconType {
+ int TYPE_DEFAULT = 0;
+ int TYPE_ADVANCED = 1;
+ }
+
@VisibleForTesting
- final Paint mOutlinePaint;
+ Paint mOutlinePaint;
private Path mPath;
- private final int mInsetPx;
- private final Bitmap mBitmap;
+ private int mInsetPx;
+ private int mStrokeWidth;
+ private Bitmap mBitmap;
+ private int mType;
public AdaptiveOutlineDrawable(Resources resources, Bitmap bitmap) {
super(new AdaptiveIconShapeDrawable(resources));
+ init(resources, bitmap, TYPE_DEFAULT);
+ }
+
+ public AdaptiveOutlineDrawable(Resources resources, Bitmap bitmap,
+ @AdaptiveOutlineIconType int type) {
+ super(new AdaptiveIconShapeDrawable(resources));
+
+ init(resources, bitmap, type);
+ }
+
+ private void init(Resources resources, Bitmap bitmap,
+ @AdaptiveOutlineIconType int type) {
+ mType = type;
getDrawable().setTint(Color.WHITE);
mPath = new Path(PathParser.createPathFromPathData(
resources.getString(com.android.internal.R.string.config_icon_mask)));
+ mStrokeWidth = resources.getDimensionPixelSize(R.dimen.adaptive_outline_stroke);
mOutlinePaint = new Paint();
- mOutlinePaint.setColor(resources.getColor(R.color.bt_outline_color, null));
+ mOutlinePaint.setColor(getColor(resources, type));
mOutlinePaint.setStyle(Paint.Style.STROKE);
- mOutlinePaint.setStrokeWidth(resources.getDimension(R.dimen.adaptive_outline_stroke));
+ mOutlinePaint.setStrokeWidth(mStrokeWidth);
mOutlinePaint.setAntiAlias(true);
- mInsetPx = resources
- .getDimensionPixelSize(R.dimen.dashboard_tile_foreground_image_inset);
+ mInsetPx = getDimensionPixelSize(resources, type);
mBitmap = bitmap;
}
+ private @ColorInt int getColor(Resources resources, @AdaptiveOutlineIconType int type) {
+ int resId;
+ switch (type) {
+ case TYPE_ADVANCED:
+ resId = R.color.advanced_outline_color;
+ break;
+ case TYPE_DEFAULT:
+ default:
+ resId = R.color.bt_outline_color;
+ break;
+ }
+ return resources.getColor(resId, /* theme */ null);
+ }
+
+ private int getDimensionPixelSize(Resources resources, @AdaptiveOutlineIconType int type) {
+ int resId;
+ switch (type) {
+ case TYPE_ADVANCED:
+ resId = R.dimen.advanced_dashboard_tile_foreground_image_inset;
+ break;
+ case TYPE_DEFAULT:
+ default:
+ resId = R.dimen.dashboard_tile_foreground_image_inset;
+ break;
+ }
+ return resources.getDimensionPixelSize(resId);
+ }
+
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
@@ -68,7 +127,12 @@ public class AdaptiveOutlineDrawable extends DrawableWrapper {
final int count = canvas.save();
canvas.scale(scaleX, scaleY);
// Draw outline
- canvas.drawPath(mPath, mOutlinePaint);
+ if (mType == TYPE_DEFAULT) {
+ canvas.drawPath(mPath, mOutlinePaint);
+ } else {
+ canvas.drawCircle(2 * mInsetPx, 2 * mInsetPx, 2 * mInsetPx - mStrokeWidth,
+ mOutlinePaint);
+ }
canvas.restoreToCount(count);
// Draw the foreground icon
diff --git a/packages/SettingsLib/SearchWidget/res/values-fa/strings.xml b/packages/SettingsLib/SearchWidget/res/values-fa/strings.xml
index fa5f9bdfe07b..2c9aaa5e9f95 100644
--- a/packages/SettingsLib/SearchWidget/res/values-fa/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-fa/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"جستجوی تنظیمات"</string>
+ <string name="search_menu" msgid="1914043873178389845">"تنظیمات جستجو"</string>
</resources>
diff --git a/packages/SettingsLib/SearchWidget/res/values-tl/strings.xml b/packages/SettingsLib/SearchWidget/res/values-tl/strings.xml
index 111cf5a15dba..14b7b2f62eee 100644
--- a/packages/SettingsLib/SearchWidget/res/values-tl/strings.xml
+++ b/packages/SettingsLib/SearchWidget/res/values-tl/strings.xml
@@ -17,5 +17,5 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="search_menu" msgid="1914043873178389845">"Mga setting ng paghahanap"</string>
+ <string name="search_menu" msgid="1914043873178389845">"Maghanap sa mga setting"</string>
</resources>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index d039c9f646df..1b5062efa23e 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -140,8 +140,8 @@
<string name="accessibility_wifi_security_type_none" msgid="162352241518066966">"Адкрытая сетка"</string>
<string name="accessibility_wifi_security_type_secured" msgid="2399774097343238942">"Бяспечная сетка"</string>
<string name="process_kernel_label" msgid="950292573930336765">"АС Android"</string>
- <string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"Выдаленыя прыкладанні"</string>
- <string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"Выдаленыя прыкладанні і карыстальнiкi"</string>
+ <string name="data_usage_uninstalled_apps" msgid="1933665711856171491">"Выдаленыя праграмы"</string>
+ <string name="data_usage_uninstalled_apps_users" msgid="5533981546921913295">"Выдаленыя праграмы і карыстальнiкi"</string>
<string name="data_usage_ota" msgid="7984667793701597001">"Абнаўленні сістэмы"</string>
<string name="tether_settings_title_usb" msgid="3728686573430917722">"USB-мадэм"</string>
<string name="tether_settings_title_wifi" msgid="4803402057533895526">"Партатыўны хот-спот"</string>
diff --git a/packages/SettingsLib/res/values-bn/arrays.xml b/packages/SettingsLib/res/values-bn/arrays.xml
index a131a3b1ad91..b19cde4f2778 100644
--- a/packages/SettingsLib/res/values-bn/arrays.xml
+++ b/packages/SettingsLib/res/values-bn/arrays.xml
@@ -40,7 +40,7 @@
<item msgid="8339720953594087771">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> এর সাথে কানেক্ট হচ্ছে…"</item>
<item msgid="3028983857109369308">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> দিয়ে যাচাইকরণ করা হচ্ছে..."</item>
<item msgid="4287401332778341890">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> থেকে আইপি অ্যাড্রেস জানা হচ্ছে…"</item>
- <item msgid="1043944043827424501">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> তে কানেক্ট হয়েছে"</item>
+ <item msgid="1043944043827424501">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>-এ কানেক্ট হয়েছে"</item>
<item msgid="7445993821842009653">"স্থগিত করা হয়েছে"</item>
<item msgid="1175040558087735707">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> থেকে ডিসকানেক্ট হচ্ছে…"</item>
<item msgid="699832486578171722">"ডিসকানেক্ট করা হয়েছে"</item>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 8db0b7e9dd28..2644cb987e3a 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -194,7 +194,7 @@
<item msgid="581904787661470707">"Ταχύτατη"</item>
</string-array>
<string name="choose_profile" msgid="343803890897657450">"Επιλογή προφίλ"</string>
- <string name="category_personal" msgid="6236798763159385225">"Προσωπικός"</string>
+ <string name="category_personal" msgid="6236798763159385225">"Προσωπικό"</string>
<string name="category_work" msgid="4014193632325996115">"Εργασίας"</string>
<string name="development_settings_title" msgid="140296922921597393">"Επιλογές για προγραμματιστές"</string>
<string name="development_settings_enable" msgid="4285094651288242183">"Ενεργοποίηση επιλογών για προγραμματιστές"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 65f456e20e4e..d003ef0b9c71 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -449,7 +449,7 @@
<string name="power_charging_duration" msgid="5005740040558984057">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> täislaadimiseni"</string>
<string name="battery_info_status_unknown" msgid="268625384868401114">"Tundmatu"</string>
<string name="battery_info_status_charging" msgid="4279958015430387405">"Laadimine"</string>
- <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Kiiresti laadimine"</string>
+ <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Kiirlaadimine"</string>
<string name="battery_info_status_charging_slow" msgid="3190803837168962319">"Aeglaselt laadimine"</string>
<string name="battery_info_status_discharging" msgid="6962689305413556485">"Ei lae"</string>
<string name="battery_info_status_not_charging" msgid="8330015078868707899">"Vooluvõrgus, praegu ei saa laadida"</string>
diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml
index e73febcb1aa4..d20bf38024ab 100644
--- a/packages/SettingsLib/res/values-in/arrays.xml
+++ b/packages/SettingsLib/res/values-in/arrays.xml
@@ -40,7 +40,7 @@
<item msgid="8339720953594087771">"Menyambung ke <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
<item msgid="3028983857109369308">"Mengautentikasi dengan <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
<item msgid="4287401332778341890">"Mendapatkan alamat IP dari <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
- <item msgid="1043944043827424501">"Tersambung ke <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+ <item msgid="1043944043827424501">"Terhubung ke <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
<item msgid="7445993821842009653">"Ditangguhkan"</item>
<item msgid="1175040558087735707">"Diputus dari <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
<item msgid="699832486578171722">"Sambungan terputus"</item>
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index a5ec5e66f242..e552d78e1a45 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -94,4 +94,7 @@
<!-- Define minimal size of the tap area -->
<dimen name="min_tap_target_size">48dp</dimen>
+
+ <!-- Size of advanced icon -->
+ <dimen name="advanced_icon_size">18dp</dimen>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
index a6202956efa5..38eeda245616 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
@@ -19,10 +19,13 @@ package com.android.settingslib.applications;
import android.app.Application;
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.hardware.usb.IUsbManager;
+import android.net.Uri;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -44,6 +47,15 @@ public class AppUtils {
*/
private static InstantAppDataProvider sInstantAppDataProvider = null;
+ private static final Intent sBrowserIntent;
+
+ static {
+ sBrowserIntent = new Intent()
+ .setAction(Intent.ACTION_VIEW)
+ .addCategory(Intent.CATEGORY_BROWSABLE)
+ .setData(Uri.parse("http:"));
+ }
+
public static CharSequence getLaunchByDefaultSummary(ApplicationsState.AppEntry appEntry,
IUsbManager usbManager, PackageManager pm, Context context) {
String packageName = appEntry.info.packageName;
@@ -153,4 +165,22 @@ public class AppUtils {
return com.android.settingslib.utils.applications.AppUtils.getAppContentDescription(context,
packageName, userId);
}
+
+ /**
+ * Returns a boolean indicating whether a given package is a browser app.
+ *
+ * An app is a "browser" if it has an activity resolution that wound up
+ * marked with the 'handleAllWebDataURI' flag.
+ */
+ public static boolean isBrowserApp(Context context, String packageName, int userId) {
+ sBrowserIntent.setPackage(packageName);
+ final List<ResolveInfo> list = context.getPackageManager().queryIntentActivitiesAsUser(
+ sBrowserIntent, PackageManager.MATCH_ALL, userId);
+ for (ResolveInfo info : list) {
+ if (info.activityInfo != null && info.handleAllWebDataURI) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index 9d1b3cf116d9..95e916b9871a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -1,5 +1,7 @@
package com.android.settingslib.bluetooth;
+import static com.android.settingslib.widget.AdaptiveOutlineDrawable.AdaptiveOutlineIconType.TYPE_ADVANCED;
+
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
@@ -7,6 +9,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -213,6 +216,46 @@ public class BluetoothUtils {
}
/**
+ * Build device icon with advanced outline
+ */
+ public static Drawable buildAdvancedDrawable(Context context, Drawable drawable) {
+ final int iconSize = context.getResources().getDimensionPixelSize(
+ R.dimen.advanced_icon_size);
+ final Resources resources = context.getResources();
+
+ Bitmap bitmap = null;
+ if (drawable instanceof BitmapDrawable) {
+ bitmap = ((BitmapDrawable) drawable).getBitmap();
+ } else {
+ final int width = drawable.getIntrinsicWidth();
+ final int height = drawable.getIntrinsicHeight();
+ bitmap = createBitmap(drawable,
+ width > 0 ? width : 1,
+ height > 0 ? height : 1);
+ }
+
+ if (bitmap != null) {
+ final Bitmap resizedBitmap = Bitmap.createScaledBitmap(bitmap, iconSize,
+ iconSize, false);
+ bitmap.recycle();
+ return new AdaptiveOutlineDrawable(resources, resizedBitmap, TYPE_ADVANCED);
+ }
+
+ return drawable;
+ }
+
+ /**
+ * Creates a drawable with specified width and height.
+ */
+ public static Bitmap createBitmap(Drawable drawable, int width, int height) {
+ final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ final Canvas canvas = new Canvas(bitmap);
+ drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ drawable.draw(canvas);
+ return bitmap;
+ }
+
+ /**
* Get boolean Bluetooth metadata
*
* @param bluetoothDevice the BluetoothDevice to get metadata
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
index 40d80488af96..00f94f5c2e64 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
@@ -21,7 +21,6 @@ import android.content.Context;
import android.graphics.drawable.Drawable;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
-import android.util.Pair;
import com.android.settingslib.R;
import com.android.settingslib.bluetooth.BluetoothUtils;
@@ -57,13 +56,11 @@ public class BluetoothMediaDevice extends MediaDevice {
@Override
public Drawable getIcon() {
- final Pair<Drawable, String> pair = BluetoothUtils
- .getBtRainbowDrawableWithDescription(mContext, mCachedDevice);
- return isFastPairDevice()
- ? pair.first
- : BluetoothUtils.buildBtRainbowDrawable(mContext,
- mContext.getDrawable(R.drawable.ic_headphone),
- mCachedDevice.getAddress().hashCode());
+ final Drawable drawable = getIconWithoutBackground();
+ if (!isFastPairDevice()) {
+ setColorFilter(drawable);
+ }
+ return BluetoothUtils.buildAdvancedDrawable(mContext, drawable);
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
index 8d6bc5c97228..ea71e52dc9c9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
@@ -55,9 +55,9 @@ public class InfoMediaDevice extends MediaDevice {
@Override
public Drawable getIcon() {
- //TODO(b/120669861): Return remote device icon uri once api is ready.
- return BluetoothUtils.buildBtRainbowDrawable(mContext,
- mContext.getDrawable(getDrawableResId()), getId().hashCode());
+ final Drawable drawable = getIconWithoutBackground();
+ setColorFilter(drawable);
+ return BluetoothUtils.buildAdvancedDrawable(mContext, drawable);
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index 317077b14e30..126f9b91b0d2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -31,6 +31,9 @@ import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES;
import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
import android.graphics.drawable.Drawable;
import android.media.MediaRoute2Info;
import android.media.MediaRouter2Manager;
@@ -39,6 +42,8 @@ import android.text.TextUtils;
import androidx.annotation.IntDef;
import androidx.annotation.VisibleForTesting;
+import com.android.settingslib.R;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -131,6 +136,14 @@ public abstract class MediaDevice implements Comparable<MediaDevice> {
getId());
}
+ void setColorFilter(Drawable drawable) {
+ final ColorStateList list =
+ mContext.getResources().getColorStateList(
+ R.color.advanced_icon_color, mContext.getTheme());
+ drawable.setColorFilter(new PorterDuffColorFilter(list.getDefaultColor(),
+ PorterDuff.Mode.SRC_IN));
+ }
+
/**
* Get name from MediaDevice.
*
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index c43a51246fb5..b6c0b30b3bd4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -85,8 +85,9 @@ public class PhoneMediaDevice extends MediaDevice {
@Override
public Drawable getIcon() {
- return BluetoothUtils.buildBtRainbowDrawable(mContext,
- mContext.getDrawable(getDrawableResId()), getId().hashCode());
+ final Drawable drawable = getIconWithoutBackground();
+ setColorFilter(drawable);
+ return BluetoothUtils.buildAdvancedDrawable(mContext, drawable);
}
@Override
@@ -105,7 +106,7 @@ public class PhoneMediaDevice extends MediaDevice {
case TYPE_HDMI:
case TYPE_WIRED_HEADSET:
case TYPE_WIRED_HEADPHONES:
- resId = com.android.internal.R.drawable.ic_bt_headphones_a2dp;
+ resId = R.drawable.ic_headphone;
break;
case TYPE_BUILTIN_SPEAKER:
default:
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
index 421e5c0db1a1..00d1f76f025f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
@@ -79,13 +79,11 @@ public class PhoneMediaDeviceTest {
public void getDrawableResId_returnCorrectResId() {
when(mInfo.getType()).thenReturn(TYPE_WIRED_HEADPHONES);
- assertThat(mPhoneMediaDevice.getDrawableResId())
- .isEqualTo(com.android.internal.R.drawable.ic_bt_headphones_a2dp);
+ assertThat(mPhoneMediaDevice.getDrawableResId()).isEqualTo(R.drawable.ic_headphone);
when(mInfo.getType()).thenReturn(TYPE_WIRED_HEADSET);
- assertThat(mPhoneMediaDevice.getDrawableResId())
- .isEqualTo(com.android.internal.R.drawable.ic_bt_headphones_a2dp);
+ assertThat(mPhoneMediaDevice.getDrawableResId()).isEqualTo(R.drawable.ic_headphone);
when(mInfo.getType()).thenReturn(TYPE_BUILTIN_SPEAKER);
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index fa87b62bd73a..eb7ad72eb1ba 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -316,7 +316,6 @@ public class SettingsBackupTest {
Settings.Global.KERNEL_CPU_THREAD_READER,
Settings.Global.LANG_ID_UPDATE_CONTENT_URL,
Settings.Global.LANG_ID_UPDATE_METADATA_URL,
- Settings.Global.LAST_ACTIVE_USER_ID,
Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS,
Settings.Global.LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS,
Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index ae8e8e82241d..4e17062fc52c 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -201,6 +201,9 @@
<uses-permission android:name="android.permission.MANAGE_APPOPS" />
+ <!-- Permission required for IncrementalLogCollectionTest -->
+ <uses-permission android:name="android.permission.LOADER_USAGE_STATS" />
+
<!-- Permission required for storage tests - FuseDaemonHostTest -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
@@ -306,6 +309,9 @@
<!-- Permission needed for CTS test - PrivilegedLocationPermissionTest -->
<uses-permission android:name="android.permission.LOCATION_HARDWARE" />
+ <!-- Permissions required for GTS test - GtsDialerAudioTestCases -->
+ <uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/Shell/res/layout/dialog_bugreport_info.xml b/packages/Shell/res/layout/dialog_bugreport_info.xml
index 4bd871103193..ea2427920285 100644
--- a/packages/Shell/res/layout/dialog_bugreport_info.xml
+++ b/packages/Shell/res/layout/dialog_bugreport_info.xml
@@ -14,58 +14,63 @@
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:paddingTop="15dp"
- android:paddingStart="24dp"
- android:paddingEnd="24dp"
- android:focusableInTouchMode="false"
- android:focusable="false"
- android:importantForAutofill="noExcludeDescendants"
- android:layout_width="wrap_content"
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
android:layout_height="wrap_content">
- <TextView
+ <LinearLayout
+ android:orientation="vertical"
+ android:paddingTop="15dp"
+ android:paddingStart="24dp"
+ android:paddingEnd="24dp"
android:focusableInTouchMode="false"
android:focusable="false"
- android:inputType="textNoSuggestions"
+ android:importantForAutofill="noExcludeDescendants"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/bugreport_info_name"/>
- <EditText
- android:id="@+id/name"
- android:nextFocusDown="@+id/title"
- android:maxLength="30"
- android:singleLine="true"
- android:inputType="textNoSuggestions"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
- <TextView
- android:focusableInTouchMode="false"
- android:focusable="false"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/bugreport_info_title"/>
- <EditText
- android:id="@+id/title"
- android:nextFocusUp="@+id/name"
- android:nextFocusDown="@+id/description"
- android:maxLength="80"
- android:singleLine="true"
- android:inputType="textAutoCorrect|textCapSentences"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
- <TextView
- android:focusableInTouchMode="false"
- android:focusable="false"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:editable="false"
- android:text="@string/bugreport_info_description"/>
- <EditText
- android:id="@+id/description"
- android:nextFocusUp="@+id/title"
- android:singleLine="false"
- android:inputType="textMultiLine|textAutoCorrect|textCapSentences"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
-</LinearLayout>
+ android:layout_height="wrap_content">
+ <TextView
+ android:focusableInTouchMode="false"
+ android:focusable="false"
+ android:inputType="textNoSuggestions"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/bugreport_info_name"/>
+ <EditText
+ android:id="@+id/name"
+ android:nextFocusDown="@+id/title"
+ android:maxLength="30"
+ android:singleLine="true"
+ android:inputType="textNoSuggestions"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+ <TextView
+ android:focusableInTouchMode="false"
+ android:focusable="false"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/bugreport_info_title"/>
+ <EditText
+ android:id="@+id/title"
+ android:nextFocusUp="@+id/name"
+ android:nextFocusDown="@+id/description"
+ android:maxLength="80"
+ android:singleLine="true"
+ android:inputType="textAutoCorrect|textCapSentences"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+ <TextView
+ android:focusableInTouchMode="false"
+ android:focusable="false"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:editable="false"
+ android:text="@string/bugreport_info_description"/>
+ <EditText
+ android:id="@+id/description"
+ android:nextFocusUp="@+id/title"
+ android:singleLine="false"
+ android:inputType="textMultiLine|textAutoCorrect|textCapSentences"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+ </LinearLayout>
+</ScrollView>
diff --git a/packages/SystemUI/res-product/values-en-rXC/strings.xml b/packages/SystemUI/res-product/values-en-rXC/strings.xml
index 33a0e9da8871..022c5b390e7b 100644
--- a/packages/SystemUI/res-product/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res-product/values-en-rXC/strings.xml
@@ -40,10 +40,7 @@
<string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4682221342671290678">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‏‏‏‎‏‎‏‎‎‏‎‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‎‎‎‏‏‎‏‎‏‏‎‎‏‏‎‎‎‎‎‏‎‎‏‏‎‏‏‎‎You have incorrectly attempted to unlock the phone ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%d</xliff:g>‎‏‎‎‏‏‏‎ times. The work profile will be removed, which will delete all profile data.‎‏‎‎‏‎"</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="1860049973474855672">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‎‎‎‎‎‎‏‏‏‎‎‏‏‎‎‏‏‎‎‎‏‎‎‎‏‏‎‏‎‏‏‏‎‎‎‏‏‎‎‎‏‎‏‎‏‏‏‏‏‎‎‎‎You have incorrectly drawn your unlock pattern ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. After ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ more unsuccessful attempts, you will be asked to unlock your tablet using an email account.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎ Try again in ‎‏‎‎‏‏‎<xliff:g id="NUMBER_2">%3$d</xliff:g>‎‏‎‎‏‏‏‎ seconds.‎‏‎‎‏‎"</string>
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="44112553371516141">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‎‏‎‎‎‏‏‎‎‎‏‏‏‎‏‏‎‎‎‎‎‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎You have incorrectly drawn your unlock pattern ‎‏‎‎‏‏‎<xliff:g id="NUMBER_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ times. After ‎‏‎‎‏‏‎<xliff:g id="NUMBER_1">%2$d</xliff:g>‎‏‎‎‏‏‏‎ more unsuccessful attempts, you will be asked to unlock your phone using an email account.‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎ Try again in ‎‏‎‎‏‏‎<xliff:g id="NUMBER_2">%3$d</xliff:g>‎‏‎‎‏‏‏‎ seconds.‎‏‎‎‏‎"</string>
- <!-- no translation found for global_action_lock_message (7092460751050168771) -->
- <skip />
- <!-- no translation found for global_action_lock_message (1024230056230539493) -->
- <skip />
- <!-- no translation found for global_action_lock_message (3165224897120346096) -->
- <skip />
+ <string name="global_action_lock_message" product="default" msgid="7092460751050168771">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎‏‏‎‏‎‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‎‎‎‎‏‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‏‏‎‎‎‎‏‏‎Unlock your phone for more options‎‏‎‎‏‎"</string>
+ <string name="global_action_lock_message" product="tablet" msgid="1024230056230539493">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‎‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‏‎‎‏‏‏‏‎‎‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‏‎‏‎‎‎‎‏‏‏‎‎‏‎‏‎Unlock your tablet for more options‎‏‎‎‏‎"</string>
+ <string name="global_action_lock_message" product="device" msgid="3165224897120346096">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‎‏‏‎‎‎‏‎‏‎‎‏‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎Unlock your device for more options‎‏‎‎‏‎"</string>
</resources>
diff --git a/packages/SystemUI/res/drawable/dismiss_circle_background.xml b/packages/SystemUI/res/drawable/dismiss_circle_background.xml
index e311c520d3d6..7809c8398c2d 100644
--- a/packages/SystemUI/res/drawable/dismiss_circle_background.xml
+++ b/packages/SystemUI/res/drawable/dismiss_circle_background.xml
@@ -21,8 +21,8 @@
<stroke
android:width="1dp"
- android:color="#66FFFFFF" />
+ android:color="#AAFFFFFF" />
- <solid android:color="#B3000000" />
+ <solid android:color="#77000000" />
</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/floating_dismiss_gradient.xml b/packages/SystemUI/res/drawable/floating_dismiss_gradient.xml
new file mode 100644
index 000000000000..8f7fb1011cf4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/floating_dismiss_gradient.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<shape
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <gradient
+ android:angle="270"
+ android:startColor="#00000000"
+ android:endColor="#77000000"
+ android:type="linear" />
+</shape> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml b/packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml
new file mode 100644
index 000000000000..6a0695e817c7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/floating_dismiss_gradient_transition.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<transition xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@color/transparent" />
+ <item android:drawable="@drawable/floating_dismiss_gradient" />
+</transition> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_create_bubble.xml b/packages/SystemUI/res/drawable/ic_create_bubble.xml
index d58e9a347a2f..4abbc8179b4d 100644
--- a/packages/SystemUI/res/drawable/ic_create_bubble.xml
+++ b/packages/SystemUI/res/drawable/ic_create_bubble.xml
@@ -15,11 +15,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
+ android:width="20dp"
+ android:height="20dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
- android:pathData="M22,12C22,12 22,12 22,12C22,12 22,12 22,12c0,0.56 -0.06,1.1 -0.15,1.64l-1.97,-0.33c0.15,-0.91 0.15,-1.84 -0.02,-2.75c-0.01,-0.03 -0.01,-0.07 -0.02,-0.1c-0.03,-0.18 -0.08,-0.36 -0.13,-0.54c-0.02,-0.08 -0.04,-0.16 -0.06,-0.24c-0.04,-0.14 -0.09,-0.27 -0.14,-0.41c-0.04,-0.12 -0.08,-0.24 -0.13,-0.35c-0.04,-0.09 -0.08,-0.18 -0.13,-0.27c-0.07,-0.15 -0.14,-0.3 -0.22,-0.45c-0.03,-0.05 -0.06,-0.09 -0.08,-0.14c-0.72,-1.26 -1.77,-2.31 -3.03,-3.03c-0.05,-0.03 -0.09,-0.06 -0.14,-0.08c-0.15,-0.08 -0.3,-0.15 -0.45,-0.22c-0.09,-0.04 -0.18,-0.09 -0.27,-0.13c-0.11,-0.05 -0.23,-0.09 -0.35,-0.13c-0.14,-0.05 -0.27,-0.1 -0.41,-0.14c-0.08,-0.02 -0.16,-0.04 -0.23,-0.06c-0.18,-0.05 -0.36,-0.1 -0.54,-0.13c-0.03,-0.01 -0.07,-0.01 -0.1,-0.01c-0.95,-0.17 -1.93,-0.17 -2.88,0c-0.03,0.01 -0.07,0.01 -0.1,0.01c-0.18,0.04 -0.36,0.08 -0.54,0.13C9.85,4.3 9.77,4.32 9.69,4.34C9.55,4.38 9.42,4.44 9.28,4.49C9.17,4.53 9.05,4.57 8.93,4.61C8.84,4.65 8.75,4.7 8.66,4.74c-0.15,0.07 -0.3,0.14 -0.45,0.22C8.16,4.98 8.12,5.01 8.07,5.04C5.64,6.42 4,9.02 4,12c0,2.74 1.39,5.16 3.49,6.6c0.01,0.01 0.03,0.02 0.04,0.03c0.16,0.11 0.33,0.2 0.49,0.3c0.06,0.04 0.12,0.08 0.19,0.11c0.13,0.07 0.27,0.13 0.4,0.19c0.11,0.05 0.21,0.1 0.32,0.15c0.1,0.04 0.2,0.07 0.29,0.11c0.15,0.06 0.31,0.11 0.46,0.16c0.05,0.02 0.11,0.03 0.17,0.04c1.11,0.31 2.27,0.35 3.4,0.18l0.35,1.98c-0.54,0.09 -1.08,0.14 -1.62,0.14V22c-0.65,0 -1.28,-0.07 -1.9,-0.19c-0.01,0 -0.01,0 -0.02,0c-0.25,-0.05 -0.49,-0.11 -0.73,-0.18c-0.08,-0.02 -0.16,-0.04 -0.23,-0.06c-0.19,-0.06 -0.37,-0.13 -0.55,-0.19c-0.13,-0.05 -0.26,-0.09 -0.39,-0.14c-0.13,-0.05 -0.25,-0.12 -0.38,-0.18c-0.18,-0.08 -0.35,-0.16 -0.53,-0.25c-0.07,-0.04 -0.14,-0.08 -0.21,-0.13c-0.22,-0.12 -0.43,-0.25 -0.64,-0.39c-0.01,-0.01 -0.02,-0.02 -0.04,-0.03c-0.51,-0.35 -1,-0.74 -1.45,-1.2l0,0C3.12,17.26 2,14.76 2,12c0,-2.76 1.12,-5.26 2.93,-7.07l0,0c0.45,-0.45 0.93,-0.84 1.44,-1.19C6.39,3.73 6.4,3.72 6.42,3.71c0.2,-0.14 0.41,-0.26 0.62,-0.38c0.08,-0.05 0.15,-0.09 0.23,-0.14c0.17,-0.09 0.33,-0.16 0.5,-0.24c0.13,-0.06 0.27,-0.13 0.4,-0.19C8.3,2.71 8.42,2.67 8.55,2.63c0.19,-0.07 0.38,-0.14 0.58,-0.2c0.07,-0.02 0.14,-0.03 0.21,-0.05C10.18,2.14 11.07,2 12,2c0.65,0 1.29,0.07 1.91,0.19c0,0 0,0 0,0c0.25,0.05 0.5,0.11 0.75,0.18c0.07,0.02 0.14,0.03 0.22,0.06c0.19,0.06 0.38,0.13 0.57,0.2c0.12,0.05 0.25,0.09 0.37,0.14c0.14,0.06 0.27,0.12 0.4,0.18c0.17,0.08 0.34,0.16 0.51,0.25c0.08,0.04 0.15,0.09 0.23,0.14c0.21,0.12 0.42,0.24 0.62,0.38c0.01,0.01 0.03,0.02 0.04,0.03c0.51,0.35 0.99,0.74 1.45,1.19c0.24,0.24 0.47,0.49 0.68,0.75c0.04,0.04 0.06,0.09 0.1,0.13c0.17,0.22 0.34,0.45 0.5,0.68c0.01,0.01 0.02,0.03 0.03,0.04c0.69,1.05 1.17,2.21 1.42,3.44c0,0 0,0.01 0,0.01c0.06,0.29 0.1,0.58 0.13,0.87c0.01,0.04 0.01,0.09 0.02,0.13C21.98,11.32 22,11.66 22,12zM18.5,15c-1.93,0 -3.5,1.57 -3.5,3.5s1.57,3.5 3.5,3.5s3.5,-1.57 3.5,-3.5S20.43,15 18.5,15z"/>
-</vector> \ No newline at end of file
+ android:pathData="M23,5v8h-2V5H3v14h10v2v0H3c-1.1,0 -2,-0.9 -2,-2V5c0,-1.1 0.9,-2 2,-2h18C22.1,3 23,3.9 23,5zM10,8v2.59L5.71,6.29L4.29,7.71L8.59,12H6v2h6V8H10zM19,15c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S20.66,15 19,15z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/dismiss_target_x.xml b/packages/SystemUI/res/drawable/ic_music_note.xml
index 3672efffe139..30959a870a02 100644
--- a/packages/SystemUI/res/drawable/dismiss_target_x.xml
+++ b/packages/SystemUI/res/drawable/ic_music_note.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2020 The Android Open Source Project
~
@@ -14,15 +13,12 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-<!-- 'X' icon. -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24.0dp"
- android:height="24.0dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
<path
- android:pathData="M19.000000,6.400000l-1.400000,-1.400000 -5.600000,5.600000 -5.600000,-5.600000 -1.400000,1.400000 5.600000,5.600000 -5.600000,5.600000 1.400000,1.400000 5.600000,-5.600000 5.600000,5.600000 1.400000,-1.400000 -5.600000,-5.600000z"
- android:fillColor="#FFFFFFFF"
- android:strokeColor="#FF000000"/>
-</vector> \ No newline at end of file
+ android:fillColor="#FF000000"
+ android:pathData="M12,3v10.55c-0.59,-0.34 -1.27,-0.55 -2,-0.55 -2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4V7h4V3h-6z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_stop_bubble.xml b/packages/SystemUI/res/drawable/ic_stop_bubble.xml
index 11bc741a4f17..6cf67a77ff55 100644
--- a/packages/SystemUI/res/drawable/ic_stop_bubble.xml
+++ b/packages/SystemUI/res/drawable/ic_stop_bubble.xml
@@ -15,11 +15,11 @@
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
+ android:width="20dp"
+ android:height="20dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
- android:pathData="M21.98,18.32l-3.3,-3.3C20.47,15.11 21.89,16.53 21.98,18.32zM8.66,4.74C8.75,4.7 8.84,4.65 8.93,4.61c0.11,-0.05 0.23,-0.09 0.35,-0.13c0.14,-0.05 0.27,-0.1 0.41,-0.14C9.77,4.32 9.85,4.3 9.92,4.28c0.18,-0.05 0.36,-0.1 0.54,-0.13c0.03,-0.01 0.07,-0.01 0.1,-0.01c0.95,-0.17 1.93,-0.17 2.88,0c0.03,0.01 0.07,0.01 0.1,0.01c0.18,0.04 0.36,0.08 0.54,0.13c0.08,0.02 0.16,0.04 0.23,0.06c0.14,0.04 0.27,0.09 0.41,0.14c0.12,0.04 0.23,0.08 0.35,0.13c0.09,0.04 0.18,0.09 0.27,0.13c0.15,0.07 0.3,0.14 0.45,0.22c0.05,0.03 0.09,0.06 0.14,0.08c1.26,0.72 2.31,1.77 3.03,3.03c0.03,0.05 0.06,0.09 0.08,0.14c0.08,0.15 0.15,0.3 0.22,0.45c0.04,0.09 0.09,0.18 0.13,0.27c0.05,0.11 0.09,0.23 0.13,0.35c0.05,0.13 0.1,0.27 0.14,0.41c0.02,0.08 0.04,0.16 0.06,0.24c0.05,0.18 0.1,0.36 0.13,0.54c0.01,0.03 0.01,0.07 0.02,0.1c0.16,0.91 0.17,1.84 0.02,2.75l1.97,0.33C21.94,13.1 22,12.56 22,12c0,0 0,0 0,0s0,0 0,0c0,-0.34 -0.02,-0.68 -0.05,-1.01c0,-0.04 -0.01,-0.09 -0.02,-0.13c-0.03,-0.29 -0.07,-0.58 -0.13,-0.87c0,0 0,-0.01 0,-0.01c-0.25,-1.23 -0.73,-2.39 -1.42,-3.44c-0.01,-0.01 -0.02,-0.03 -0.03,-0.04c-0.15,-0.23 -0.32,-0.46 -0.5,-0.68c-0.03,-0.04 -0.06,-0.09 -0.1,-0.13c-0.21,-0.26 -0.44,-0.51 -0.68,-0.75c-0.45,-0.45 -0.94,-0.84 -1.45,-1.19c-0.01,-0.01 -0.03,-0.02 -0.04,-0.03c-0.2,-0.14 -0.41,-0.26 -0.62,-0.38c-0.08,-0.04 -0.15,-0.09 -0.23,-0.14c-0.17,-0.09 -0.34,-0.17 -0.51,-0.25c-0.13,-0.06 -0.26,-0.13 -0.4,-0.18c-0.12,-0.05 -0.25,-0.09 -0.37,-0.14c-0.19,-0.07 -0.38,-0.14 -0.57,-0.2c-0.07,-0.02 -0.14,-0.04 -0.22,-0.06c-0.25,-0.07 -0.5,-0.13 -0.75,-0.18c0,0 0,0 0,0C13.29,2.07 12.65,2 12,2c-0.93,0 -1.82,0.14 -2.67,0.37C9.26,2.39 9.19,2.41 9.12,2.43c-0.2,0.06 -0.39,0.13 -0.58,0.2C8.42,2.67 8.3,2.71 8.18,2.76c-0.14,0.06 -0.27,0.12 -0.4,0.19C7.61,3.03 7.44,3.1 7.27,3.19C7.19,3.24 7.12,3.29 7.04,3.33C7.03,3.34 7.02,3.34 7.01,3.35l1.48,1.48C8.55,4.8 8.6,4.77 8.66,4.74zM2.71,1.29L1.29,2.71l2.97,2.97C2.85,7.4 2,9.6 2,12c0,2.76 1.12,5.26 2.93,7.07l0,0c0.45,0.45 0.94,0.85 1.45,1.2c0.01,0.01 0.02,0.02 0.04,0.03c0.21,0.14 0.42,0.27 0.64,0.39c0.07,0.04 0.14,0.09 0.21,0.13c0.17,0.09 0.35,0.17 0.53,0.25c0.13,0.06 0.25,0.12 0.38,0.18c0.13,0.05 0.26,0.1 0.39,0.14c0.18,0.07 0.36,0.14 0.55,0.19c0.08,0.02 0.16,0.04 0.23,0.06c0.24,0.07 0.48,0.13 0.73,0.18c0.01,0 0.01,0 0.02,0C10.72,21.93 11.35,22 12,22v-0.01c0.54,0 1.08,-0.05 1.62,-0.14l-0.35,-1.98c-1.13,0.18 -2.29,0.13 -3.4,-0.18c-0.06,-0.02 -0.11,-0.03 -0.17,-0.04c-0.16,-0.05 -0.31,-0.11 -0.46,-0.16c-0.1,-0.04 -0.2,-0.07 -0.29,-0.11c-0.11,-0.05 -0.22,-0.1 -0.32,-0.15c-0.13,-0.06 -0.27,-0.12 -0.4,-0.19c-0.06,-0.03 -0.13,-0.08 -0.19,-0.11c-0.17,-0.1 -0.33,-0.19 -0.49,-0.3c-0.01,-0.01 -0.03,-0.02 -0.04,-0.03C5.39,17.16 4,14.74 4,12c0,-1.85 0.64,-3.54 1.7,-4.89l9.73,9.73C15.16,17.33 15,17.9 15,18.5c0,1.93 1.57,3.5 3.5,3.5c0.6,0 1.17,-0.16 1.66,-0.43l1.13,1.13l1.41,-1.41L2.71,1.29z"/>
+ android:pathData="M11.29,14.71L7,10.41V13H5V7h6v2H8.41l4.29,4.29L11.29,14.71zM21,3H3C1.9,3 1,3.9 1,5v14c0,1.1 0.9,2 2,2h10v0v-2H3V5h18v8h2V5C23,3.9 22.1,3 21,3zM19,15c-1.66,0 -3,1.34 -3,3s1.34,3 3,3s3,-1.34 3,-3S20.66,15 19,15z"/>
</vector>
diff --git a/packages/SystemUI/res/layout/controls_detail_dialog.xml b/packages/SystemUI/res/layout/controls_detail_dialog.xml
index d61122fd47dd..ee5315ad782f 100644
--- a/packages/SystemUI/res/layout/controls_detail_dialog.xml
+++ b/packages/SystemUI/res/layout/controls_detail_dialog.xml
@@ -42,6 +42,7 @@
android:layout_height="1dp" />
<ImageView
android:id="@+id/control_detail_open_in_app"
+ android:contentDescription="@string/controls_open_app"
android:src="@drawable/ic_open_in_new"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:tint="@color/control_primary_text"
diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml
index 3bd7e04f2094..49d525fc189a 100644
--- a/packages/SystemUI/res/layout/notification_conversation_info.xml
+++ b/packages/SystemUI/res/layout/notification_conversation_info.xml
@@ -84,34 +84,21 @@
android:layout_weight="1"
style="@style/TextAppearance.NotificationImportanceChannel"/>
</LinearLayout>
- <LinearLayout
+ <TextView
+ android:id="@+id/pkg_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:gravity="start"
- android:orientation="horizontal">
- <TextView
- android:id="@+id/pkg_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@style/TextAppearance.NotificationImportanceChannelGroup"
- android:ellipsize="end"
- android:maxLines="1"/>
- <TextView
- android:id="@+id/group_divider"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- style="@style/TextAppearance.NotificationImportanceHeader"
- android:layout_marginStart="2dp"
- android:layout_marginEnd="2dp"
- android:text="@*android:string/notification_header_divider_symbol" />
- <TextView
- android:id="@+id/group_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- style="@style/TextAppearance.NotificationImportanceChannelGroup"/>
- </LinearLayout>
+ style="@style/TextAppearance.NotificationImportanceChannelGroup"
+ android:ellipsize="end"
+ android:textDirection="locale"
+ android:maxLines="1"/>
+ <TextView
+ android:id="@+id/group_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:textDirection="locale"
+ style="@style/TextAppearance.NotificationImportanceChannelGroup"/>
<TextView
android:id="@+id/delegate_name"
android:layout_width="match_parent"
@@ -121,6 +108,7 @@
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:ellipsize="end"
+ android:textDirection="locale"
android:text="@string/notification_delegate_header"
android:maxLines="1" />
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index af5a8f4d3c23..870deacd87ae 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -58,35 +58,21 @@
android:layout_height="wrap_content"
android:textDirection="locale"
style="@style/TextAppearance.NotificationImportanceChannel"/>
- <LinearLayout
+ <TextView
+ android:id="@+id/pkg_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:gravity="start"
- android:orientation="horizontal">
- <TextView
- android:id="@+id/pkg_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@style/TextAppearance.NotificationImportanceChannelGroup"
- android:ellipsize="end"
- android:maxLines="1"/>
- <TextView
- android:id="@+id/group_divider"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- style="@style/TextAppearance.NotificationImportanceHeader"
- android:layout_marginStart="2dp"
- android:layout_marginEnd="2dp"
- android:text="@*android:string/notification_header_divider_symbol" />
- <TextView
- android:id="@+id/group_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:textDirection="locale"
- style="@style/TextAppearance.NotificationImportanceChannelGroup"/>
- </LinearLayout>
+ style="@style/TextAppearance.NotificationImportanceChannelGroup"
+ android:ellipsize="end"
+ android:textDirection="locale"
+ android:maxLines="1"/>
+ <TextView
+ android:id="@+id/group_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:textDirection="locale"
+ android:ellipsize="end"
+ style="@style/TextAppearance.NotificationImportanceChannelGroup"/>
<TextView
android:id="@+id/delegate_name"
android:layout_width="match_parent"
@@ -96,6 +82,7 @@
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:ellipsize="end"
+ android:textDirection="locale"
android:text="@string/notification_delegate_header"
android:maxLines="1" />
diff --git a/packages/SystemUI/res/layout/partial_conversation_info.xml b/packages/SystemUI/res/layout/partial_conversation_info.xml
index a261114fa0f2..803b0c61e6da 100644
--- a/packages/SystemUI/res/layout/partial_conversation_info.xml
+++ b/packages/SystemUI/res/layout/partial_conversation_info.xml
@@ -46,66 +46,33 @@
android:layout_weight="1"
android:layout_width="0dp"
android:orientation="vertical"
-
android:layout_height="wrap_content"
android:minHeight="@dimen/notification_guts_conversation_icon_size"
android:layout_centerVertical="true"
android:gravity="center_vertical"
android:layout_alignEnd="@id/conversation_icon"
android:layout_toEndOf="@id/conversation_icon">
- <LinearLayout
+ <TextView
+ android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:gravity="start"
- android:orientation="horizontal">
- <TextView
- android:id="@+id/name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@style/TextAppearance.NotificationImportanceChannel"/>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- style="@style/TextAppearance.NotificationImportanceHeader"
- android:layout_marginStart="2dp"
- android:layout_marginEnd="2dp"
- android:text="@*android:string/notification_header_divider_symbol" />
- <TextView
- android:id="@+id/parent_channel_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@style/TextAppearance.NotificationImportanceChannel"/>
-
- </LinearLayout>
- <LinearLayout
+ android:ellipsize="end"
+ android:textDirection="locale"
+ style="@style/TextAppearance.NotificationImportanceChannel"/>
+ <TextView
+ android:id="@+id/parent_channel_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:gravity="start"
- android:orientation="horizontal">
- <TextView
- android:id="@+id/pkg_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@style/TextAppearance.NotificationImportanceChannelGroup"
- android:ellipsize="end"
- android:maxLines="1"/>
- <TextView
- android:id="@+id/group_divider"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- style="@style/TextAppearance.NotificationImportanceHeader"
- android:layout_marginStart="2dp"
- android:layout_marginEnd="2dp"
- android:text="@*android:string/notification_header_divider_symbol" />
- <TextView
- android:id="@+id/group_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- style="@style/TextAppearance.NotificationImportanceChannelGroup"/>
- </LinearLayout>
+ android:ellipsize="end"
+ android:textDirection="locale"
+ style="@style/TextAppearance.NotificationImportanceChannel"/>
+ <TextView
+ android:id="@+id/group_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:textDirection="locale"
+ style="@style/TextAppearance.NotificationImportanceChannelGroup"/>
<TextView
android:id="@+id/delegate_name"
android:layout_width="match_parent"
@@ -115,6 +82,7 @@
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:ellipsize="end"
+ android:textDirection="locale"
android:text="@string/notification_delegate_header"
android:maxLines="1" />
diff --git a/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml b/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml
index c27b3a9b3bf4..bf2eac3c8ff3 100644
--- a/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml
+++ b/packages/SystemUI/res/layout/priority_onboarding_half_shell.xml
@@ -38,157 +38,67 @@
android:background="@drawable/rounded_bg_full"
>
- <!-- We have a known number of rows that can be shown; just design them all here -->
- <LinearLayout
- android:id="@+id/show_at_top_tip"
+ <ImageView
+ android:id="@+id/conversation_icon"
+ android:layout_width="@dimen/notification_guts_conversation_icon_size"
+ android:layout_height="@dimen/notification_guts_conversation_icon_size"
+ android:layout_gravity="center_horizontal" />
+
+ <TextView
+ android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:paddingStart="4dp"
- android:paddingEnd="4dp"
- android:orientation="horizontal"
- >
- <ImageView
- android:id="@+id/bell_icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="center_vertical"
- android:src="@drawable/ic_notifications_alert"
- android:tint="?android:attr/colorControlNormal" />
-
- <TextView
- android:id="@+id/show_at_top_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
- android:gravity="center_vertical|start"
- android:textSize="15sp"
- android:ellipsize="end"
- android:maxLines="2"
- android:text="@string/priority_onboarding_show_at_top_text"
- style="@style/TextAppearance.NotificationInfo"
- />
-
- </LinearLayout>
-
- <LinearLayout
- android:id="@+id/show_avatar_tip"
+ android:gravity="center_horizontal"
+ android:layout_marginTop="16dp"
+ android:text="@string/priority_onboarding_title"
+ style="@style/TextAppearance.NotificationImportanceChannel"
+ />
+
+ <View
+ android:id="@+id/divider"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:paddingStart="4dp"
- android:paddingEnd="4dp"
- android:orientation="horizontal"
- >
- <ImageView
- android:id="@+id/avatar_icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="center_vertical"
- android:src="@drawable/ic_person"
- android:tint="?android:attr/colorControlNormal" />
-
- <TextView
- android:id="@+id/avatar_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
- android:gravity="center_vertical|start"
- android:textSize="15sp"
- android:ellipsize="end"
- android:maxLines="2"
- android:text="@string/priority_onboarding_show_avatar_text"
- style="@style/TextAppearance.NotificationInfo"
- />
+ android:layout_height="0.5dp"
+ android:layout_marginTop="20dp"
+ android:layout_marginBottom="20dp"
+ android:background="@color/material_grey_300" />
- </LinearLayout>
-
- <!-- These rows show optionally -->
-
- <LinearLayout
- android:id="@+id/floating_bubble_tip"
+ <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:paddingStart="4dp"
- android:paddingEnd="4dp"
- android:orientation="horizontal"
- >
-
- <ImageView
- android:id="@+id/bubble_icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="center_vertical"
- android:src="@drawable/ic_create_bubble"
- android:tint="?android:attr/colorControlNormal" />
+ android:gravity="start"
+ android:text="@string/priority_onboarding_behavior"
+ style="@style/TextAppearance.NotificationImportanceChannelGroup"
+ />
- <TextView
- android:id="@+id/bubble_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
- android:gravity="center_vertical|start"
- android:textSize="15sp"
- android:ellipsize="end"
- android:maxLines="2"
- android:text="@string/priority_onboarding_appear_as_bubble_text"
- style="@style/TextAppearance.NotificationInfo"
- />
-
- </LinearLayout>
-
- <LinearLayout
- android:id="@+id/ignore_dnd_tip"
+ <TextView
+ android:id="@+id/behaviors"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:paddingStart="4dp"
- android:paddingEnd="4dp"
- android:orientation="horizontal"
- >
-
- <ImageView
- android:id="@+id/dnd_icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
- android:layout_gravity="center_vertical"
- android:src="@drawable/moon"
- android:tint="?android:attr/colorControlNormal" />
-
- <TextView
- android:id="@+id/dnd_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
- android:gravity="center_vertical|start"
- android:textSize="15sp"
- android:ellipsize="end"
- android:maxLines="2"
- android:text="@string/priority_onboarding_ignores_dnd_text"
- style="@style/TextAppearance.NotificationInfo"
- />
-
- </LinearLayout>
+ android:gravity="start"
+ android:layout_marginTop="8dp"
+ style="@style/TextAppearance.NotificationImportanceChannelGroup"
+ />
<!-- Bottom button container -->
<RelativeLayout
android:id="@+id/button_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingStart="4dp"
- android:paddingEnd="4dp"
+ android:layout_marginTop="32dp"
android:orientation="horizontal"
>
<TextView
+ android:id="@+id/settings_button"
+ android:text="@string/priority_onboarding_settings_button_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentStart="true"
+ android:gravity="start|center_vertical"
+ android:minWidth="@dimen/notification_importance_toggle_size"
+ android:minHeight="@dimen/notification_importance_toggle_size"
+ android:maxWidth="125dp"
+ style="@style/TextAppearance.NotificationInfo.Button"/>
+ <TextView
android:id="@+id/done_button"
android:text="@string/priority_onboarding_done_button_title"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
index 5b7e7e7d59a3..44f52efd175e 100644
--- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml
+++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml
@@ -21,8 +21,6 @@
android:layout_height="wrap_content"
android:paddingTop="@dimen/qs_header_top_padding"
android:paddingBottom="@dimen/qs_header_bottom_padding"
- android:paddingStart="@dimen/status_bar_padding_start"
- android:paddingEnd="@dimen/status_bar_padding_end"
android:layout_below="@id/quick_status_bar_system_icons"
android:clipChildren="false"
android:clipToPadding="false"
diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
index 28672241b1b2..12127f529054 100644
--- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
@@ -18,8 +18,6 @@
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_gravity="center_vertical"
- android:paddingLeft="16dp"
- android:paddingRight="16dp"
style="@style/BrightnessDialogContainer">
<com.android.systemui.settings.ToggleSliderView
diff --git a/packages/SystemUI/res/layout/quick_settings_footer.xml b/packages/SystemUI/res/layout/quick_settings_footer.xml
index 846c5386dd06..15f398aa52e6 100644
--- a/packages/SystemUI/res/layout/quick_settings_footer.xml
+++ b/packages/SystemUI/res/layout/quick_settings_footer.xml
@@ -23,7 +23,7 @@
android:paddingStart="@dimen/qs_footer_padding_start"
android:paddingEnd="@dimen/qs_footer_padding_end"
android:gravity="center_vertical"
- android:background="?android:attr/colorPrimary" >
+ android:background="@android:color/transparent">
<TextView
android:id="@+id/footer_text"
@@ -32,7 +32,7 @@
android:gravity="start"
android:layout_weight="1"
android:textAppearance="@style/TextAppearance.QS.TileLabel"
- android:textColor="?android:attr/textColorSecondary"/>
+ style="@style/qs_security_footer"/>
<ImageView
android:id="@+id/footer_icon"
@@ -40,6 +40,6 @@
android:layout_height="@dimen/qs_footer_icon_size"
android:contentDescription="@null"
android:src="@drawable/ic_info_outline"
- android:tint="?android:attr/textColorSecondary"/>
+ style="@style/qs_security_footer"/>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_header_info.xml b/packages/SystemUI/res/layout/quick_settings_header_info.xml
index 683e86728e91..e6ef9b4b902c 100644
--- a/packages/SystemUI/res/layout/quick_settings_header_info.xml
+++ b/packages/SystemUI/res/layout/quick_settings_header_info.xml
@@ -19,8 +19,6 @@
android:layout_width="match_parent"
android:layout_height="@dimen/qs_header_tooltip_height"
android:layout_below="@id/quick_status_bar_system_icons"
- android:paddingStart="@dimen/status_bar_padding_start"
- android:paddingEnd="@dimen/status_bar_padding_end"
android:visibility="invisible"
android:theme="@style/QSHeaderTheme">
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index 9a7c344baf20..abeb33111c40 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -33,6 +33,7 @@
android:paddingStart="0dp"
android:elevation="4dp" >
+ <!-- The clock -->
<include layout="@layout/quick_status_bar_header_system_icons" />
<!-- Status icons within the panel itself (and not in the top-most status bar) -->
diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
index b27d096c12b5..be86e5f5abc5 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml
@@ -25,8 +25,6 @@
android:gravity="center"
android:orientation="horizontal"
android:clickable="true"
- android:paddingStart="@dimen/status_bar_padding_start"
- android:paddingEnd="@dimen/status_bar_padding_end"
android:paddingTop="@dimen/status_bar_padding_top" >
<com.android.systemui.statusbar.policy.Clock
diff --git a/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml b/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml
index af6f9bb827f6..0c4d5a26f95b 100644
--- a/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml
+++ b/packages/SystemUI/res/layout/screen_record_dialog_audio_source.xml
@@ -16,21 +16,20 @@
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
+ android:layout_width="250dp"
android:layout_height="48dp"
android:orientation="vertical"
- android:padding="10dp"
- android:layout_weight="1">
+ android:padding="13dp">
<TextView
android:id="@+id/screen_recording_dialog_source_text"
- android:layout_width="match_parent"
+ android:layout_width="250dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"/>
<TextView
android:id="@+id/screen_recording_dialog_source_description"
- android:layout_width="wrap_content"
+ android:layout_width="250dp"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"/>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index cc1f7a3afead..06fa15494857 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoem om skerm te vul"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Strek om skerm te vul"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Skermkiekie"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Ontsluit jou foon vir meer opsies"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Ontsluit jou tablet vir meer opsies"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Ontsluit jou toestel vir meer opsies"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"het \'n prent gestuur"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Stoor tans skermkiekie..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Stoor tans skermkiekie..."</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Wys boaan die gespreksafdeling, verskyn as \'n swewende borrel, wys profielfoto op sluitskerm"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Instellings"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioriteit"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> steun nie gesprekspesifieke-instellings nie"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Geen onlangse borrels nie"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Onlangse borrels en borrels wat toegemaak is, sal hier verskyn"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Hierdie kennisgewings kan nie gewysig word nie."</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index dff3e810ecbc..e8df135c8aea 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"ማያ እንዲሞላ አጉላ"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"ማያ ለመሙለት ሳብ"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ቅጽበታዊ ገጽ እይታ"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ለተጨማሪ አማራጮች የእርስዎን ስልክ ይክፈቱ"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ለተጨማሪ አማራጮች የእርስዎን ጡባዊ ይክፈቱ"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ለተጨማሪ አማራጮች የእርስዎን መሣሪያ ይክፈቱ"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ምስል ተልኳል"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"ቅጽበታዊ ገጽ እይታ በማስቀመጥ ላይ..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ቅጽበታዊ ገጽ እይታ በማስቀመጥ ላይ..."</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"በውይይት ክፍል አናት ላይ ያሳያል፣ እንደ ተንሳፋፊ አረፋ ብቅ ይላል፣ በቆልፍ ማያ ገጽ ላይ የመገለጫ ሥዕልን ያሳያል"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ቅንብሮች"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ቅድሚያ"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ውይይት-ተኮር ቅንብሮችን አይደግፍም"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ምንም የቅርብ ጊዜ አረፋዎች የሉም"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"የቅርብ ጊዜ አረፋዎች እና የተሰናበቱ አረፋዎች እዚህ ብቅ ይላሉ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"እነዚህ ማሳወቂያዎች ሊሻሻሉ አይችሉም።"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 084081c4748c..38e3c20c48e0 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"تكبير/تصغير لملء الشاشة"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"توسيع بملء الشاشة"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"لقطة شاشة"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"يمكنك فتح قفل هاتفك للوصول إلى مزيد من الخيارات."</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"يمكنك فتح قفل جهازك اللوحي للوصول إلى مزيد من الخيارات."</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"يمكنك فتح قفل جهازك للوصول إلى مزيد من الخيارات."</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"أرسَل صورة"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"جارٍ حفظ لقطة الشاشة..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"جارٍ حفظ لقطة الشاشة..."</string>
@@ -607,29 +604,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"تفعيل"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"إيقاف"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"تبديل جهاز الاستماع"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"تم تثبيت التطبيق"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار الزرين \"رجوع\" و\"نظرة عامة\" لإزالة التثبيت."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار الزرين \"رجوع\" و\"الشاشة الرئيسية\" لإزالة التثبيت."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. مرّر الشاشة بسرعة للأعلى مع الاستمرار لإزالة تثبيت الشاشة."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار زر \"نظرة عامة\" لإزالة التثبيت."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار زر \"الشاشة الرئيسية\" لإزالة التثبيت."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"يمكن الوصول إلى البيانات الشخصية (مثلاً جهات الاتصال ومحتوى الرسائل الإلكترونية)"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"يمكن للتطبيق المثبَّت فتح تطبيقات أخرى."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"لإزالة تثبيت هذا التطبيق، المس مع الاستمرار زرّي \"رجوع\" و\"نظرة عامة\"."</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"لإزالة تثبيت هذا التطبيق، المس مع الاستمرار زرّي \"رجوع\" و\"الشاشة الرئيسية\"."</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"مرّر الشاشة بسرعة للأعلى مع الاستمرار لإزالة تثبيت هذا التطبيق."</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"حسنًا"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"لا، شكرًا"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"تم تثبيت التطبيق."</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"تمت إزالة تثبيت التطبيق"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"هل تريد إخفاء <xliff:g id="TILE_LABEL">%1$s</xliff:g>؟"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"سيظهر مرة أخرى عند تمكينه في الإعدادات المرة التالية."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"إخفاء"</string>
@@ -742,7 +731,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"تظهر في أعلى قسم المحادثات وتظهر كفقاعة عائمة وتعرض صورة الملف الشخصي على شاشة القفل"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"الإعدادات"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"الأولوية"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"لا يدعم تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> الإعدادات الخاصة بالمحادثة."</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ليس هناك فقاعات محادثات"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ستظهر هنا أحدث فقاعات المحادثات وفقاعات المحادثات التي تم إغلاقها."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"يتعذّر تعديل هذه الإشعارات."</string>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 697d3753f4dd..9b36f9a1a235 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"স্ক্ৰীণ পূর্ণ কৰিবলৈ জুম কৰক"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"স্ক্ৰীণ পূর্ণ কৰিবলৈ প্ৰসাৰিত কৰক"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"স্ক্ৰীনশ্বট"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"অধিক বিকল্পৰ বাবে আপোনাৰ ফ’নটো আনলক কৰক"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"অধিক বিকল্পৰ বাবে আপোনাৰ টেবলেটটো আনলক কৰক"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"অধিক বিকল্পৰ বাবে আপোনাৰ ডিভাইচটো আনলক কৰক"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"এখন প্ৰতিচ্ছবি পঠিয়াইছে"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"স্ক্ৰীণশ্বট ছেভ কৰি থকা হৈছে…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"স্ক্ৰীণশ্বট ছেভ কৰি থকা হৈছে…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"সক্ষম কৰক"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"অক্ষম কৰক"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"আউটপুট ডিভাইচ সলনি কৰক"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"এপ্‌টো পিন কৰা আছে"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"এই কাৰ্যই আপুনি আনপিন নকৰালৈকে ইয়াক দেখা পোৱা অৱস্থাত ৰাখে। আনপিন কৰিবলৈ \'পিছলৈ যাওক\' আৰু \'অৱলোকন\'-ত স্পৰ্শ কৰি থাকক।"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"এই কাৰ্যই আপুনি আনপিন নকৰালৈকে ইয়াক দেখা পোৱা অৱস্থাত ৰাখে। আনপিন কৰিবলৈ পিছলৈ যাওক আৰু হ\'মত স্পৰ্শ কৰি সেঁচি ধৰক।"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"এই কাৰ্যই আপুনি আনপিন নকৰালৈকে ইয়াক দেখা পোৱা অৱস্থাত ৰাখে। আনপিন কৰিবলৈ ওপৰলৈ ছোৱাইপ কৰি ধৰি ৰাখক।"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"এই কাৰ্যই আপুনি আনপিন নকৰালৈকে ইয়াক দেখা পোৱা অৱস্থাত ৰাখে। আনপিন কৰিবলৈ \'অৱলোকন\'-ত স্পৰ্শ কৰি থাকক।"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"এই কাৰ্যই আপুনি আনপিন নকৰালৈকে ইয়াক দেখা পোৱা অৱস্থাত ৰাখে। আনপিন কৰিবলৈ পিছলৈ যাওক আৰু হ\'মত স্পৰ্শ কৰি সেঁচি ধৰক।"</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ব্যক্তিগত ডেটা এক্সেছ কৰিব পৰা যাব পাৰে (যেনে সম্পর্কসমূহ আৰু ইমেইলৰ সমল)।"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"পিন কৰি ৰখা এপ্‌টোৱে হয়তো অন্য এপ্‌সমূহ খুলিব পাৰে।"</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"এই এপ্‌টো আনপিন কৰিবলৈ, উভতি যাওক আৰু ৰূপৰেখাৰ বুটামসমূহ স্পৰ্শ কৰি ধৰি ৰাখক"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"এই এপ্‌টো আনপিন কৰিবলৈ, উভতি যাওক আৰু গৃহপৃষ্ঠাৰ বুটামসমূহ স্পৰ্শ কৰি ধৰি ৰাখক"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"এই এপ্‌টো আনপিন কৰিবলৈ, ওপৰলৈ ছোৱাইপ কৰক আৰু ধৰি ৰাখক"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"বুজি পালোঁ"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"নালাগে, ধন্যবাদ"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"এপ্‌টো পিন কৰা হ’ল"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"এপ্‌টো আনপিন কৰা হ’ল"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> লুকুৱাবনে?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"আপুনি ইয়াক পৰৱৰ্তী সময়ত ছেটিংসমূহত অন কৰিলে ই পুনৰ প্ৰকট হ\'ব।"</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"লুকুৱাওক"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"বাৰ্তালাপ শাখাটোৰ শীৰ্ষত দেখুৱায়, ওপঙা বাবল হিচাপে দেখা পোৱা যায়, লক স্ক্ৰীনত প্ৰ’ফাইলৰ চিত্ৰ প্ৰদৰ্শন কৰে"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ছেটিংসমূহ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"অগ্ৰাধিকাৰ"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ বাৰ্তালাপ নিৰ্দিষ্ট ছেটিংসমূহ সমৰ্থন নকৰে"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"কোনো শেহতীয়া bubbles নাই"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"শেহতীয়া bubbles আৰু অগ্ৰাহ্য কৰা bubbles ইয়াত প্ৰদর্শিত হ\'ব"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"এই জাননীসমূহ সংশোধন কৰিব নোৱাৰি।"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 52c85d1d70e7..502044e3b9d9 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Ekranı doldurmaq üçün yaxınlaşdır"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Ekranı doldurmaq üçün uzat"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Skrinşot"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Daha çox seçim üçün telefonu kiliddən çıxarın"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Daha çox seçim üçün planşeti kiliddən çıxarın"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Daha çox seçim üçün cihazı kiliddən çıxarın"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"şəkil göndərdi"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Skrinşot yadda saxlanılır..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Skrinşot yadda saxlanır..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktiv edin"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktiv edin"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Çıxış cihazına keçin"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Tətbiq bərkidilib"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Sancaq götürülənə qədər bu görünəcək. Sancağı götürmək üçün Geri və İcmal düymələrinə basıb saxlayın."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Sancaq götürülənə qədər bu görünəcək. Sancağı götürmək üçün Geri və Əsas səhifə düymələrinə basıb saxlayın."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Bu, onu çıxarana qədər görünəcək. Çıxarmaq üçün yuxarı sürüşdürün &amp; basıb saxlayın."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Sancaq götürülənə qədər bu görünəcək. Sancağı götürmək üçün Geri düyməsinə basıb saxlayın."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Sancaq götürülənə qədər bu görünəcək. Sancağı götürmək üçün Əsas səhifə düyməsinə basıb saxlayın."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Şəxsi məlumatlar (məsələn, kontaktlar və e-poçt məzmunu) əlçatan ola bilər."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Bərkidilmiş tətbiq digər tətbiqləri aça bilər."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Bu tətbiqi çıxarmaq üçün Geri və İcmal düymələrinə basıb saxlayın"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Bu tətbiqi çıxarmaq üçün Geri və Əsas ekran düymələrinə basıb saxlayın"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Bu tətbiqi çıxarmaq üçün yuxarı sürüşdürüb saxlayın"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Anladım!"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Yox, çox sağ olun"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Tətbiq bərkidildi"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Tətbiq çıxarıldı"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> gizlədilsin?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Ayarlarda onu aktivləşdirəcəyiniz vaxta qədər o, yenidən görünəcək."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Gizlədin"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Söhbət bölməsinin yuxarısında göstərilir, üzən qabarcıq kimi görünür, kilid ekranında profil şəkli göstərir"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ayarlar"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> söhbətə aid ayarları dəstəkləmir"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Yumrucuqlar yoxdur"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Son yumrucuqlar və buraxılmış yumrucuqlar burada görünəcək"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirişlər dəyişdirilə bilməz."</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 2057dd2d576c..00e375c70614 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zumiraj na celom ekranu"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Razvuci na ceo ekran"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Snimak ekrana"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Otključajte telefon za još opcija"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Otključajte tablet za još opcija"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Otključajte uređaj za još opcija"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"je poslao/la sliku"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Čuvanje snimka ekrana..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Čuvanje snimka ekrana..."</string>
@@ -725,7 +722,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Prikazuje se u vrhu odeljka za konverzacije kao plutajući oblačić, prikazuje sliku profila na zaključanom ekranu"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Podešavanja"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava podešavanja za konverzacije"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nema nedavnih oblačića"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Ovde se prikazuju nedavni i odbačeni oblačići"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ova obaveštenja ne mogu da se menjaju."</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 82c2535a7316..cb3aed5fc089 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Павял. на ўвесь экран"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Расцягн. на ўвесь экран"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Здымак экрана"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Каб адкрыць іншыя параметры, разблакіруйце тэлефон"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Каб адкрыць іншыя параметры, разблакіруйце планшэт"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Каб адкрыць іншыя параметры, разблакіруйце прыладу"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"адпраўлены відарыс"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Захаванне скрыншота..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Захаванне скрыншота..."</string>
@@ -728,7 +725,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Паказваецца ўверсе раздзела размоў у выглядзе ўсплывальнага апавяшчэння, а на экране блакіроўкі – у выглядзе відарыса профілю"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Налады"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Прыярытэт"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> не падтрымлівае пэўныя налады размоў"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Няма нядаўніх усплывальных апавяшчэнняў"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Нядаўнія і адхіленыя ўсплывальныя апавяшчэнні будуць паказаны тут"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Гэтыя апавяшчэнні нельга змяніць."</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 6dd050fb0735..66613490a073 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Мащаб – запълва екрана"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Разпъване – запълва екрана"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Екранна снимка"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Отключете телефона си за още опции"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Отключете таблета си за още опции"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Отключете устройството си за още опции"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"изпратено изображение"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Екранната снимка се запазва..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Екранната снимка се запазва..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"активиране"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"деактивиране"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Превключване на устройството за възпроизвеждане на звук"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Приложението е фиксирано"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Екранът ще се показва, докато не го освободите с докосване и задържане на бутона за връщане назад и този за общ преглед."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Екранът ще се показва, докато не го освободите с докосване и задържане на бутона за връщане назад и „Начало“."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Екранът ще остане на преден план, докато не го освободите. Прекарайте пръст нагоре и задръжте за освобождаване."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Екранът ще се показва, докато не го освободите с докосване и задържане на бутона за общ преглед."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Екранът ще се показва, докато не го освободите с докосване и задържане на бутона „Начало“."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Някои лични данни може да бъдат достъпни (като например контактите и съдържанието от имейлите)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Фиксираните приложения може да отворят други приложения."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"За да освободите това приложение, докоснете и задръжте бутона за връщане назад и този за общ преглед"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"За да освободите това приложение, докоснете и задръжте бутона за връщане назад и „Начало“"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"За да освободите това приложение, прекарайте пръст нагоре и задръжте"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Разбрах"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Не, благодаря"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Приложението е фиксирано"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Приложението е освободено"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Да се скрие ли „<xliff:g id="TILE_LABEL">%1$s</xliff:g>“?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Бързите настройки ще се покажат отново следващия път, когато ги включите от „Настройки“."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Скриване"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Показва се като плаващо балонче в горната част на секцията с разговори и показва снимката на потребителския профил на заключения екран"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Настройки"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддържа свързаните с разговорите настройки"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Няма скорошни балончета"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Скорошните и отхвърлените балончета ще се показват тук"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Тези известия не могат да бъдат променяни."</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index f25890b26bb0..74d903cf61c8 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"স্ক্রীণ পূরণ করতে জুম করুন"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"ফুল স্ক্রিন করুন"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"স্ক্রিনশট"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"আরও বিকল্প দেখতে আপনার ফোন আনলক করুন"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"আরও বিকল্প দেখতে আপনার ট্যাবলেট আনলক করুন"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"আরও বিকল্প দেখতে আপনার ডিভাইস আনলক করুন"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"একটি ছবি পাঠানো হয়েছে"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"স্ক্রিনশট সেভ করা হচ্ছে..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"স্ক্রিনশট সেভ করা হচ্ছে..."</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"কথোপকথন বিভাগের উপরে ভাসমান বাবলের মতো দেখা যাবে, লক স্ক্রিনে প্রোফাইল ছবি দেখাবে"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"সেটিংস"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"অগ্রাধিকার"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> অ্যাপে কথোপকথনের ক্ষেত্রে প্রযোজ্য সেটিংস কাজ করে না"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"কোনও সাম্প্রতিক বাবল নেই"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"সাম্প্রতিক ও বাতিল করা বাবল এখানে দেখা যাবে"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"এই বিজ্ঞপ্তিগুলি পরিবর্তন করা যাবে না।"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index a25a917b23ae..67515f7aad08 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Uvećaj prikaz na ekran"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Razvuci prikaz na ekran"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Snimak ekrana"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Otključajte telefon za više opcija"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Otključajte tablet za više opcija"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Otključajte uređaj za više opcija"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"je poslao/la sliku"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Spašavanje snimka ekrana..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Spašavanje snimka ekrana..."</string>
@@ -727,7 +724,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Prikazuje se na vrhu odjeljka za razgovor, pojavljuje se kao plutajući oblačić, prikazuje sliku profila na zaključanom ekranu"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Postavke"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritetni"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava postavke za određeni razgovor"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nema nedavnih oblačića"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Nedavni i odbačeni oblačići će se pojaviti ovdje"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ta obavještenja se ne mogu izmijeniti."</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 436776f68414..bca1fa21b51e 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom per omplir pantalla"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Estira per omplir pant."</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Captura de pantalla"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desbloqueja el teu telèfon per veure més opcions"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desbloqueja la teva tauleta per veure més opcions"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desbloqueja el teu dispositiu per veure més opcions"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ha enviat una imatge"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"S\'està desant captura de pantalla..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"S\'està desant la captura de pantalla..."</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Es mostra com a bombolla flotant a la part superior de la secció de converses i mostra la foto de perfil a la pantalla de bloqueig"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configuració"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritat"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet opcions de configuració específiques de converses"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No hi ha bombolles recents"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Les bombolles recents i les ignorades es mostraran aquí"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Aquestes notificacions no es poden modificar."</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 1bd6dec8d7d3..882c3e819a1b 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Přiblížit na celou obrazovku"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Na celou obrazovku"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Snímek obrazovky"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Chcete-li zobrazit další možnosti, odemkněte telefon"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Chcete-li zobrazit další možnosti, odemkněte tablet"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Chcete-li zobrazit další možnosti, odemkněte zařízení"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"odesílá obrázek"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Ukládání snímku obrazovky..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Ukládání snímku obrazovky..."</string>
@@ -728,7 +725,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Zobrazuje se v horní části sekce konverzace a má podobu plovoucí bubliny, zobrazuje profilovou fotku na obrazovce uzamčení"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nastavení"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorita"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> nepodporuje nastavení specifická pro konverzaci"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Žádné nedávné bubliny"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Zde se budou zobrazovat nedávné bubliny a zavřené bubliny"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Tato oznámení nelze upravit."</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index a463aac1fb6d..ecaf84f0b033 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom til fuld skærm"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Stræk til fuld skærm"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Lås din telefon op for at se flere valgmuligheder"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Lås din tablet op for at se flere valgmuligheder"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Lås din enhed op for at se flere valgmuligheder"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sendte et billede"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Gemmer screenshot..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Gemmer screenshot..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktivér"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktiver"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Skift enhed til lydudgang"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Appen er fastgjort"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Dette fastholder skærmen i visningen, indtil du frigør den. Tryk på Tilbage og Overblik, og hold fingeren nede for at frigøre skærmen."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Dette fastholder skærmen i visningen, indtil du frigør den. Hold Tilbage og Startskærm nede for at frigøre skærmen."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Dette fastholder skærmen i visningen, indtil du frigør den. Stryg opad, og hold fingeren nede for at frigøre den."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Dette fastholder skærmen i visningen, indtil du frigør den. Tryk på Tilbage, og hold fingeren nede for at frigøre skærmen."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Dette fastholder skærmen i visningen, indtil du frigør den. Hold Startskærm nede for at frigøre skærmen."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Personoplysninger er muligvis tilgængelige (f.eks. kontakter og mailindhold)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"En fastgjort app kan åbne andre apps."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Du kan frigøre denne app ved at holde knapperne Tilbage og Oversigt nede"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Du kan frigøre denne app ved at holde knapperne Tilbage og Hjem nede"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Du kan frigøre denne app ved at stryge opad og holde fingeren nede"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"OK"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Nej tak"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Appen er fastgjort"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Appen er frigjort"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Vil du skjule <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Den vises igen, næste gang du aktiverer den i indstillingerne."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Skjul"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Vises øverst i samtalesektionen, som en svævende boble og med profilbillede på låseskærmen"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Indstillinger"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> understøtter ikke samtalespecifikke indstillinger"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Ingen seneste bobler"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Nye bobler og afviste bobler vises her"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Disse notifikationer kan ikke redigeres."</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 1a796e3291f4..0d7197766b6c 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom auf Bildschirmgröße"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Auf Bildschirmgröße anpassen"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Entsperre dein Smartphone für weitere Optionen"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Entsperre dein Tablet für weitere Optionen"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Entsperre dein Gerät für weitere Optionen"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"Bild gesendet"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Screenshot wird gespeichert..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Screenshot wird gespeichert..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"aktivieren"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"deaktivieren"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Ausgabegerät wechseln"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"App ist auf dem Bildschirm fixiert"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Der Bildschirm bleibt so lange eingeblendet, bis du die Fixierung aufhebst. Berühre und halte dazu \"Zurück\" und \"Übersicht\"."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Der Bildschirm wird so lange angezeigt, bis du die Fixierung aufhebst. Berühre und halte dazu \"Zurück\" und \"Startbildschirm\"."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Der Bildschirm wird so lange angezeigt, bis du die Fixierung aufhebst. Dazu wischst du nach oben und hältst den Bildschirm gedrückt"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Der Bildschirm bleibt so lange eingeblendet, bis du die Fixierung aufhebst. Berühre und halte dazu \"Übersicht\"."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Der Bildschirm wird so lange angezeigt, bis du die Fixierung aufhebst. Berühre und halte dazu \"Startbildschirm\"."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Zugriff auf personenbezogene Daten wie beispielsweise Kontakte oder E-Mails ist möglich."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Eine auf dem Bildschirm fixierte App kann ggf. andere Apps öffnen."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Zum Aufheben der Fixierung dieser App \"Zurück\" und \"Übersicht\" halten"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Zum Aufheben der Fixierung dieser App \"Zurück\" und \"Startbildschirm\" halten"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Zum Loslösen der App nach oben wischen und halten"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Ok"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Nein danke"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Auf dem Bildschirm fixierte App"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Vom Bildschirm gelöste App"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ausblenden?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Sie wird wieder eingeblendet, wenn du sie in den Einstellungen erneut aktivierst."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Ausblenden"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Wird oben im Bereich \"Unterhaltungen\" als unverankerte Bubble mit einem Profilbild auf dem Sperrbildschirm angezeigt"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Einstellungen"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorität"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> unterstützt keine unterhaltungsspezifischen Einstellungen"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Keine kürzlich geschlossenen Bubbles"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Hier werden aktuelle und geschlossene Bubbles angezeigt"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Diese Benachrichtigungen können nicht geändert werden."</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 49a4dac968f2..ca8e555a6738 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Ζουμ σε πλήρη οθόνη"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Προβoλή σε πλήρη οθ."</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Στιγμιότυπο οθόνης"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Ξεκλειδώστε το τηλέφωνό σας για περισσότερες επιλογές."</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Ξεκλειδώστε το tablet για περισσότερες επιλογές."</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Ξεκλειδώστε τη συσκευή σας για περισσότερες επιλογές."</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"έστειλε μια εικόνα"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Αποθήκ. στιγμιότυπου οθόνης..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Αποθήκευση στιγμιότυπου οθόνης..."</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Εμφανίζεται στο επάνω μέρος της ενότητας συζητήσεων, προβάλλεται ως κινούμενο συννεφάκι, εμφανίζει τη φωτογραφία προφίλ στην οθόνη κλειδώματος"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ρυθμίσεις"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Προτεραιότητα"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δεν υποστηρίζει ρυθμίσεις για συγκεκριμένη συνομιλία"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Δεν υπάρχουν πρόσφατα συννεφάκια"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Τα πρόσφατα συννεφάκια και τα συννεφάκια που παραβλέψατε θα εμφανίζονται εδώ."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Δεν είναι δυνατή η τροποποίηση αυτών των ειδοποιήσεων"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 626b06782e4a..eb71c5673ae4 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Unlock your phone for more options"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Unlock your tablet for more options"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Unlock your device for more options"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Shows at top of conversation section, appears as floating bubble, displays profile picture on lock screen"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Settings"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support conversation-specific settings"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No recent bubbles"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recent bubbles and dismissed bubbles will appear here"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index e4646f18709e..fbc603a07451 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Unlock your phone for more options"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Unlock your tablet for more options"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Unlock your device for more options"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Shows at top of conversation section, appears as floating bubble, displays profile picture on lock screen"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Settings"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support conversation-specific settings"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No recent bubbles"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recent bubbles and dismissed bubbles will appear here"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 626b06782e4a..eb71c5673ae4 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Unlock your phone for more options"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Unlock your tablet for more options"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Unlock your device for more options"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Shows at top of conversation section, appears as floating bubble, displays profile picture on lock screen"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Settings"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support conversation-specific settings"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No recent bubbles"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recent bubbles and dismissed bubbles will appear here"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 626b06782e4a..eb71c5673ae4 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Unlock your phone for more options"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Unlock your tablet for more options"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Unlock your device for more options"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Shows at top of conversation section, appears as floating bubble, displays profile picture on lock screen"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Settings"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support conversation-specific settings"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No recent bubbles"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recent bubbles and dismissed bubbles will appear here"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"These notifications can\'t be modified."</string>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 99ca7806bf11..5e021c51fcca 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -719,7 +719,7 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‏‏‎‏‏‎‎‎‎‎‎‏‎‎‏‎‎‏‎‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎‎‏‏‎‎‏‎‏‎‎‎‏‏‏‎‎‎‏‎Shows at top of conversation section, appears as floating bubble, displays profile picture on lock screen‎‏‎‎‏‎"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‏‏‎‎‎‏‏‏‏‏‎‏‎‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‎‏‏‏‏‏‎‎‏‏‎Settings‎‏‎‎‏‎"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‎‎‏‏‏‎‎‎‎‏‏‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‎‏‏‎‏‎‎‎‏‎‏‎Priority‎‏‎‎‏‎"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‎‏‎‏‏‏‏‎‎‏‏‎‏‏‎‎‏‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‏‎‎‎‏‏‎‎‏‏‎‎‎‏‏‎‎‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ does not support conversation specific settings‎‏‎‎‏‎"</string>
+ <string name="no_shortcut" msgid="8257177117568230126">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‏‏‏‎‏‏‎‎‎‏‎‏‏‎‏‎‏‏‏‎‎‎‎‏‏‎‎‎‎‏‎‎‎‏‏‎‏‏‎‎‎‏‎‏‏‏‎‏‏‏‎‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ doesn’t support conversation features‎‏‎‎‏‎"</string>
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‎‏‏‎‎‏‎‎‏‎‎‏‎‎‎‏‏‏‎‏‎‏‎‎‎‏‎‏‎‏‎‎‏‎‎‏‎‎‏‎‎‎‎‏‏‎‎‏‏‏‎‏‎‎No recent bubbles‎‏‎‎‏‎"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‎‎‏‎‏‏‏‏‎‎‎‏‏‏‎‏‏‎‎‏‎‎‎‏‏‏‏‎‏‎‏‎‏‎‎‏‎‏‎‏‎‏‎‎‎‏‎‎‎‏‏‏‎‏‎‏‎Recent bubbles and dismissed bubbles will appear here‎‏‎‎‏‎"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‎‎‎‏‎‏‎‎‏‏‎‏‏‏‎‎‎‎‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‎‎These notifications can\'t be modified.‎‏‎‎‏‎"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 31b48d9c8ebd..5b3aada2d74e 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom para ocupar la pantalla"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Estirar p/ ocupar la pantalla"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Captura de pantalla"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desbloquea el teléfono para ver más opciones"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desbloquea la tablet para ver más opciones"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desbloquea el dispositivo para ver más opciones"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"envió una imagen"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Guardando captura de pantalla"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Guardando la captura de pantalla..."</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Aparece en la parte superior de la sección de conversaciones, en forma de burbuja flotante, y muestra la foto de perfil en la pantalla de bloqueo"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configuración"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridad"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admite opciones de configuración específicas de conversaciones"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No hay burbujas recientes"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Las burbujas recientes y las que se descartaron aparecerán aquí"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"No se pueden modificar estas notificaciones."</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index cdfad83af199..4c574c2872f5 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom para ajustar"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Expandir para ajustar"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Captura de pantalla"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desbloquea el teléfono para ver más opciones"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desbloquea el tablet para ver más opciones"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desbloquea el dispositivo para ver más opciones"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ha enviado una imagen"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Guardando captura..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Guardando captura..."</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Se muestra en la parte superior de la sección de conversaciones en forma de burbuja flotante, y la imagen de perfil aparece en la pantalla de bloqueo"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ajustes"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridad"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> no es compatible con ajustes específicos de conversaciones"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"No hay burbujas recientes"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Las burbujas recientes y las cerradas aparecerán aquí"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Estas notificaciones no se pueden modificar."</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 2e29befd6189..9e90e5edeec9 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Suumi ekraani täitmiseks"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Venita ekraani täitmiseks"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Ekraanipilt"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Lisavalikute nägemiseks avage oma telefon"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Lisavalikute nägemiseks avage oma tahvelarvuti"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Lisavalikute nägemiseks avage oma seade"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"saatis kujutise"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Kuvatõmmise salvestamine ..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Kuvatõmmise salvestamine ..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"luba"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"keela"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Väljundseadme vahetamine"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Rakendus on kinnitatud"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"See hoitakse kuval, kuni selle vabastate. Vabastamiseks puudutage pikalt nuppe Tagasi ja Ülevaade."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"See hoitakse kuval, kuni selle vabastate. Vabastamiseks puudutage pikalt nuppe Tagasi ja Avakuva."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"See hoitakse kuval, kuni selle vabastate. Vabastamiseks pühkige üles ja hoidke sõrme ekraanil."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"See hoitakse kuval, kuni selle vabastate. Vabastamiseks puudutage pikalt nuppu Ülevaade."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"See hoitakse kuval, kuni selle vabastate. Vabastamiseks puudutage pikalt nuppu Avakuva."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Isiklikud andmed (nt kontaktid ja meilide sisu) võivad olla juurdepääsetavad."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Kinnitatud rakendused võivad avada muid rakendusi."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Rakenduse vabastamiseks puudutage pikalt nuppe Tagasi ja Ülevaade"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Rakenduse vabastamiseks puudutage pikalt nuppe Tagasi ja Avaekraan"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Rakenduse vabastamiseks pühkige üles ja hoidke sõrme ekraanil"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Selge"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Tänan, ei"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Rakendus on kinnitatud"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Rakendus on vabastatud"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Kas peita <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"See kuvatakse uuesti järgmisel korral, kui selle seadetes sisse lülitate."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Peida"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Kuvatakse vestluste jaotise ülaosas hõljuva mullina ja lukustuskuval kuvatakse profiilipilt"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Seaded"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioriteetne"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei toeta vestluspõhiseid seadeid"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Hiljutisi mulle pole"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Siin kuvatakse hiljutised ja suletud mullid."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Neid märguandeid ei saa muuta."</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 8e38736ecbdf..ac3bd8704617 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Handiagotu pantaila betetzeko"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Luzatu pantaila betetzeko"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Pantaila-argazkia"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desblokeatu telefonoa aukera gehiago ikusteko"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desblokeatu tableta aukera gehiago ikusteko"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desblokeatu gailua aukera gehiago ikusteko"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"erabiltzaileak irudi bat bidali du"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Pantaila-argazkia gordetzen…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Pantaila-argazkia gordetzen…"</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Burbuila gisa agertzen da elkarrizketen atalaren goialdean, eta profileko argazkia bistaratzen du pantaila blokeatuta dagoenean"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ezarpenak"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Lehentasuna"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak ez du onartzen elkarrizketen berariazko ezarpenik"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Ez dago azkenaldiko burbuilarik"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Azken burbuilak eta baztertutakoak agertuko dira hemen"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Jakinarazpen horiek ezin dira aldatu."</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index b9472344f595..207d4a208158 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"بزرگ‌نمایی برای پر کردن صفحه"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"گسترده کردن برای پر کردن صفحه"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"نماگرفت"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"برای گزینه‌های بیشتر، قفل تلفن را باز کنید"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"برای گزینه‌های بیشتر، قفل رایانه لوحی را باز کنید"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"برای گزینه‌های بیشتر، قفل دستگاه را باز کنید"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"تصویری ارسال کرد"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"در حال ذخیره نماگرفت..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"درحال ذخیره نماگرفت…"</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"در بالای بخش مکالمه به‌صورت حبابک شناور نشان داده می‌شود و تصویر نمایه را در صفحه قفل نمایش می‌دهد"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"تنظیمات"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"اولویت"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> از تنظیمات خاص مکالمه پشتیبانی نمی‌کند"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"هیچ ابزارک اعلان جدیدی وجود ندارد"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ابزارک اعلان اخیر و ابزارک اعلان ردشده اینجا ظاهر خواهند شد"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"این اعلان‌ها قابل اصلاح نیستند."</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 7a83222754ec..ed6768caf75e 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoomaa koko näyttöön"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Venytä koko näyttöön"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Kuvakaappaus"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Avaa puhelimen lukitus, niin näet enemmän vaihtoehtoja"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Avaa tabletin lukitus, niin näet enemmän vaihtoehtoja"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Avaa laitteen lukitus, niin näet enemmän vaihtoehtoja"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"lähetti kuvan"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Tallennetaan kuvakaappausta..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Tallennetaan kuvakaappausta..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ota käyttöön"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"poista käytöstä"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Vaihda toistolaitetta"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Sovellus on kiinnitetty"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Pysyy näkyvissä, kunnes irrotat sen. Irrota painamalla pitkään Edellinen ja Viimeisimmät."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Pysyy näkyvissä, kunnes irrotat sen. Irrota painamalla pitkään Edellinen ja Aloitusnäyttö."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Pysyy näkyvissä, kunnes irrotat sen. Irrota pyyhkäisemällä ylös ja painamalla pitkään."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Pysyy näkyvissä, kunnes irrotat sen. Irrota painamalla pitkään Viimeisimmät."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Pysyy näkyvissä, kunnes irrotat sen. Irrota painamalla pitkään Aloitusnäyttö."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Henkilökohtaisiin tietoihin (esim. yhteystietoihin ja sähköpostin sisältöön) voi saada pääsyn."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Kiinnitetty sovellus voi avata muita sovelluksia."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Irrota sovellus koskettamalla pitkään Takaisin- ja Viimeisimmät-painikkeita"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Irrota sovellus koskettamalla pitkään Takaisin- ja Aloitusnäyttö-painikkeita"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Irrota sovellus pyyhkäisemällä ylös ja painamalla pitkään"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Selvä"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Ei kiitos"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Sovellus kiinnitetty"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Sovellus irrotettu"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Piilotetaanko <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Se tulee takaisin näkyviin, kun seuraavan kerran otat sen käyttöön asetuksissa."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Piilota"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Näkyy keskusteluosion yläosassa kelluvana kuplana, profiilikuva näkyy lukitusnäytöllä"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Asetukset"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Tärkeä"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei tue keskustelukohtaisia asetuksia"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Ei viimeaikaisia kuplia"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Viimeaikaiset ja äskettäin ohitetut kuplat näkyvät täällä"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Näitä ilmoituksia ei voi muokata"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 901d1e687004..e1d5cca477e5 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoomer pour remplir l\'écran"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Étirer pour remplir l\'écran"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Capture d\'écran"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Déverrouillez votre téléphone pour afficher davantage d\'options"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Déverrouillez votre tablette pour afficher davantage d\'options"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Déverrouillez votre appareil pour afficher davantage d\'options"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a envoyé une image"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Enregistrement capture écran…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Enregistrement capture écran…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"activer"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"désactiver"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Changer d\'appareil de sortie"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"L\'application est épinglée"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur « Retour » et « Aperçu »."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur les touches Retour et Accueil."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'épinglage. Pour annuler l\'épinglage, balayez l\'écran vers le haut et gardez le doigt dessus."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur « Aperçu »."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur la touche Accueil."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Certaines données personnelles pourraient être accessibles (comme les contacts et le contenu des courriels)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"L\'application épinglée peut ouvrir d\'autres applications."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Pour annuler l\'épinglage de cette application, maintenez un doigt sur les touches Retour et Aperçu"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Pour annuler l\'épinglage de cette application, maintenez un doigt sur les touches Retour et Accueil"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Pour annuler l\'épinglage de cette application, balayez-la vers le haut et gardez le doigt dessus"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"OK"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Non, merci"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Application épinglée"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"L\'épinglage de l\'application a été annulé"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Masquer <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Cet élément réapparaîtra la prochaine fois que vous l\'activerez dans les paramètres."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Masquer"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"S\'affiche en haut de la section des conversations sous forme de bulle flottante et affiche la photo du profil sur l\'écran de verrouillage"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Paramètres"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorité"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne prend pas en charge les paramètres propres aux conversations"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Aucune bulle récente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Les bulles récentes et les bulles ignorées s\'afficheront ici"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ces notifications ne peuvent pas être modifiées"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 0145ce9113e7..faaccc6c113d 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoomer pour remplir l\'écran"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Étirer pour remplir l\'écran"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Capture d\'écran"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Déverrouillez votre téléphone pour obtenir plus d\'options"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Déverrouillez votre tablette pour obtenir plus d\'options"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Déverrouillez votre appareil pour obtenir plus d\'options"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a envoyé une image"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Enregistrement capture écran…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Enregistrement de la capture d\'écran…"</string>
@@ -730,7 +727,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"S\'affiche en haut de la section des conversations, apparaît sous forme de bulle flottante, affiche la photo de profil sur l\'écran de verrouillage"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Paramètres"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritaire"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas compatible avec les paramètres de conversation"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Aucune bulle récente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Les bulles récentes et ignorées s\'afficheront ici"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Impossible de modifier ces notifications."</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 59537e218582..ef8223059404 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Ampliar ata ocupar todo"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Estirar ata ocupar todo"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Facer captura"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desbloquea o teléfono para ver máis opcións"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desbloquea a tableta para ver máis opcións"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desbloquea o dispositivo para ver máis opcións"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou unha imaxe"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Gardando captura de pantalla…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Gardando captura de pantalla…"</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Móstrase na parte superior da sección de conversas en forma de burbulla flotante e aparece a imaxe do perfil na pantalla de bloqueo"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configuración"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> non admite opcións de configuración específicas para conversas"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Non hai burbullas recentes"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"As burbullas recentes e ignoradas aparecerán aquí."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Estas notificacións non se poden modificar."</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 28d55b7df177..cb1e26e44500 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"સ્ક્રીન ભરવા માટે ઝૂમ કરો"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"સ્ક્રીન ભરવા માટે ખેંચો"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"સ્ક્રીનશૉટ"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"વધુ વિકલ્પો માટે તમારા ફોનને અનલૉક કરો"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"વધુ વિકલ્પો માટે તમારા ટૅબ્લેટને અનલૉક કરો"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"વધુ વિકલ્પો માટે તમારા ડિવાઇસને અનલૉક કરો"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"છબી મોકલી"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"સ્ક્રીનશોટ સાચવી રહ્યું છે…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"સ્ક્રીનશોટ સાચવી રહ્યું છે…"</string>
@@ -730,7 +727,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"એને વાતચીત વિભાગની ટોચ પર બતાવે છે, તરતા બબલ તરીકે દેખાય છે, લૉક સ્ક્રીન પર પ્રોફાઇલ ફોટા તરીકે બતાવે છે"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"સેટિંગ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"પ્રાધાન્યતા"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> વાતચીત માટેના ચોક્કસ સેટિંગને સપોર્ટ કરતી નથી"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"તાજેતરના કોઈ બબલ નથી"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"એકદમ નવા બબલ અને છોડી દીધેલા બબલ અહીં દેખાશે"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"આ નોટિફિકેશનમાં કોઈ ફેરફાર થઈ શકશે નહીં."</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index ba84d090287f..5e4d8df089da 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"स्‍क्रीन भरने के लिए ज़ूम करें"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"स्‍क्रीन भरने के लिए खींचें"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"स्क्रीनशॉट"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ज़्यादा विकल्प देखने के लिए, अपना फ़ोन अनलॉक करें"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ज़्यादा विकल्प देखने के लिए, अपना टैबलेट अनलॉक करें"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ज़्यादा विकल्प देखने के लिए, अपना डिवाइस अनलॉक करें"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"एक इमेज भेजी गई"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"स्क्रीनशॉट सहेजा जा रहा है..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रीनशॉट सहेजा जा रहा है..."</string>
@@ -597,29 +594,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"चालू करें"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"बंद करें"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"आउटपुट डिवाइस बदलें"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"ऐप्लिकेशन पिन किया गया है"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"इससे वह तब तक दिखता रहता है जब तक कि आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, \'वापस जाएं\' और \'खास जानकारी\' को दबाकर रखें."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"इससे वह तब तक दिखाई देती है जब तक आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, होम और वापस जाएं वाले बटन को दबाकर रखें."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"इससे ऐप्लिकेशन की स्क्रीन तब तक दिखाई देती है जब तक आप उसे अनपिन नहीं करते. अनपिन करने के लिए ऊपर स्वाइप करें और स्क्रीन दबाकर रखें."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"इससे वह तब तक दिखता रहता है जब तक कि आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, \'खास जानकारी\' को दबाकर रखें."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"इससे वह तब तक दिखाई देती है जब तक आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए, होम बटन को दबाकर रखें."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"निजी डेटा ऐक्सेस किया जा सकता है. जैसे कि संपर्क और ईमेल का कॉन्टेंट."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"पिन किए गए ऐप्लिकेशन से दूसरे ऐप्लिकेशन भी खोले जा सकते हैं."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"इस ऐप्लिकेशन को अनपिन करने के लिए, \'वापस जाएं\' और \'खास जानकारी\' बटन को साथ-साथ दबाकर रखें"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"इस ऐप्लिकेशन को अनपिन करने के लिए, \'होम\' और \'वापस जाएं\' बटन को साथ-साथ दबाकर रखें"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"इस ऐप्लिकेशन को अनपिन करने के लिए, ऊपर की ओर स्वाइप करें और स्क्रीन को दबाकर रखें"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"ठीक है"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"नहीं, रहने दें"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"ऐप्लिकेशन पिन किया गया"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"ऐप्लिकेशन अनपिन किया गया"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> को छिपाएं?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"जब आप उसे अगली बार सेटिंग में चालू करेंगे तो वह फिर से दिखाई देगी."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"छिपाएं"</string>
@@ -732,7 +721,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"इससे बातचीत की सुविधा, सेक्शन में सबसे ऊपर और फ़्लोटिंग बबल के तौर पर दिखती है. साथ ही, लॉक स्क्रीन पर प्रोफ़ाइल फ़ोटो दिखती है"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"सेटिंग"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"प्राथमिकता"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> में हर बातचीत के लिए अलग सेटिंग तय नहीं की जा सकती"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"हाल ही के बबल्स मौजूद नहीं हैं"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"हाल ही के बबल्स और हटाए गए बबल्स यहां दिखेंगे"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ये सूचनाएं नहीं बदली जा सकती हैं."</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 003f05c2ad84..46ed282f6c27 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zumiraj i ispuni zaslon"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Rastegni i ispuni zaslon"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Snimka zaslona"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Za više opcija otključajte telefon"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Za više opcija otključajte tablet"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Za više opcija otključajte uređaj"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"šalje sliku"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Spremanje snimke zaslona..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Spremanje snimke zaslona..."</string>
@@ -725,7 +722,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Prikazuje se pri vrhu odjeljka razgovora kao pomični oblačić i prikazuje profilnu sliku na zaključanom zaslonu"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Postavke"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava postavke koje se odnose na razgovor"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nema nedavnih oblačića"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Ovdje će se prikazivati nedavni i odbačeni oblačići"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Te se obavijesti ne mogu izmijeniti."</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 8e3a833289a3..924eed0835a0 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Nagyítás a kitöltéshez"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Nyújtás kitöltéshez"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Képernyőkép"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"További lehetőségekért oldja fel a telefont"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"További lehetőségekért oldja fel a táblagépet"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"További lehetőségekért oldja fel az eszközt"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"képet küldött"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Képernyőkép mentése..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Képernyőkép mentése..."</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"A beszélgetések szakaszának tetején, lebegő buborékként látható, megjeleníti a profilképet a lezárási képernyőn"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Beállítások"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritás"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás nem támogatja a beszélgetésspecifikus beállításokat"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nincsenek buborékok a közelmúltból"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"A legutóbbi és az elvetett buborékok itt jelennek majd meg"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ezeket az értesítéseket nem lehet módosítani."</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index dc84c41e7246..640f6cfb31c6 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Խոշորացնել` էկրանը լցնելու համար"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Ձգել` էկրանը լցնելու համար"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Սքրինշոթ"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Ապակողպեք ձեր հեռախոսը՝ լրացուցիչ կարգավորումները տեսնելու համար"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Ապակողպեք ձեր պլանշետը՝ լրացուցիչ կարգավորումները տեսնելու համար"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Ապակողպեք ձեր սարքը՝ լրացուցիչ կարգավորումները տեսնելու համար"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"պատկեր է ուղարկվել"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Սքրինշոթը պահվում է…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Սքրինշոթը պահվում է..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"միացնել"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"անջատել"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Փոխել արտածման սարքը"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Հավելվածն ամրացված է"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Էկրանը կմնա տեսադաշտում, մինչև այն ապամրացնեք: Ապամրացնելու համար հպեք և պահեք Հետ և Համատեսք կոճակները:"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Էկրանը կցուցադրվի այնքան ժամանակ, մինչև չապամրացնեք այն: Ապամրացնելու համար հպեք և պահեք «Հետ» և «Գլխավոր էկրան» կոճակները"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Էկրանը կցուցադրվի այնքան ժամանակ, մինչև որ չապամրացնեք այն: Ապամրացնելու համար մատը սահեցրեք վեր և պահեք։"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Էկրանը կմնա տեսադաշտում, մինչև այն ապամրացնեք: Ապամրացնելու համար հպեք և պահեք Համատեսք կոճակը:"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Էկրանը կցուցադրվի այնքան ժամանակ, մինչև որ չապամրացնեք այն: Ապամրացնելու համար հպեք և պահեք գլխավոր էկրանի կոճակը:"</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Ձեր անձնական տվյալները (օր․՝ կոնտակտները և նամակների բովանդակությունը) կարող են հասանելի դառնալ։"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Ամրացված հավելվածը կարող է այլ հավելվածներ գործարկել։"</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Հավելվածն ապամրացնելու համար հպեք և պահեք «Հետ» և «Համատեսք» կոճակները"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Հավելվածն ապամրացնելու համար հպեք և պահեք «Հետ» և «Գլխավոր էկրան» կոճակները"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Հավելվածն ապամրացնելու համար մատը սահեցրեք վերև և պահեք"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Եղավ"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Ոչ"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Հավելվածն ամրացվեց"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Հավելվածն ապամրացվեց"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Թաքցնե՞լ <xliff:g id="TILE_LABEL">%1$s</xliff:g>-ը:"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Այն դարձյալ կհայտնվի, երբ նորից միացնեք կարգավորումներում:"</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Թաքցնել"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Ցուցադրվում է զրույցների ցանկի վերևում, հայտնվում է լողացող ամպիկի տեսքով, ցուցադրում է պրոֆիլի նկարը կողպէկրանին"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Կարգավորումներ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Կարևոր"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը չի աջակցում զրույցի կարգավորումները"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Վերջին ամպիկներ չկան"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Այստեղ կցուցադրվեն վերջերս օգտագործված և փակված ամպիկները, որոնք կկարողանաք հեշտությամբ վերաբացել"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Այս ծանուցումները չեն կարող փոփոխվել:"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index afb96b3b520b..c101829211f6 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Perbesar utk mengisi layar"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Rentangkn utk mngisi layar"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Buka kunci ponsel untuk melihat opsi lainnya"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Buka kunci tablet untuk opsi lainnya"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Buka kunci perangkat untuk melihat opsi lainnya"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"mengirim gambar"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Menyimpan screenshot..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Menyimpan screenshot..."</string>
@@ -604,7 +601,7 @@
<string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Data pribadi dapat diakses (seperti kontak dan konten email)."</string>
<string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Aplikasi yang dipasangi pin dapat membuka aplikasi lain."</string>
<string name="screen_pinning_toast" msgid="8177286912533744328">"Untuk melepas pin aplikasi ini, sentuh &amp; lama tombol Kembali dan Ringkasan"</string>
- <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Untuk melepas pin layar ini, sentuh &amp; lama tombol Kembali dan Layar utama"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Untuk melepas pin aplikasi ini, sentuh &amp; lama tombol Kembali dan Layar utama"</string>
<string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Untuk melepas pin aplikasi ini, geser ke atas &amp; tahan"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Mengerti"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Lain kali"</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Muncul di atas bagian percakapan, ditampilkan sebagai balon yang mengambang, menampilkan gambar profil di layar kunci"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Setelan"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritas"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak mendukung setelan khusus percakapan"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Tidak ada balon baru-baru ini"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Balon yang baru dipakai dan balon yang telah ditutup akan muncul di sini"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Notifikasi ini tidak dapat diubah."</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 66db202feed5..29c145f0d635 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Fylla skjá með aðdrætti"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Teygja yfir allan skjáinn"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Skjámynd"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Taktu símann úr lás til að fá fleiri valkosti"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Taktu spjaldtölvuna úr lás til að fá fleiri valkosti"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Taktu tækið úr lás til að fá fleiri valkosti"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sendi mynd"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Vistar skjámynd…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Vistar skjámynd…"</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Birtist efst í samtalshluta, birtist sem fljótandi blaðra, birtir prófílmynd á lásskjánum"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Áfram"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Forgangur"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> styður ekki stillingar fyrir einstök samtöl"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Engar nýlegar blöðrur"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Nýlegar blöðrur og blöðrur sem þú hefur lokað birtast hér"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ekki er hægt að breyta þessum tilkynningum."</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 629b850b799e..ff1fb6794b59 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom per riempire schermo"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Estendi per riemp. schermo"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Sblocca il telefono per visualizzare altre opzioni"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Sblocca il tablet per visualizzare altre opzioni"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Sblocca il dispositivo per visualizzare altre opzioni"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"è stata inviata un\'immagine"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Salvataggio screenshot..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Salvataggio screenshot..."</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Viene mostrata in cima alla sezione delle conversazioni, appare sotto forma di bolla mobile, mostra l\'immagine del profilo nella schermata di blocco"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Impostazioni"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorità"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> non supporta impostazioni specifiche per le conversazioni"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nessuna bolla recente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Le bolle recenti e ignorate verranno visualizzate qui"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Impossibile modificare queste notifiche."</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 566baf143760..20006e5ed618 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"הגדל תצוגה כדי למלא את המסך"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"מתח כדי למלא את המסך"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"צילום מסך"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"לאפשרויות נוספות, יש לבטל את נעילת הטלפון"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"לאפשרויות נוספות, יש לבטל את נעילת הטאבלט"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"לאפשרויות נוספות, יש לבטל את נעילת המכשיר"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"נשלחה תמונה"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"שומר צילום מסך..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"שומר צילום מסך..."</string>
@@ -601,29 +598,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"הפעלה"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"השבתה"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"החלפת מכשיר פלט"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"האפליקציה מוצמדת"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'סקירה\' כדי לבטל את ההצמדה."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'דף הבית\' כדי לבטל את ההצמדה."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"נשאר בתצוגה עד לביטול ההצמדה. יש להחליק למעלה ולהחזיק כדי לבטל הצמדה."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצן \'סקירה\' כדי לבטל את ההצמדה."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצן \'דף הבית\' כדי לבטל את ההצמדה."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ייתכן שתתאפשר גישה למידע אישי (כמו אנשי קשר ותוכן מהאימייל)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"האפליקציה שהוצמדה עשויה לפתוח אפליקציות אחרות."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"כדי לבטל את ההצמדה של האפליקציה הזו, יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'סקירה\'"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"כדי לבטל את ההצמדה של האפליקציה הזו, יש ללחוץ לחיצה ארוכה על הלחצן \'הקודם\' והלחצן הראשי"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"לביטול ההצמדה של האפליקציה הזו, יש להחליק למעלה ולהחזיק"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"הבנתי"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"לא, תודה"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"האפליקציה הוצמדה"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"הצמדת האפליקציה בוטלה"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"להסתיר<xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"יופיע מחדש בפעם הבאה שתפעיל את האפשרות בהגדרות."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"הסתר"</string>
@@ -736,7 +725,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"מוצגת בחלק העליון של קטע התראות השיחה, מופיעה בבועה צפה, תוצג תמונת פרופיל במסך הנעילה"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"הגדרות"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"עדיפות"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לא תומכת בהגדרות ספציפיות לשיחות"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"אין בועות מהזמן האחרון"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"בועות אחרונות ובועות שנסגרו יופיעו כאן"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"לא ניתן לשנות את ההתראות האלה."</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 7567a224e863..1aa40327ee4e 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"画面サイズに合わせて拡大"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"画面サイズに合わせて拡大"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"スクリーンショット"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"スマートフォンのロックを解除してその他のオプションを表示する"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"タブレットのロックを解除してその他のオプションを表示する"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"デバイスのロックを解除してその他のオプションを表示する"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"画像を送信しました"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"スクリーンショットを保存中..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"スクリーンショットを保存しています..."</string>
@@ -730,7 +727,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"会話セクションの一番上にふきだしとして表示され、プロフィール写真がロック画面に表示されます"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"設定"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"優先度"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> は会話専用の設定をサポートしていません"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"最近閉じたバブルはありません"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"最近表示されたバブルや閉じたバブルが、ここに表示されます"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"これらの通知は変更できません。"</string>
@@ -759,7 +757,7 @@
<string name="notification_conversation_unfavorite" msgid="181383708304763807">"重要でない会話"</string>
<string name="notification_conversation_mute" msgid="268951550222925548">"マナーモード"</string>
<string name="notification_conversation_unmute" msgid="2692255619510896710">"アラートを受け取る"</string>
- <string name="notification_conversation_bubble" msgid="2242180995373949022">"バブルを表示"</string>
+ <string name="notification_conversation_bubble" msgid="2242180995373949022">"バブルで表示"</string>
<string name="notification_conversation_unbubble" msgid="6908427185031099868">"バブルを削除"</string>
<string name="notification_conversation_home_screen" msgid="8347136037958438935">"ホーム画面に追加"</string>
<string name="notification_menu_accessibility" msgid="8984166825879886773">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="MENU_DESCRIPTION">%2$s</xliff:g>"</string>
@@ -1014,7 +1012,7 @@
<string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"左下に移動"</string>
<string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"右下に移動"</string>
<string name="bubble_dismiss_text" msgid="7071770411580452911">"閉じる"</string>
- <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"会話をバブルにしない"</string>
+ <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"会話をバブルで表示しない"</string>
<string name="bubbles_user_education_title" msgid="5547017089271445797">"チャットでのバブルの使用"</string>
<string name="bubbles_user_education_description" msgid="1160281719576715211">"新しい会話はフローティング アイコン(バブル)として表示されます。タップするとバブルが開きます。ドラッグしてバブルを移動できます。"</string>
<string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"いつでもバブルを管理"</string>
@@ -1024,7 +1022,7 @@
<string name="notification_content_system_nav_changed" msgid="5077913144844684544">"システム ナビゲーションを更新しました。変更するには [設定] に移動してください。"</string>
<string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"システム ナビゲーションを更新するには [設定] に移動してください"</string>
<string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"スタンバイ"</string>
- <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"会話セクションの一番上にバブル表示"</string>
+ <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"会話セクションの一番上にバブルで表示"</string>
<string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"ロック画面にプロフィール写真を表示"</string>
<string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"他のアプリに重ねてフローティング バブルとして表示"</string>
<string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"サイレント モードに割り込み"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 4def42554e11..e8795eeffa17 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"მასშტაბი შეცვალეთ ეკრანის შესავსებად."</string>
<string name="compat_mode_off" msgid="7682459748279487945">"გაწიეთ ეკრანის შესავსებად."</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ეკრანის ანაბეჭდი"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"მეტი ვარიანტის სანახავად განბლოკეთ თქვენი ტელეფონი"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"მეტი ვარიანტის სანახავად განბლოკეთ თქვენი ტაბლეტი"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"მეტი ვარიანტის სანახავად განბლოკეთ თქვენი მოწყობილობა"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"გაიგზავნა სურათი"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"სკრინშოტის შენახვა…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ეკრანის სურათის შენახვა…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ჩართვა"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"გამორთვა"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"გამოტანის მოწყობილობის გადართვა"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"აპი ჩამაგრებულია"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"ამით ის დარჩება ხედში ჩამაგრების მოხსნამდე. ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ „უკან და მიმოხილვა“-ს."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ამით ის დარჩება ხედში ჩამაგრების მოხსნამდე. ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ „უკან მთავარ გვერდზე“-ს."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"ამით ის დარჩება ხედში ჩამაგრების მოხსნამდე. აუსვით ზემოთ და დააყოვნეთ ჩამაგრების მოსახსნელად."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"ამით ის დარჩება ხედში ჩამაგრების მოხსნამდე. ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ „მიმოხილვა“-ს."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"ამით ის დარჩება ხედში ჩამაგრების მოხსნამდე. ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ „მთავარ გვერდს“."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"შეიძლება მისაწვდომი გახდეს პერსონალური მონაცემები (მაგალითად, კონტაქტები და ელფოსტის კონტენტი)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"ჩამაგრებულმა აპმა შეიძლება სხვა აპები გახსნას."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"ამ აპის ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ ღილაკებს „უკან“ და „მიმოხილვა“"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"ამ აპის ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ ღილაკებს „უკან“ და „მთავარი გვერდი“"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"ამ აპის ჩამაგრების მოსახსნელად გადაფურცლეთ ზემოთ და არ აუშვათ"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"გასაგებია"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"არა, გმადლობთ"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"აპი ჩამაგრდა"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"აპის ჩამაგრება გაუქმდა"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"დაიმალოს <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"ის კვლავ გამოჩნდება, როდესაც პარამეტრებში ჩართავთ"</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"დამალვა"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"გამოჩნდება მიმოწერების სექციის ზედა ნაწილში მოლივლივე ბუშტის სახით, აჩვენებს პროფილის სურათს ჩაკეტილ ეკრანზე"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"პარამეტრები"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"პრიორიტეტი"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ს არ აქვს სპეციალურად მიმოწერისთვის განკუთვნილი პარამეტრების მხარდაჭერა"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ბოლო დროს გამოყენებული ბუშტები არ არის"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"აქ გამოჩნდება ბოლოდროინდელი ბუშტები და უარყოფილი ბუშტები"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ამ შეტყობინებების შეცვლა შეუძლებელია."</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index b7b1ac49b467..27308e84def0 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Экранды толтыру үшін ұлғайту"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Экранды толтыру үшін созу"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Скриншот"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Басқа опцияларды көру үшін телефон құлпын ашыңыз."</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Басқа опцияларды көру үшін планшет құлпын ашыңыз."</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Басқа опцияларды көру үшін құрылғы құлпын ашыңыз."</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"сурет жіберілді"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Скриншотты сақтауда…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Скриншотты сақтауда…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"қосу"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"өшіру"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Шығыс құрылғыны ауыстыру"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Қолданба бекітілді"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Экран босатылғанға дейін көрсетіліп тұрады. Оны босату үшін \"Артқа\" және \"Шолу\" түймелерін басып тұрыңыз."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Экран босатылғанға дейін көрсетіліп тұрады. Оны босату үшін \"Артқа\" және \"Негізгі бет\" түймелерін түртіп, ұстап тұрыңыз"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Экран босатылғанға дейін көрсетіліп тұрады. Экранды босату үшін жоғары сырғытып, ұстап тұрыңыз."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Экран босатылғанға дейін көрсетіліп тұрады. Оны босату үшін \"Кері\" түймесін басып тұрыңыз."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Экран босатылғанға дейін көрсетіліп тұрады. Оны босату үшін \"Негізгі бет\" түймесін түртіп, ұстап тұрыңыз."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Жеке деректер (мысалы, байланыс ақпараты және электрондық пошта мазмұны) ашық болуы мүмкін."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Бекітілген қолданба басқа қолданбаларды ашуы мүмкін."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Бұл қолданбаны босату үшін \"Артқа\" және \"Шолу\" түймелерін түртіп, ұстап тұрыңыз."</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Бұл қолданбаны босату үшін \"Артқа\" және \"Негізгі бет\" түймелерін түртіп, ұстап тұрыңыз."</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Бұл қолданбасы босату үшін жоғары сырғытып, ұстап тұрыңыз."</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Түсінікті"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Жоқ, рақмет"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Қолданба бекітілді."</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Қолданба босатылды."</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> жасыру керек пе?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Ол сіз оны параметрлерде келесі қосқанда қайта пайда болады."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Жасыру"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Әңгімелер бөлімінің жоғарғы жағында тұрады, қалқыма хабар түрінде шығады, құлыптаулы экранда профиль суретін көрсетеді"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Параметрлер"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Маңыздылығы"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасында чаттың арнайы параметрлеріне қолдау көрсетілмейді."</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Жақындағы қалқыма хабарлар жоқ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Жақында ашылған және жабылған қалқыма хабарлар осы жерде көрсетіледі."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Бұл хабарландыруларды өзгерту мүмкін емес."</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 15a022b4103b..3d6cfa16366e 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"ពង្រីក​​ដើម្បី​ឲ្យ​ពេញ​អេក្រង់"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"ទាញ​ដើម្បី​ឲ្យ​ពេញ​អេក្រង់"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"រូបថតអេក្រង់"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ដោះសោ​ទូរសព្ទរបស់អ្នក​សម្រាប់​ជម្រើសច្រើនទៀត"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ដោះសោ​ថេប្លេតរបស់អ្នក​សម្រាប់​ជម្រើសច្រើនទៀត"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ដោះសោ​ឧបករណ៍របស់អ្នក​សម្រាប់​ជម្រើសច្រើនទៀត"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"បាន​ផ្ញើរូបភាព"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"កំពុង​រក្សាទុក​រូបថត​អេក្រង់…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"កំពុង​រក្សាទុក​រូបថត​អេក្រង់..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"បើក"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"បិទ"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"ប្ដូរ​ឧបករណ៍​បញ្ចេញ​សំឡេង"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"កម្មវិធី​ត្រូវបានខ្ទាស់"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"វា​នឹង​នៅតែ​បង្ហាញ រហូត​ទាល់​តែ​អ្នក​ដក​ការដៅ។ សូម​សង្កត់​ប៊ូតុង​ថយ​ក្រោយ និង​ប៊ូតុង​ទិដ្ឋភាពរួម​ឲ្យ​ជាប់ ដើម្បី​ដក​ការ​ដៅ។"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"វា​នឹង​នៅតែ​បង្ហាញ រហូត​ទាល់​តែ​អ្នក​ដក​ការដៅ។ សូម​ចុចប៊ូតុង​ថយក្រោយ និងប៊ូតុង​ទំព័រដើម​ឱ្យ​ជាប់ ដើម្បី​ដក​ការ​ដៅ។"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"វា​នឹង​នៅតែ​បង្ហាញ រហូតទាល់​តែអ្នក​ដកការដៅ។ អូសឡើងលើ​ឱ្យជាប់ ដើម្បី​ដក​ការដៅ។"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"វា​នឹង​នៅតែ​បង្ហាញ រហូត​ទាល់​តែ​អ្នក​ដក​ការ​ដៅ។ សូម​សង្កត់​ប៊ូតុង​ទិដ្ឋភាពរួម​​ឲ្យ​ជាប់ ដើម្បី​ដក​ការ​ដៅ។"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"វា​នឹង​នៅតែ​បង្ហាញ រហូត​ទាល់​តែ​អ្នក​ដក​ការដៅ។ សូម​ចុច​ប៊ូតុង​ទំព័រដើម​ឱ្យ​ជាប់ ដើម្បី​ដក​ការ​ដៅ។"</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"អាចចូលប្រើ​ទិន្នន័យផ្ទាល់ខ្លួន​បាន (ដូចជា ទំនាក់ទំនង និងខ្លឹមសារ​អ៊ីមែលជាដើម)។"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"កម្មវិធីដែលបានខ្ទាស់​អាចបើកកម្មវិធី​ផ្សេងទៀតបាន។"</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"ដើម្បីដកខ្ទាស់​កម្មវិធីនេះ សូមចុច​ប៊ូតុង​ថយក្រោយ និងប៊ូតុង​ទិដ្ឋភាពរួម​ឱ្យជាប់"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"ដើម្បី​ដកខ្ទាស់​កម្មវិធីនេះ សូម​ចុចប៊ូតុង​ថយក្រោយ និង​ប៊ូតុងទំព័រដើម​ឱ្យជាប់"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"ដើម្បីដកខ្ទាស់កម្មវិធី​នេះ សូមអូសឡើងលើ​ឱ្យជាប់"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"យល់​ហើយ"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"ទេ អរគុណ"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"បានខ្ទាស់​កម្មវិធី"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"បានដកខ្ទាស់​កម្មវិធី"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"លាក់ <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"វា​នឹង​បង្ហាញ​ពេល​ក្រោយ​ ពេល​ដែល​អ្នក​បើក​ក្នុង​ការ​កំណត់។"</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"លាក់"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"បង្ហាញនៅខាងលើ​ផ្នែកសន្ទនា បង្ហាញជា​ពពុះអណ្ដែត បង្ហាញ​រូបភាព​កម្រងព័ត៌មាន​នៅលើ​អេក្រង់ចាក់សោ"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ការកំណត់"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"អាទិភាព"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> មិនអាចប្រើ​ការកំណត់​ជាក់លាក់ចំពោះការសន្ទនា​បានទេ"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"មិនមាន​ពពុះ​ថ្មីៗ​ទេ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ពពុះថ្មីៗ​ និង​ពពុះដែលបានបិទ​​នឹង​បង្ហាញ​នៅទីនេះ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"មិនអាច​កែប្រែ​ការជូនដំណឹង​ទាំងនេះ​បានទេ។"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 7d77fc144680..b21d50394a32 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"ಪರದೆ ತುಂಬಿಸಲು ಝೂಮ್ ಮಾಡು"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"ಪರದೆ ತುಂಬಿಸಲು ವಿಸ್ತಾರಗೊಳಿಸು"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಿ"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ಚಿತ್ರವನ್ನು ಕಳುಹಿಸಲಾಗಿದೆ"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಉಳಿಸಲಾಗುತ್ತಿದೆ…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಉಳಿಸಲಾಗುತ್ತಿದೆ…"</string>
@@ -252,7 +249,7 @@
<string name="accessibility_gps_enabled" msgid="4061313248217660858">"GPS ಸಕ್ರಿಯವಾಗಿದೆ."</string>
<string name="accessibility_gps_acquiring" msgid="896207402196024040">"GPS ಸ್ವಾಧೀನ."</string>
<string name="accessibility_tty_enabled" msgid="1123180388823381118">"ಟೆಲಿಟೈಪ್‌ರೈಟರ್ ಸಕ್ರಿಯವಾಗಿದೆ."</string>
- <string name="accessibility_ringer_vibrate" msgid="6261841170896561364">"ರಿಂಗರ್ ಕಂಪನ."</string>
+ <string name="accessibility_ringer_vibrate" msgid="6261841170896561364">"ರಿಂಗರ್ ವೈಬ್ರೇಟ್‌."</string>
<string name="accessibility_ringer_silent" msgid="8994620163934249882">"ರಿಂಗರ್ ಶಾಂತ."</string>
<!-- no translation found for accessibility_casting (8708751252897282313) -->
<skip />
@@ -730,7 +727,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"ಸಂಭಾಷಣೆ ವಿಭಾಗದ ಮೇಲ್ಭಾಗದಲ್ಲಿ ತೇಲುವ ಬಬಲ್‌ ಆಗಿ ಗೋಚರಿಸುತ್ತದೆ ಮತ್ತು ಪ್ರೊಫೈಲ್ ಚಿತ್ರವನ್ನು ಲಾಕ್‌ಸ್ಕ್ರೀನ್‌ ಮೇಲೆ‌ ಗೋಚರಿಸುತ್ತದೆ"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ಆದ್ಯತೆ"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಆ್ಯಪ್ ಸಂಭಾಷಣೆ ನಿರ್ದಿಷ್ಟ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಬಬಲ್ಸ್ ಇಲ್ಲ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ಇತ್ತೀಚಿನ ಬಬಲ್ಸ್ ಮತ್ತು ವಜಾಗೊಳಿಸಿದ ಬಬಲ್ಸ್ ಇಲ್ಲಿ ಗೋಚರಿಸುತ್ತವೆ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಮಾರ್ಪಡಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index a015afee2faa..91c58b03693f 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"전체화면 모드로 확대"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"전체화면 모드로 확대"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"스크린샷"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"더 많은 옵션을 확인하려면 휴대전화를 잠금 해제하세요."</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"더 많은 옵션을 확인하려면 태블릿을 잠금 해제하세요."</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"더 많은 옵션을 확인하려면 기기를 잠금 해제하세요."</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"이미지 보냄"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"캡쳐화면 저장 중..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"캡쳐화면 저장 중..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"사용"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"사용 중지"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"출력 기기 전환"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"앱 고정됨"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"고정 해제할 때까지 계속 표시됩니다. 고정 해제하려면 뒤로 및 최근 사용을 길게 터치하세요."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"고정 해제할 때까지 계속 표시됩니다. 고정 해제하려면 뒤로 및 홈을 길게 터치하세요."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"고정 해제할 때까지 계속 표시됩니다. 고정 해제하려면 위로 스와이프한 다음 탭한 상태를 유지하세요."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"고정 해제할 때까지 계속 표시됩니다. 고정 해제하려면 최근 사용을 길게 터치하세요."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"고정 해제할 때까지 계속 표시됩니다. 고정 해제하려면 홈을 길게 터치하세요."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"개인 정보가 표시될 수 있습니다(연락처, 이메일 내용 등)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"고정된 앱을 통해 다른 앱이 열릴 수 있습니다."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"이 앱을 고정 해제하려면 뒤로 및 최근 사용 버튼을 길게 터치하세요."</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"이 앱을 고정 해제하려면 뒤로 및 홈 버튼을 길게 터치하세요."</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"이 앱을 고정 해제하려면 위로 스와이프하고 유지하세요."</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"확인"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"거부"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"앱 고정됨"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"앱 고정 해제됨"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>을(를) 숨기시겠습니까?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"다음번에 설정에서 사용 설정하면 다시 표시됩니다."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"숨기기"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"대화 섹션 상단의 플로팅 대화창 또는 잠금 화면의 프로필 사진으로 표시됩니다."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"설정"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"우선순위"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서는 대화 관련 설정을 지원하지 않습니다."</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"최근에 닫은 대화창 없음"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"최근 대화창과 내가 닫은 대화창이 여기에 표시됩니다."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"이 알림은 수정할 수 없습니다."</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index fbf3dc05fc7b..1b046764f4a0 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Экрнд тлтр ү. чен өлч өзг"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Экранды толтуруу ү-н чоюу"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Скриншот"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Дагы башка параметрлерди көрүү үчүн телефонуңуздун кулпусун ачыңыз"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Дагы башка параметрлерди көрүү үчүн планшетиңиздин кулпусун ачыңыз"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Дагы башка параметрлерди көрүү үчүн түзмөгүңүздүн кулпусун ачыңыз"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"сүрөт жөнөттү"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Скриншот сакталууда…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Скриншот сакталууда..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"иштетүү"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"өчүрүү"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Аудио түзмөктү которуштуруу"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Колдонмо кадалды"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн, \"Артка\" жана \"Карап чыгуу\" баскычтарын басып, кармап туруңуз."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн, \"Артка\" жана \"Башкы бет\" баскычтарын басып, кармап туруңуз."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн өйдө сүрүп, коё бербей басып туруңуз."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн, \"Карап чыгуу\" баскычын басып, кармап туруңуз."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн, \"Башкы бет\" баскычын басып, кармап туруңуз."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Байланыштар жана электрондук почталардын мазмуну сыяктуу жеке дайындар ачык болушу мүмкүн."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Кадалган колдонмо башка колдонмолорду ача алат."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Бул колдонмону бошотуу үчүн \"Артка\" жана \"Назар салуу\" баскычтарын басып, кармап туруңуз"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Бул колдонмону бошотуу үчүн \"Артка\" жана \"Башкы бет\" баскычтарын басып, кармап туруңуз"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Бул колдонмону бошотуу үчүн аны өйдө сүрүп, кармап туруңуз"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Түшүндүм"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Жок, рахмат"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Колдонмо кадалды"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Кадалган колдонмо бошотулду"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> жашырылсынбы?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Бул кийинки жолу жөндөөлөрдөн күйгүзүлгөндө кайра көрүнөт."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Жашыруу"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Жазышуу бөлүмүнүн жогорку жагында калкып чыкма билдирме түрүндө көрүнүп, профиль сүрөтү кулпуланган экрандан чагылдырылат"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Жөндөөлөр"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Маанилүүлүгү"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда жазышууга болбойт"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Акыркы калкып чыкма билдирмелер жок"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Кайра жөнөтүлгөн жана жабылган калкып чыкма билдирмелер ушул жерде көрүнөт"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Бул билдирмелерди өзгөртүүгө болбойт."</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index a59716c4be06..62649f5550bd 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"ຊູມໃຫ້ເຕັມໜ້າຈໍ"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"ປັບໃຫ້ເຕັມໜ້າຈໍ"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ພາບໜ້າຈໍ"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ປົດລັອກໂທລະສັບຂອງທ່ານເພື່ອໃຊ້ຕົວເລືອກເພີ່ມເຕີມ"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ປົດລັອກແທັບເລັດຂອງທ່ານເພື່ອໃຊ້ຕົວເລືອກເພີ່ມເຕີມ"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ປົດລັອກອຸປະກອນຂອງທ່ານເພື່ອໃຊ້ຕົວເລືອກເພີ່ມເຕີມ"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ສົ່ງຮູບແລ້ວ"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"ກຳລັງບັນທຶກຮູບໜ້າຈໍ"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ກຳລັງບັນທຶກພາບໜ້າຈໍ..."</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"ສະແດງຢູ່ເທິງສຸດຂອງພາກສ່ວນການສົນທະນາ, ປາກົດເປັນ bubble ແບບລອຍ, ສະແດງຮູບໂປຣໄຟລ໌ຢູ່ໜ້າຈໍລັອກ"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ຕັ້ງຄ່າ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ສຳຄັນ"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ່ຮອງຮັບການຕັ້ງຄ່າສະເພາະຂອງການສົນທະນາ"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ບໍ່ມີຟອງຫຼ້າສຸດ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ຟອງຫຼ້າສຸດ ແລະ ຟອງທີ່ປິດໄປຈະປາກົດຢູ່ບ່ອນນີ້"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ບໍ່ສາມາດແກ້ໄຂການແຈ້ງເຕືອນເຫຼົ່ານີ້ໄດ້."</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 1c51b8662fa3..589b011a4651 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Keisti mast., kad atit. ekr."</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Ištempti, kad atit. ekr."</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Ekrano kopija"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Atrakinkite telefoną, kad galėtumėte naudoti daugiau parinkčių"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Atrakinkite planšetinį kompiuterį, kad galėtumėte naudoti daugiau parinkčių"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Atrakinkite įrenginį, kad galėtumėte naudoti daugiau parinkčių"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"išsiuntė vaizdą"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Išsaugoma ekrano kopija..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Išsaugoma ekrano kopija..."</string>
@@ -601,29 +598,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"įgalinti"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"išjungti"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Perjungti išvesties įrenginį"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Programa prisegta"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Tai bus rodoma, kol atsegsite. Palieskite ir palaikykite „Atgal“ ir „Apžvalga“, kad atsegtumėte."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Tai bus rodoma, kol atsegsite. Palieskite ir palaikykite „Atgal“ ir „Pagrindinis ekranas“, kad atsegtumėte."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Tai bus rodoma, kol atsegsite. Perbraukite aukštyn ir palaikykite, kad atsegtumėte."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Tai bus rodoma, kol atsegsite. Palieskite ir palaikykite „Apžvalga“, kad atsegtumėte."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Tai bus rodoma, kol atsegsite. Palieskite ir palaikykite „Pagrindinis ekranas“, kad atsegtumėte."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Gali būti pasiekiami asmens duomenys (pvz., kontaktai ir el. pašto turinys)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Prisegta programa gali atidaryti kitas programas."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Kad atsegtumėte šią programą, palieskite ir palaikykite mygtukus „Atgal“ ir „Apžvalga“"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Kad atsegtumėte šią programą, palieskite ir palaikykite mygtuką „Atgal“ ir pagrindinio ekrano mygtuką"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Kad atsegtumėte šią programą, perbraukite aukštyn ir palaikykite"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Supratau"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Ne, ačiū"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Programa prisegta"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Programa atsegta"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Slėpti „<xliff:g id="TILE_LABEL">%1$s</xliff:g>“?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Tai bus vėl parodyta, kai kitą kartą įjungsite tai nustatymuose."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Slėpti"</string>
@@ -736,7 +725,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Rodoma pokalbių skilties viršuje, rodoma kaip slankusis burbulas, pateikiama profilio nuotrauka užrakinimo ekrane"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nustatymai"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritetas"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ nepalaiko konkrečių pokalbių nustatymų"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nėra naujausių burbulų"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Naujausi ir atsisakyti burbulus bus rodomi čia"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Šių pranešimų keisti negalima."</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index db20f065820b..c3d461975eaa 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Tālumm., lai aizp. ekr."</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Stiepiet, lai aizp. ekr."</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Ekrānuzņēmums"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Atbloķējiet tālruni, lai skatītu citas opcijas."</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Atbloķējiet planšetdatoru, lai skatītu citas opcijas."</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Atbloķējiet ierīci, lai skatītu citas opcijas."</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"nosūtīts attēls"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saglabā ekrānuzņēmumu…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Notiek ekrānuzņēmuma saglabāšana..."</string>
@@ -725,7 +722,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Parādās sarunu sadaļas augšdaļā un kā peldošs burbulis, kā arī bloķēšanas ekrānā tiek rādīts profila attēls"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Iestatījumi"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritārs"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"Lietotnē <xliff:g id="APP_NAME">%1$s</xliff:g> netiek atbalstīti atsevišķu sarunu iestatījumi."</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nav nesen aizvērtu burbuļu"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Šeit būs redzami nesen rādītie burbuļi un aizvērtie burbuļi"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Šos paziņojumus nevar modificēt."</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index a897a8f492e3..96266805d127 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Зумирај да се исполни екранот"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Растегни да се исполни екранот"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Слика од екранот"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Отклучето го вашиот телефон за повеќе опции"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Отклучето го вашиот таблет за повеќе опции"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Отклучето го вашиот уред за повеќе опции"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"испрати слика"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Сликата на екранот се зачувува..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Сликата на екранот се зачувува..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"овозможи"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"оневозможи"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Префрлете го излезниот уред"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Апликацијата е прикачена"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ќе се гледа сѐ додека не го откачите. Допрете и држете „Назад“ и „Краток преглед“ за откачување."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ќе се гледа сѐ додека не го откачите. Допрете и задржете „Назад“ и „Почетен екран“ за откачување."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ќе се гледа сѐ додека не го откачите. Лизгајте нагоре и задржете за откачување."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ќе се гледа сѐ додека не го откачите. Допрете и држете „Краток преглед“ за откачување."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ќе се гледа сѐ додека не го откачите. Допрете и задржете „Почетен екран“ за откачување."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Личните податоци може да се пристапни (како контакти и содржини од е-пошта)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Прикачените апликации може да отворат други апликации."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"За откачување на апликацијава, допрете и држете на копчињата „Назад“ и „Преглед“"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"За откачување на апликацијава, допрете и држете на копчињата „Назад“ и „Почетен екран“"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"За откачување на апликацијава, повлечете нагоре и држете"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Сфатив"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Не, фала"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Апликацијата е прикачена"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Апликацијата е откачена"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Сокриј <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Ќе се појави повторно следниот пат кога ќе го вклучите во поставки."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Сокриј"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Се појавува на горниот дел од секцијата на разговорот во вид на лебдечко меурче, покажувајќи ја профилната слика на заклучениот екран"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Поставки"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддржува поставки поврзани со разговорите"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Нема неодамнешни балончиња"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Неодамнешните и отфрлените балончиња ќе се појавуваат тука"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Овие известувања не може да се изменат"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 43fc1bb0e514..4ac0d4f6e508 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"സ്‌ക്രീനിൽ ഉൾക്കൊള്ളിക്കാൻ സൂം ചെയ്യുക"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"സ്‌ക്രീനിൽ ഉൾക്കൊള്ളിക്കാൻ വലിച്ചുനീട്ടുക"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"സ്ക്രീൻഷോട്ട്"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് നിങ്ങളുടെ ഫോൺ അൺലോക്ക് ചെയ്യുക"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് നിങ്ങളുടെ ടാബ്‌ലെറ്റ് അൺലോക്ക് ചെയ്യുക"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് നിങ്ങളുടെ ഉപകരണം അൺലോക്ക് ചെയ്യുക"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ചിത്രം അയച്ചു"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"സ്‌ക്രീൻഷോട്ട് സംരക്ഷിക്കുന്നു..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"സ്‌ക്രീൻഷോട്ട് സംരക്ഷിക്കുന്നു..."</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"സംഭാഷണ വിഭാഗത്തിന് മുകളിലായി കാണിക്കുന്നു, ഫ്ലോട്ടിംഗ് ബബിളായി ദൃശ്യമാകുന്നു, ലോക്ക് സ്ക്രീനിൽ പ്രൊഫൈൽ ചിത്രം പ്രദർശിപ്പിക്കുന്നു"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ക്രമീകരണം"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"മുൻഗണന"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"സംഭാഷണ നിർദ്ദിഷ്ട ക്രമീകരണം <xliff:g id="APP_NAME">%1$s</xliff:g> പിന്തുണയ്ക്കുന്നില്ല"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"അടുത്തിടെയുള്ള ബബിളുകൾ ഒന്നുമില്ല"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"അടുത്തിടെയുള്ള ബബിളുകൾ, ഡിസ്മിസ് ചെയ്ത ബബിളുകൾ എന്നിവ ഇവിടെ ദൃശ്യമാവും"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ഈ അറിയിപ്പുകൾ പരിഷ്ക്കരിക്കാനാവില്ല."</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 6d4c8c650ca6..fa8b1a5fd26e 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Дэлгэц дүүргэх бол өсгөнө үү"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Дэлгэц дүүргэх бол татна уу"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Дэлгэцийн зураг дарах"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Бусад сонголтыг харахын тулд утасныхаа түгжээг тайлна уу"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Бусад сонголтыг харахын тулд таблетынхаа түгжээг тайлна уу"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Бусад сонголтыг харахын тулд төхөөрөмжийнхөө түгжээг тайлна уу"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"зураг илгээсэн"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Дэлгэцийн агшинг хадгалж байна…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Дэлгэцийн агшинг хадгалж байна…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"идэвхжүүлэх"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"идэвхгүй болгох"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Гаралтын төхөөрөмжийг солих"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Аппыг бэхэлсэн"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Таныг тогтоосныг болиулах хүртэл үүнийг харуулна. Тогтоосныг болиулахын тулд Буцах, Тоймыг дараад хүлээнэ үү."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Таныг тогтоосныг болиулах хүртэл үүнийг харуулсан хэвээр байна. Тогтоосныг болиулахын тулд Буцах, Нүүр хуудас товчлуурыг дараад хүлээнэ үү."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Та тогтоосныг болиулах хүртэл үүнийг харуулсан хэвээр байна. Тогтоосныг болиулахын тулд дээш удаан шударна уу."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Таныг тогтоосныг болиулах хүртэл харагдах болно. Тогтоосныг болиулахын тулд Буцах товчлуурыг дараад, хүлээнэ үү."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Таныг тогтоосныг болиулах хүртэл үүнийг харуулсан хэвээр байна. Тогтоосныг болиулахын тулд Нүүр хуудас товчлуурыг дараад хүлээнэ үү."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Хувийн мэдээлэлд хандах боломжтой байж магадгүй (харилцагчид, имэйлийн контент зэрэг)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Тогтоосон апп бусад аппыг нээж магадгүй."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Энэ аппыг тогтоосныг болиулахын тулд Буцах, Тойм товчлуурыг дараад хүлээнэ үү"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Энэ аппыг тогтоосныг болиулахын тулд Буцах, Нүүр хуудасны товчлуурыг дараад хүлээнэ үү"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Энэ аппыг тогтоосныг болиулахын тулд дээш шудраад хүлээнэ үү"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Ойлголоо"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Үгүй"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Аппыг бэхэлсэн"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Аппыг тогтоосныг болиулсан"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>-ийг нуух уу?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Тохируулгын хэсэгт үүнийг асаахад энэ дахин харагдана."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Нуух"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Харилцан ярианы хэсгийн дээд талд хөвж буй бөмбөлөг хэлбэрээр харагдах бөгөөд профайлын зургийг түгжигдсэн дэлгэцэд үзүүлнэ"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Тохиргоо"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Ач холбогдол"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> харилцан ярианы тодорхой тохиргоог дэмждэггүй"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Саяхны бөмбөлөг алга байна"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Саяхны бөмбөлгүүд болон үл хэрэгссэн бөмбөлгүүд энд харагдана"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Эдгээр мэдэгдлийг өөрчлөх боломжгүй."</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 12acadeb1d61..0a8360bb2b7e 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"स्क्रीन भरण्यासाठी झूम करा"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"स्क्रीन भरण्यासाठी ताणा"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"स्क्रीनशॉट"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"आणखी पर्यायांसाठी तुमचा फोन अनलॉक करा"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"आणखी पर्यायांसाठी तुमचा टॅबलेट अनलॉक करा"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"आणखी पर्यायांसाठी तुमचे डिव्हाइस अनलॉक करा"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"इमेज पाठवली आहे"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"स्क्रीनशॉट सेव्ह करत आहे…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रीनशॉट सेव्ह करत आहे…"</string>
@@ -730,7 +727,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"संभाषण विभागात सर्वात वरती फ्लोटिंग बबल म्हणून दिसते, लॉक स्क्रीनवर प्रोफाइल पिक्चर दाखवते"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"सेटिंग्ज"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"प्राधान्य"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> संभाषण विशिष्ट सेटिंग्जना सपोर्ट करत नाही"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"अलीकडील कोणतेही बबल नाहीत"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"अलीकडील बबल आणि डिसमिस केलेले बबल येथे दिसतील"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"या सूचनांमध्ये सुधारणा केली जाऊ शकत नाही."</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 63b6f1cb4b79..ef8198a3f378 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zum untuk memenuhi skrin"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Regang utk memenuhi skrin"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Tangkapan skrin"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Buka kunci telefon anda untuk mendapatkan lagi pilihan"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Buka kunci tablet anda untuk mendapatkan lagi pilihan"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Buka kunci peranti anda untuk mendapatkan lagi pilihan"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"menghantar imej"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Menyimpan tangkapan skrin..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Menyimpan tangkapan skrin..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"dayakan"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"lumpuhkan"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Tukar peranti output"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Apl telah disemat"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Tindakan ini memastikan skrin kelihatan sehingga anda menyahsemat. Sentuh &amp; tahan Kembali dan Ikhtisar untuk menyahsemat."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Tindakan ini memastikan skrin kelihatan sehingga anda menyahsemat. Sentuh &amp; tahan Kembali dan Skrin Utama untuk menyahsemat."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Tindakan ini memastikan skrin kelihatan sehingga anda menyahsemat. Leret ke atas &amp; tahan untuk menyahsemat."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Tindakan ini memastikan skrin kelihatan sehingga anda menyahsemat. Sentuh &amp; tahan Ikhtisar untuk menyahsemat."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Tindakan ini memastikan skrin kelihatan sehingga anda menyahsemat. Sentuh &amp; tahan Skrin Utama untuk menyahsemat."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Data peribadi mungkin boleh diakses (seperti kenalan dan kandungan e-mel)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Apl yang disematkan boleh membuka aplikasi lain."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Untuk menyahsemat apl ini, sentuh &amp; tahan butang Kembali dan Ikhtisar"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Untuk menyahsemat apl ini, sentuh &amp; tahan butang Kembali dan Skrin Utama"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Untuk menyahsemat apl ini, leret ke atas &amp; tahan"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Faham"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Tidak"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Apl disemat"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Apl dinyahsemat"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Sembunyikan <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Mesej itu akan terpapar semula pada kali seterusnya anda menghidupkan apl dalam tetapan."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Sembunyikan"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Ditunjukkan di sebelah atas bahagian perbualan, muncul sebagai gelembung terapung, memaparkan gambar profil pada skrin kunci"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Tetapan"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Keutamaan"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak menyokong tetapan khusus perbualan"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Tiada gelembung terbaharu"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Gelembung baharu dan gelembung yang diketepikan akan dipaparkan di sini"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Pemberitahuan ini tidak boleh diubah suai."</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 991e774ac4c2..96c35781204e 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -42,7 +42,7 @@
<string name="status_bar_settings_auto_rotation" msgid="8329080442278431708">"မျက်နှာပြင်အလိုအလျောက်လှည့်ရန်"</string>
<string name="status_bar_settings_mute_label" msgid="914392730086057522">"MUTE"</string>
<string name="status_bar_settings_auto_brightness_label" msgid="2151934479226017725">"AUTO"</string>
- <string name="status_bar_settings_notifications" msgid="5285316949980621438">"သတိပေးချက်များ"</string>
+ <string name="status_bar_settings_notifications" msgid="5285316949980621438">"အကြောင်းကြားချက်များ"</string>
<string name="bluetooth_tethered" msgid="4171071193052799041">"ဘလူးတုသ်မှတဆင့်ပြန်လည်ချိတ်ဆက်ခြင်း"</string>
<string name="status_bar_input_method_settings_configure_input_methods" msgid="2972273031043777851">"ထည့်သွင်းနည်းများ သတ်မှတ်ခြင်း"</string>
<string name="status_bar_use_physical_keyboard" msgid="4849251850931213371">"ခလုတ်ပါဝင်သော ကီးဘုတ်"</string>
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"ဇူးမ်အပြည့်ဆွဲခြင်း"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"ဖန်သားပြင်အပြည့်ဆန့်ခြင်း"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"နောက်ထပ် ထိန်းချုပ်မှုများအတွက် သင့်ဖုန်းကို လော့ခ်ဖွင့်ပါ"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"နောက်ထပ် ထိန်းချုပ်မှုများအတွက် သင့်တက်ဘလက်ကို လော့ခ်ဖွင့်ပါ"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"နောက်ထပ် ထိန်းချုပ်မှုများအတွက် သင့်စက်ကို လော့ခ်ဖွင့်ပါ"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ပုံပို့ထားသည်"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"ဖန်သားပြင်ဓါတ်ပုံသိမ်းစဉ်.."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ဖန်သားပြင်ဓါတ်ပုံရိုက်ခြင်းအား သိမ်းဆည်းပါမည်"</string>
@@ -595,7 +592,7 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ဖွင့်ရန်"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ပိတ်ရန်"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"အထွက် စက်ပစ္စည်းကို ပြောင်းပါ"</string>
- <string name="screen_pinning_title" msgid="9058007390337841305">"အက်ပ်ကို ပင်ထိုးလိုက်သည်"</string>
+ <string name="screen_pinning_title" msgid="9058007390337841305">"အက်ပ်ကို ပင်ထိုးထားသည်"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"သင်ပင်မဖြုတ်မခြင်း ၎င်းကို ပြသထားပါမည်။ ပင်ဖြုတ်ရန် Back နှင့် Overview ကို ထိ၍ဖိထားပါ။"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"သင်က ပင်မဖြုတ်မခြင်း ၎င်းကို ပြသထားပါမည်။ ပင်ဖြုတ်ရန် \'နောက်သို့\' နှင့် \'ပင်မ\' ခလုတ်တို့ကို တို့၍ဖိထားပါ။"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"သင်က ပင်မဖြုတ်မချင်း ၎င်းကို ပြသထားပါမည်။ ပင်ဖြုတ်ရန် အပေါ်သို့ပွတ်ဆွဲပြီး ဖိထားပါ။"</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"စကားဝိုင်းကဏ္ဍ၏ ထိပ်ပိုင်းတွင် ပြပြီး ပူဖောင်းကွက်အဖြစ် မြင်ရသည်၊ လော့ခ်ချထားချိန် မျက်နှာပြင်တွင် ပရိုဖိုင်ပုံကို ပြသည်"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ဆက်တင်များ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ဦးစားပေး"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> က စကားဝိုင်းအလိုက် ဆက်တင်များကို မပံ့ပိုးပါ"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"လတ်တလော ပူဖောင်းကွက်များ မရှိပါ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"လတ်တလော ပူဖောင်းကွက်များနှင့် ပိတ်လိုက်သော ပူဖောင်းကွက်များကို ဤနေရာတွင် မြင်ရပါမည်"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ဤအကြောင်းကြားချက်များကို ပြုပြင်၍ မရပါ။"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 22a7ff88cd55..241b6c383bb0 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom for å fylle skjermen"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Strekk for å fylle skjerm"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Skjermdump"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Lås opp telefonen din for å få flere alternativer"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Lås opp nettbrettet ditt for å få flere alternativer"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Lås opp enheten din for å få flere alternativer"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"har sendt et bilde"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Lagrer skjermdumpen …"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Lagrer skjermdumpen …"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"slå på"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"slå av"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Bytt enhet for lydutgang"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Appen er festet"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"På denne måten blir skjermen synlig frem til du løsner den. Trykk og hold inne Tilbake og Oversikt for å løsne den."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"På denne måten blir skjermen synlig frem til du løsner den. Trykk og hold inne Tilbake og Startside for å løsne den."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"På denne måten blir skjermen synlig frem til du løsner den. Sveip opp og hold for å løsne."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"På denne måten blir skjermen synlig frem til du løsner den. Trykk og hold inne Oversikt for å løsne den."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"På denne måten blir skjermen synlig frem til du løsner den. Trykk og hold inne Startside for å løsne den."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Personlige data kan være tilgjengelige (for eksempel kontakter og e-postinnhold)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Den festede appen kan åpne andre apper."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"For å løsne denne appen, trykk og hold inne tilbakeknappen og oversiktsknappen"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"For å løsne denne appen, trykk og hold inne tilbakeknappen og hjemknappen"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"For å løsne denne appen, sveip opp og hold"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Skjønner"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Nei takk"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Appen er festet"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Appen er løsnet"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Vil du skjule <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Den vises igjen neste gang du slår den på i innstillingene."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Skjul"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Vises øverst i samtaledelen, vises som en flytende boble, viser profilbildet på låseskjermen"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Innstillinger"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> støtter ikke samtalespesifikke innstillinger"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Ingen nylige bobler"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Nylige bobler og avviste bobler vises her"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Disse varslene kan ikke endres."</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 8f703f9d0098..ccce091745b0 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"स्क्रिन भर्न जुम गर्नुहोस्"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"स्क्रिन भर्न तन्काउनुहोस्"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"स्क्रिनसट"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"थप विकल्पहरू हेर्न आफ्नो फोन अनलक गर्नुहोस्"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"थप विकल्पहरू हेर्न आफ्नो ट्याब्लेट अनलक गर्नुहोस्"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"थप विकल्पहरू हेर्न आफ्नो यन्त्र अनलक गर्नुहोस्"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"कुनै छवि पठाइयो"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"स्क्रिनसट बचत गर्दै…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रिनसट बचत गर्दै…"</string>
@@ -730,7 +727,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"वार्तालाप खण्डको सिरानमा देखा पर्छ, तैरने बबलका रूपमा देखा पर्छ, लक स्क्रिनमा प्रोफाइल तस्बिर देखाइन्छ"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"सेटिङ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"प्राथमिकता"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा वार्तालापविशेषका लागि सेटिङ उपलब्ध छैन"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"हालैका बबलहरू छैनन्"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"हालैका बबल र खारेज गरिएका बबलहरू यहाँ देखिने छन्"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"यी सूचनाहरू परिमार्जन गर्न मिल्दैन।"</string>
diff --git a/packages/SystemUI/res/values-night/styles.xml b/packages/SystemUI/res/values-night/styles.xml
index 4fdeb6fa4a92..50261e1b2139 100644
--- a/packages/SystemUI/res/values-night/styles.xml
+++ b/packages/SystemUI/res/values-night/styles.xml
@@ -29,4 +29,9 @@
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
+ <style name="qs_security_footer" parent="@style/qs_theme">
+ <item name="android:textColor">#B3FFFFFF</item> <!-- 70% white -->
+ <item name="android:tint">#FFFFFFFF</item>
+ </style>
+
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index bcf9c6189482..3b70c39eb5f5 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom om scherm te vullen"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Rek uit v. schermvulling"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Ontgrendel je telefoon voor meer opties"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Ontgrendel je tablet voor meer opties"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Ontgrendel je apparaat voor meer opties"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"heeft een afbeelding gestuurd"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Screenshot opslaan..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Screenshot opslaan..."</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Wordt bovenaan het gedeelte met gesprekken weergegeven, verschijnt als zwevende bubbel, geeft de profielfoto weer op het vergrendelingsscherm"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Instellingen"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioriteit"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ondersteunt geen gespreksspecifieke instellingen"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Geen recente bubbels"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Recente bubbels en gesloten bubbels worden hier weergegeven"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Deze meldingen kunnen niet worden aangepast."</string>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 73c36907ed8e..cd24e358ba31 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"ସ୍କ୍ରୀନ ଭରିବା ପାଇଁ ଜୁମ୍ କରନ୍ତୁ"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"ସ୍କ୍ରୀନ୍‌କୁ ଭରିବା ପାଇଁ ଟାଣନ୍ତୁ"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ସ୍କ୍ରିନ୍‌ସଟ୍ ନିଅନ୍ତୁ"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ଅଧିକ ବିକଳ୍ପ ପାଇଁ ଆପଣଙ୍କ ଫୋନ୍ ଅନଲକ୍ କରନ୍ତୁ"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ଅଧିକ ବିକଳ୍ପ ପାଇଁ ଆପଣଙ୍କ ଟାବଲେଟ୍ ଅନଲକ୍ କରନ୍ତୁ"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ଅଧିକ ବିକଳ୍ପ ପାଇଁ ଆପଣଙ୍କ ଡିଭାଇସ୍ ଅନଲକ୍ କରନ୍ତୁ"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ଏକ ଛବି ପଠାଯାଇଛି"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"ସ୍କ୍ରୀନଶଟ୍‍ ସେଭ୍‍ କରାଯାଉଛି…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ସ୍କ୍ରୀନଶଟ୍‍ ସେଭ୍‍ କରାଯାଉଛି…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ସକ୍ଷମ କରନ୍ତୁ"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ଅକ୍ଷମ କରନ୍ତୁ"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"ଆଉଟପୁଟ୍ ଡିଭାଇସ୍‌କୁ ଯାଆନ୍ତୁ"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"ଆପକୁ ପିନ୍ କରାଯାଇଛି"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"ଆପଣ ଅନପିନ୍‍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍‍ କରିବାକୁ ସ୍ପର୍ଶ କରି ଧରିରଖନ୍ତୁ ଓ ଦେଖନ୍ତୁ।"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"ଆପଣ ଅନପିନ୍‍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍‍ କରିବା ପାଇଁ ହୋମ୍ ଓ ବ୍ୟାକ୍ ବଟନ୍‌କୁ ଧରିରଖନ୍ତୁ।"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"ଆପଣ ଅନ୍‌ପିନ୍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଯାଉଥିବ। ଅନ୍‌ପିନ୍ କରିବା ପାଇଁ ଉପରକୁ ସ୍ୱାଇପ୍‌ କରି ଧରି ରଖନ୍ତୁ"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"ଆପଣ ଅନପିନ୍‍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍‍ କରିବାକୁ ସ୍ପର୍ଶ କରନ୍ତୁ ଏବଂ ଓଭରଭ୍ୟୁକୁ ଧରିରଖନ୍ତୁ।"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"ଆପଣ ଅନପିନ୍‍ ନକରିବା ପର୍ଯ୍ୟନ୍ତ ଏହା ଦେଖାଉଥିବ। ଅନପିନ୍‍ କରିବା ପର୍ଯ୍ୟନ୍ତ ହୋମ୍‌କୁ ଦାବିଧରନ୍ତୁ।"</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ବ୍ୟକ୍ତିଗତ ଡାଟାକୁ ଆକ୍ସେସ୍ କରାଯାଇପାରେ (ଯେପରିକି ଯୋଗାଯୋଗଗୁଡ଼ିକ ଏବଂ ଇମେଲ୍ ବିଷୟବସ୍ତୁ)।"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"ପିନ୍ କରାଯାଇଥିବା ଆପଟି ଅନ୍ୟ ଆପଗୁଡ଼ିକୁ ଖୋଲିପାରେ।"</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"ଏହି ଆପକୁ ଅନପିନ୍ କରିବା ପାଇଁ, \"ବ୍ୟାକ୍\" ଏବଂ \"ଓଭରଭିଉ\" ବଟନକୁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"ଏହି ଆପକୁ ଅନପିନ୍ କରିବାକୁ, \"ବ୍ୟାକ୍\" ଏବଂ \"ହୋମ୍\" ବଟନକୁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"ଏହି ଆପକୁ ଅନପିନ୍ କରିବାକୁ, ଉପରକୁ ସ୍ୱାଇପ୍ କରି ଧରି ରଖନ୍ତୁ"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"ବୁଝିଗଲି"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"ନାହିଁ, ଥାଉ"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"ଆପ୍ ପିନ୍ କରାଯାଇଛି"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"ଆପ୍ ଅନପିନ୍ କରାଯାଇଛି"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ଲୁଚାନ୍ତୁ?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"ଆଗକୁ ଆପଣ ଯେତେବେଳେ ଏହି ସେଟିଙ୍ଗକୁ ଚାଲୁ କରିବେ, ଏହା ପୁଣି ଦେଖାଦେବ।"</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"ଲୁଚାନ୍ତୁ"</string>
@@ -715,7 +704,7 @@
<string name="inline_minimize_button" msgid="1474436209299333445">"ଛୋଟ କରନ୍ତୁ"</string>
<string name="inline_silent_button_silent" msgid="525243786649275816">"ନୀରବ"</string>
<string name="inline_silent_button_stay_silent" msgid="2129254868305468743">"ନୀରବ ରହନ୍ତୁ"</string>
- <string name="inline_silent_button_alert" msgid="5705343216858250354">"ଆଲର୍ଟ କରିବା"</string>
+ <string name="inline_silent_button_alert" msgid="5705343216858250354">"ଆଲର୍ଟିଂ"</string>
<string name="inline_silent_button_keep_alerting" msgid="6577845442184724992">"ଆଲର୍ଟ କରିବା ଜାରି ରଖନ୍ତୁ"</string>
<string name="inline_turn_off_notifications" msgid="8543989584403106071">"ବିଜ୍ଞପ୍ତି ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="inline_keep_showing_app" msgid="4393429060390649757">"ଏହି ଆପ୍‌ରୁ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଦେଖାଇବା ଜାରି ରଖିବେ?"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"ବାର୍ତ୍ତାଳାପ ବିଭାଗର ଶୀର୍ଷରେ ଦେଖାଏ, ଭାସମାନ ବବଲ୍ ଭାବେ ଦେଖାଯାଏ, ଲକ୍ ସ୍କ୍ରିନରେ ପ୍ରୋଫାଇଲ୍ ଛବି ଡିସପ୍ଲେ କରେ"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ସେଟିଂସ୍"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ପ୍ରାଥମିକତା"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବାର୍ତ୍ତାଳାପ ସମ୍ବନ୍ଧିତ ନିର୍ଦ୍ଦିଷ୍ଟ ସେଟିଂସକୁ ସମର୍ଥନ କରେ ନାହିଁ"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ବର୍ତ୍ତମାନ କୌଣସି ବବଲ୍ ନାହିଁ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ବର୍ତ୍ତମାନର ଏବଂ ଖାରଜ କରାଯାଇଥିବା ବବଲଗୁଡ଼ିକ ଏଠାରେ ଦେଖାଯିବ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ଏହି ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ପରିବର୍ତ୍ତନ କରିହେବ ନାହିଁ।"</string>
@@ -758,7 +748,7 @@
<string name="notification_conversation_favorite" msgid="1905240206975921907">"ଗୁରୁତ୍ୱପୂର୍ଣ୍ଣ ବାର୍ତ୍ତାଳାପ"</string>
<string name="notification_conversation_unfavorite" msgid="181383708304763807">"କୌଣସି ଗୁରୁତ୍ୱପୂର୍ଣ୍ଣ ବାର୍ତ୍ତାଳାପ ନାହିଁ"</string>
<string name="notification_conversation_mute" msgid="268951550222925548">"ନିରବ କରାଯାଇଛି"</string>
- <string name="notification_conversation_unmute" msgid="2692255619510896710">"ଆଲର୍ଟ କରୁଛି"</string>
+ <string name="notification_conversation_unmute" msgid="2692255619510896710">"ଆଲର୍ଟିଂ"</string>
<string name="notification_conversation_bubble" msgid="2242180995373949022">"ବବଲ୍ ଦେଖାନ୍ତୁ"</string>
<string name="notification_conversation_unbubble" msgid="6908427185031099868">"ବବଲଗୁଡ଼ିକ କାଢ଼ି ଦିଅନ୍ତୁ"</string>
<string name="notification_conversation_home_screen" msgid="8347136037958438935">"ମୂଳ ସ୍କ୍ରିନରେ ଯୋଗ କରନ୍ତୁ"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 59009a1f94b0..22b1029ea26a 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"ਸਕ੍ਰੀਨ ਭਰਨ ਲਈ ਜ਼ੂਮ ਕਰੋ"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"ਸਕ੍ਰੀਨ ਭਰਨ ਲਈ ਸਟ੍ਰੈਚ ਕਰੋ"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਆਪਣਾ ਫ਼ੋਨ ਅਣਲਾਕ ਕਰੋ"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਆਪਣਾ ਟੈਬਲੈੱਟ ਅਣਲਾਕ ਕਰੋ"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਆਪਣਾ ਡੀਵਾਈਸ ਅਣਲਾਕ ਕਰੋ"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ਚਿੱਤਰ ਭੇਜਿਆ ਗਿਆ"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸੁਰੱਖਿਅਤ ਕਰ ਰਿਹਾ ਹੈ…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸੁਰੱਖਿਅਤ ਕਰ ਰਿਹਾ ਹੈ…"</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"ਗੱਲਬਾਤ ਸੈਕਸ਼ਨ ਦੇ ਸਿਖਰ \'ਤੇ ਦਿਖਾਈਆਂ ਜਾਂਦੀਆਂ ਹਨ, ਬਬਲ ਵਜੋਂ ਦਿਸਦੀਆਂ ਹਨ, ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ ਪ੍ਰੋਫਾਈਲ ਤਸਵੀਰ ਦਿਖਾਈ ਜਾਂਦੀ ਹੈ"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ਸੈਟਿੰਗਾਂ"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ਤਰਜੀਹ"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਗੱਲਬਾਤ ਸੰਬੰਧੀ ਵਿਸ਼ੇਸ਼ ਸੈਟਿੰਗਾਂ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ਕੋਈ ਹਾਲੀਆ ਬਬਲ ਨਹੀਂ"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ਹਾਲੀਆ ਬਬਲ ਅਤੇ ਖਾਰਜ ਕੀਤੇ ਬਬਲ ਇੱਥੇ ਦਿਸਣਗੇ"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਸੋਧਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ।"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 59fa13cad8f1..cea8ece68e94 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Powiększ, aby wypełnić ekran"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Rozciągnij, aby wypełnić ekran"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Zrzut ekranu"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Odblokuj telefon, by wyświetlić więcej opcji"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Odblokuj tablet, by wyświetlić więcej opcji"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Odblokuj urządzenie, by wyświetlić więcej opcji"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"wysłano obraz"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Zapisywanie zrzutu ekranu..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Zapisywanie zrzutu ekranu..."</string>
@@ -601,29 +598,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"włącz"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"wyłącz"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Przełącz urządzenie wyjściowe"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacja jest przypięta"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, kliknij i przytrzymaj Wstecz oraz Przegląd."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, naciśnij i przytrzymaj Wstecz oraz Ekran główny."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ekran będzie widoczny, dopóki go nie odepniesz. Przesuń palcem w górę i przytrzymaj, by odpiąć."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, kliknij i przytrzymaj Przegląd."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, naciśnij i przytrzymaj Ekran główny."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Dane osobowe mogą być dostępne (np. kontakty czy treść e-maili)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Przypięta aplikacja może otwierać inne aplikacje."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Aby odpiąć tę aplikację, naciśnij i przytrzymaj przyciski Wstecz oraz Przegląd"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Aby odpiąć tę aplikację, naciśnij i przytrzymaj przyciski Wstecz oraz Ekran główny"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Aby odpiąć tę aplikację, przesuń w górę i przytrzymaj"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"OK"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Nie, dziękuję"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Aplikacja przypięta"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Aplikacja odpięta"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Ukryć <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Pojawi się ponownie, gdy następnym włączysz go w ustawieniach."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Ukryj"</string>
@@ -736,7 +725,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Wyświetla się jako pływający dymek u góry sekcji rozmów, pokazuje zdjęcie profilowe na ekranie blokady"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ustawienia"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorytet"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> nie obsługuje ustawień rozmowy"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Brak ostatnich dymków"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Tutaj będą pojawiać się ostatnie i odrzucone dymki"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Tych powiadomień nie można zmodyfikować."</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index ef3770c4be73..00a33d26e173 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom p/ preencher a tela"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Ampliar p/ preencher tela"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Capturar tela"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desbloqueie seu smartphone para ver mais opções"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desbloqueie seu tablet para ver mais opções"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desbloqueie seu dispositivo para ver mais opções"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou uma imagem"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Salvando captura de tela..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Salvando captura de tela..."</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Aparece na parte superior de uma seção de conversa, em forma de balão, mostrando a foto do perfil na tela de bloqueio"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configurações"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com configurações específicas de conversa"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nenhum balão recente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Os balões recentes e dispensados aparecerão aqui"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar essas notificações."</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index e343c2f0bfcc..fadd23478789 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom para preencher o ecrã"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Esticar p. caber em ec. int."</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Captura de ecrã"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desbloqueie o telemóvel para obter mais opções."</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desbloqueie o tablet para obter mais opções."</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desbloqueie o dispositivo para obter mais opções."</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou uma imagem"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"A guardar captura de ecrã..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"A guardar captura de ecrã..."</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Aparece na parte superior da secção de conversas, surge como um balão flutuante e apresenta a imagem do perfil no ecrã de bloqueio."</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Definições"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> não suporta definições específicas de conversas."</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nenhum balão recente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Os balões recentes e ignorados vão aparecer aqui."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar estas notificações."</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index ef3770c4be73..00a33d26e173 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom p/ preencher a tela"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Ampliar p/ preencher tela"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Capturar tela"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desbloqueie seu smartphone para ver mais opções"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desbloqueie seu tablet para ver mais opções"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desbloqueie seu dispositivo para ver mais opções"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou uma imagem"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Salvando captura de tela..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Salvando captura de tela..."</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Aparece na parte superior de uma seção de conversa, em forma de balão, mostrando a foto do perfil na tela de bloqueio"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configurações"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com configurações específicas de conversa"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nenhum balão recente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Os balões recentes e dispensados aparecerão aqui"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Não é possível modificar essas notificações."</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index ef37cfe52002..0ee2593cbc5b 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoom pt. a umple ecranul"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Înt. pt. a umple ecranul"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Captură de ecran"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Deblocați telefonul pentru mai multe opțiuni"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Deblocați tableta pentru mai multe opțiuni"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Deblocați dispozitivul pentru mai multe opțiuni"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a trimis o imagine"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Se salv. captura de ecran..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Se salvează captura de ecran..."</string>
@@ -598,29 +595,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"activați"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"dezactivați"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Comutați dispozitivul de ieșire"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Aplicația este fixată"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunile Înapoi și Recente pentru a anula fixarea."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunile Înapoi și Acasă pentru a anula fixarea."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Astfel rămâne afișat până anulați fixarea. Glisați în sus și țineți apăsat pentru a anula fixarea."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunea Recente pentru a anula fixarea."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunea Acasă pentru a anula fixarea."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Pot fi accesate date cu caracter personal (cum ar fi agenda și conținutul e-mailurilor)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Aplicațiile fixate pot deschide alte aplicații."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Pentru a anula fixarea acestei aplicații, atingeți lung butoanele Înapoi și Recente"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Pentru a anula fixarea acestei aplicații, atingeți lung butoanele Înapoi și Acasă"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Pentru a anula fixarea acestei aplicații, glisați în sus și mențineți"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Am înțeles"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Nu, mulțumesc"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Aplicație fixată"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Aplicație nefixată"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Ascundeți <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Va reapărea la următoarea activare în setări."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Ascundeți"</string>
@@ -733,7 +722,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Se afișează în partea de sus a secțiunii de conversație, apare ca un balon flotant, afișează fotografia de profil pe ecranul de blocare"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Setări"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritate"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu acceptă setările pentru conversații"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nu există baloane recente"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Baloanele recente și baloanele respinse vor apărea aici"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Aceste notificări nu pot fi modificate."</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 6adc37939b8a..b7cb75a092c1 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Подогнать по размерам экрана"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Растянуть на весь экран"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Скриншот"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Чтобы посмотреть дополнительные параметры, разблокируйте телефон."</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Чтобы посмотреть дополнительные параметры, разблокируйте планшет."</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Чтобы посмотреть дополнительные параметры, разблокируйте устройство."</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"отправлено изображение"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Сохранение..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Сохранение..."</string>
@@ -728,7 +725,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Появляется в верхней части списка разговоров и как всплывающий чат, а также показывает фото профиля на заблокированном экране"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Настройки"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" не поддерживает настройки разговора."</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Нет недавних всплывающих чатов"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Здесь будут появляться недавние и закрытые всплывающие чаты."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Эти уведомления нельзя изменить."</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 2ace6ed664eb..3843754c2d7d 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"තිරය පිරවීමට විශාලනය කරන්න"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"තිරය පිරවීමට අදින්න"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"තිර රුව"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"තව විකල්ප සඳහා ඔබේ දුරකථනය අගුලු හරින්න"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"තව විකල්ප සඳහා ඔබේ ටැබ්ලට් පරිගණකය අගුලු හරින්න"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"තව විකල්ප සඳහා ඔබේ උපාංගය අගුලු හරින්න"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"රූපයක් එවන ලදී"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"තිර රුව සුරකිමින්…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"තිර රුව සුරැකෙමින් පවතී…"</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"සංවාද කොටසේ ඉහළම පෙන්වයි, බුබුළක් ලෙස දිස් වේ, අගුලු තිරයේ පැතිකඩ පින්තූරය සංදර්ශනය වේ"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"සැකසීම්"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ප්‍රමුඛතාව"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> සංවාදය නිශ්චිත සැකසීම්වලට සහාය නොදක්වයි"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"මෑත බුබුලු නැත"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"මෑත බුබුලු සහ ඉවත ලූ බුබුලු මෙහි දිස් වනු ඇත"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"මෙම දැනුම්දීම් වෙනස් කළ නොහැක."</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index c5b615a04b40..20dd9006b3ee 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Priblížiť na celú obrazovku"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Na celú obrazovku"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Snímka obrazovky"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Odomknite svoj telefón pre ďalšie možnosti"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Odomknite svoj tablet pre ďalšie možnosti"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Odomknite svoje zariadenie pre ďalšie možnosti"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"odoslal(a) obrázok"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Prebieha ukladanie snímky obrazovky..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Prebieha ukladanie snímky obrazovky..."</string>
@@ -728,7 +725,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Nájdete ju v hornej sekcii konverzácie ako plávajúcu bublinu a zobrazuje profilovú fotku na uzamknutej obrazovke"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nastavenia"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priorita"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> nepodporuje nastavenia konkrétnych konverzácií"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Žiadne nedávne bubliny"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Tu sa budú zobrazovať nedávne a zavreté bubliny"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Tieto upozornenia sa nedajú upraviť."</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index a3995ac4db24..42f1151d6a2c 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Povečava čez cel zaslon"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Raztegnitev čez zaslon"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Posnetek zaslona"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Za več možnosti odklenite telefon"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Za več možnosti odklenite tablični računalnik"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Za več možnosti odklenite napravo"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"je poslal(-a) sliko"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Shranjev. posnetka zaslona ..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Shranjevanje posnetka zaslona ..."</string>
@@ -601,29 +598,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"omogoči"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"onemogoči"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Izbira druge izhodne naprave"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Aplikacija je pripeta"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"S tem ostane zaslon viden, dokler ga ne odpnete. Če ga želite odpeti, hkrati pridržite gumba za nazaj in pregled."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"S tem ostane zaslon viden, dokler ga ne odpnete. Če ga želite odpeti, hkrati pridržite gumba za nazaj in za začetni zaslon."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"S tem ostane zaslon viden, dokler ga ne odpnete. Če ga želite odpeti, povlecite navzgor in pridržite."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"S tem ostane zaslon viden, dokler ga ne odpnete. Če ga želite odpeti, pridržite gumb za pregled."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"S tem ostane zaslon viden, dokler ga ne odpnete. Če ga želite odpeti, pridržite gumb za začetni zaslon."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Dostopni so lahko osebni podatki (na primer stiki in vsebina e-poštnih sporočil)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Pripeta aplikacija lahko odpre druge aplikacije."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Če želite odpeti to aplikacijo, hkrati pridržite gumba za nazaj in za pregled."</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Če želite odpeti to aplikacijo, hkrati pridržite gumba za nazaj in za začetni zaslon."</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Če želite odpeti to aplikacijo, povlecite navzgor in pridržite."</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Razumem"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Ne, hvala"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Aplikacija je pripeta"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Aplikacija je odpeta"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Želite skriti <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Znova se bo pojavila, ko jo naslednjič vklopite v nastavitvah."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Skrij"</string>
@@ -736,7 +725,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Prikaz na vrhu razdelka s pogovorom in v plavajočem oblačku, prikaz profilne slike na zaklenjenem zaslonu"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nastavitve"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prednost"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podpira posebnih nastavitev za pogovore"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Ni nedavnih oblačkov"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Tukaj bodo prikazani tako nedavni kot tudi opuščeni oblački"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Za ta obvestila ni mogoče spremeniti nastavitev."</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 87c39d6f1447..b2d23c12fa65 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zmadho për të mbushur ekranin"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Shtrije për të mbushur ekranin"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Pamja e ekranit"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Shkyçe telefonin për më shumë opsione"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Shkyçe tabletin për më shumë opsione"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Shkyçe pajisjen për më shumë opsione"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"dërgoi një imazh"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Po ruan pamjen e ekranit..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Po ruan pamjen e ekranit…"</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Shfaqet në krye të seksionit të bisedës dhe shfaqet si flluskë pluskuese, shfaq fotografinë e profilit në ekranin e kyçjes"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Cilësimet"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Përparësia"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk i mbështet cilësimet specifike të bisedës"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nuk ka flluska të fundit"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Flluskat e fundit dhe flluskat e hequra do të shfaqen këtu"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Këto njoftime nuk mund të modifikohen."</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index ad4161017c17..070ca211b04a 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Зумирај на целом екрану"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Развуци на цео екран"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Снимак екрана"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Откључајте телефон за још опција"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Откључајте таблет за још опција"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Откључајте уређај за још опција"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"је послао/ла слику"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Чување снимка екрана..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Чување снимка екрана..."</string>
@@ -725,7 +722,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Приказује се у врху одељка за конверзације као плутајући облачић, приказује слику профила на закључаном екрану"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Подешавања"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> не подржава подешавања за конверзације"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Нема недавних облачића"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Овде се приказују недавни и одбачени облачићи"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ова обавештења не могу да се мењају."</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 35fff9fd3f89..9eb2ead0725f 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zooma för att fylla skärm"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Dra för att fylla skärmen"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Skärmdump"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Lås upp telefonen för fler alternativ"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Lås upp surfplattan för fler alternativ"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Lås upp enheten för fler alternativ"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"har skickat en bild"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Skärmdumpen sparas ..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Skärmdumpen sparas ..."</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Visas högst upp bland konversationerna som en flytande bubbla, visar profilbilden på låsskärmen"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Inställningar"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> har inte stöd för konversationsspecifika inställningar"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Inga nya bubblor"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"De senaste bubblorna och ignorerade bubblor visas här"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Det går inte att ändra de här aviseringarna."</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 47e208358168..8ebf50771dcf 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Kuza ili kujaza skrini"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Tanua ili kujaza skrini"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Picha ya skrini"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Fungua simu yako ili upate chaguo zaidi"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Fungua kompyuta yako kibao ili upate chaguo zaidi"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Fungua kifaa chako ili upate chaguo zaidi"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"imetuma picha"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Inahifadhi picha ya skrini..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Inahifadhi picha ya skrini..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"washa"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"zima"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Badilisha kifaa cha kutoa sauti"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Programu imebandikwa"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Hali hii huifanya ionekane hadi utakapoibandua. Gusa na ushikilie kipengele cha Nyuma na Muhtasari ili ubandue."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Hali hii huifanya ionekane hadi utakapoibandua. Gusa na ushikilie kitufe cha kurudisha Nyuma na cha Mwanzo kwa pamoja ili ubandue."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Hali hii huifanya ionekane hadi utakapoibandua. Telezesha kidole juu na ushikilie ili uibandue."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Hali hii huifanya ionekane hadi utakapoibandua. Gusa na ushikilie kipengele cha Muhtasari ili ubandue."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Hali hii huifanya ionekane hadi utakapoibandua. Gusa na ushikilie kitufe cha Mwanzo ili ubandue."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Data binafsi inaweza kufikiwa (kama vile maudhui ya barua pepe na anwani)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Programu iliyobandikwa inaweza kufungua programu zingine."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Ili ubandue programu hii, gusa na ushikilie kitufe cha Nyuma na Muhtasari"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Ili ubandue programu hii, gusa na ushikilie kitufe cha Nyuma na Ukurasa wa Mwanzo"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Ili ubandue programu hii, telezesha kidole juu na ushikilie"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Nimeelewa"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Hapana"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Programu imebandikwa"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Programu imebanduliwa"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Ungependa kuficha <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Itaonekana tena wakati mwingine utakapoiwasha katika mipangilio."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Ficha"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Huonyeshwa kwenye sehemu ya juu ya mazungumzo, huonekana kama kiputo, huonyesha picha ya wasifu kwenye skrini iliyofungwa"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Mipangilio"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Kipaumbele"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> haitumii mipangilio mahususi ya mazungumzo"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Hakuna viputo vya hivi majuzi"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Viputo vya hivi karibuni na vile vilivyoondolewa vitaonekana hapa"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Arifa hizi haziwezi kubadilishwa."</string>
diff --git a/packages/SystemUI/res/values-sw320dp/dimens.xml b/packages/SystemUI/res/values-sw320dp/dimens.xml
deleted file mode 100644
index c110113e91f4..000000000000
--- a/packages/SystemUI/res/values-sw320dp/dimens.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?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
- -->
-<resources>
- <!-- Global actions grid -->
- <dimen name="global_actions_grid_vertical_padding">3dp</dimen>
- <dimen name="global_actions_grid_horizontal_padding">3dp</dimen>
-
- <dimen name="global_actions_grid_item_side_margin">5dp</dimen>
- <dimen name="global_actions_grid_item_vertical_margin">4dp</dimen>
- <dimen name="global_actions_grid_item_width">64dp</dimen>
- <dimen name="global_actions_grid_item_height">64dp</dimen>
-
- <dimen name="global_actions_grid_item_icon_width">20dp</dimen>
- <dimen name="global_actions_grid_item_icon_height">20dp</dimen>
- <dimen name="global_actions_grid_item_icon_top_margin">12dp</dimen>
- <dimen name="global_actions_grid_item_icon_side_margin">22dp</dimen>
- <dimen name="global_actions_grid_item_icon_bottom_margin">4dp</dimen>
-
- <!-- Home Controls -->
- <dimen name="global_actions_side_margin">10dp</dimen>
-</resources>
-
diff --git a/packages/SystemUI/res/values-sw372dp/dimens.xml b/packages/SystemUI/res/values-sw372dp/dimens.xml
index e64662ec7bea..d3fff0c059f9 100644
--- a/packages/SystemUI/res/values-sw372dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw372dp/dimens.xml
@@ -17,5 +17,4 @@
-->
<resources>
<dimen name="nav_content_padding">8dp</dimen>
- <dimen name="qs_header_tile_margin_horizontal">13dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 32c6792d7354..8824b9b346cc 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"திரையை நிரப்ப அளவை மாற்று"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"திரையை நிரப்ப இழு"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ஸ்கிரீன்ஷாட்"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"மேலும் விருப்பங்களுக்கு மொபைலை அன்லாக் செய்யவும்"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"மேலும் விருப்பங்களுக்கு டேப்லெட்டை அன்லாக் செய்யவும்"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"மேலும் விருப்பங்களுக்குச் சாதனத்தை அன்லாக் செய்யவும்"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"படம் அனுப்பப்பட்டது"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"ஸ்க்ரீன் ஷாட்டைச் சேமிக்கிறது…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ஸ்க்ரீன் ஷாட்டைச் சேமிக்கிறது…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"இயக்கும்"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"முடக்கும்"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"வெளியீட்டுச் சாதனத்தை மாற்றுதல்"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"ஆப்ஸ் பின் செய்யப்பட்டது"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"பொருத்தியதை அகற்றும் வரை இதைக் காட்சியில் வைக்கும். அகற்ற, முந்தையது மற்றும் மேலோட்டப் பார்வையைத் தொட்டுப் பிடிக்கவும்."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"இதற்கான பின்னை அகற்றும் வரை, இந்தப் பயன்முறை செயல்பாட்டிலேயே இருக்கும். அகற்றுவதற்கு, முந்தையது மற்றும் முகப்புப் பொத்தான்களைத் தொட்டுப் பிடிக்கவும்."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"பின் செய்திருப்பதை அகற்றும் வரை இதைச் செயல்பாட்டில் வைத்திருக்கும். அதை அகற்றுவதற்கு மேல்நோக்கி ஸ்வைப் செய்து பிடித்திருக்கவும்."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"பொருத்தியதை அகற்றும் வரை இதைக் காட்சியில் வைக்கும். அகற்ற, மேலோட்டப் பார்வையைத் தொட்டுப் பிடிக்கவும்."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"இதற்கான பின்னை அகற்றும் வரை, இந்தப் பயன்முறை செயல்பாட்டிலேயே இருக்கும். அகற்றுவதற்கு, முகப்புப் பொத்தானைத் தொட்டுப் பிடிக்கவும்."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"(தொடர்புகள், மின்னஞ்சலின் உள்ளடக்கம் போன்ற) தனிப்பட்ட தரவு அணுகப்படக்கூடும்."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"பின் செய்யப்பட்டிருக்கும் ஆப்ஸ் பிற ஆப்ஸைத் திறக்கக்கூடும்."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"இந்த ஆப்ஸை அகற்ற, பின்செல் மற்றும் மேலோட்டப் பார்வை பட்டன்களைத் தொட்டுப் பிடித்திருக்கவும்"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"இந்த ஆப்ஸை அகற்ற, பின்செல் மற்றும் முகப்பு பட்டன்களைத் தொட்டுப் பிடித்திருக்கவும்"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"இந்த ஆப்ஸை அகற்ற, மேல்நோக்கி ஸ்வைப் செய்தவாறு பிடித்திருக்கவும்"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"புரிந்தது"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"வேண்டாம்"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"ஆப்ஸ் பின் செய்யப்பட்டது"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"ஆப்ஸ் அகற்றப்பட்டது"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>ஐ மறைக்கவா?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"அடுத்த முறை அமைப்புகளில் மீண்டும் இயக்கும்போது, இது மீண்டும் தோன்றும்."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"மறை"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"உரையாடல் பிரிவின் மேற்பகுதியில் மிதக்கும் குமிழாகத் தோன்றும். பூட்டுத் திரையின் மேல் சுயவிவரப் படத்தைக் காட்டும்"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"அமைப்புகள்"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"முன்னுரிமை"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"உரையாடல் சார்ந்த குறிப்பிட்ட அமைப்புகளை <xliff:g id="APP_NAME">%1$s</xliff:g> ஆதரிக்காது"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"சமீபத்திய குமிழ்கள் இல்லை"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"சமீபத்திய குமிழ்களும் நிராகரிக்கப்பட்ட குமிழ்களும் இங்கே தோன்றும்"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"இந்த அறிவிப்புகளை மாற்ற இயலாது."</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 75f308affe0a..bc9519402db5 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"స్క్రీన్‌కు నింపేలా జూమ్ చేయండి"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"స్క్రీన్‌కు నింపేలా విస్తరించండి"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"స్క్రీన్‌షాట్"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"మరిన్ని ఆప్షన్‌ల కోసం మీ ఫోన్‌ను అన్‌లాక్ చేయండి"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"మరిన్ని ఆప్షన్‌ల కోసం మీ టాబ్లెట్‌ను అన్‌లాక్ చేయండి"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"మరిన్ని ఆప్షన్‌ల కోసం మీ పరికరాన్ని అన్‌లాక్ చేయండి"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ఇమేజ్‌ను పంపారు"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"స్క్రీన్‌షాట్‌ను సేవ్ చేస్తోంది…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"స్క్రీన్‌షాట్‌ను సేవ్ చేస్తోంది…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"ప్రారంభించు"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"నిలిపివేయండి"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"పరికరం అవుట్‌పుట్‌ని మార్చండి"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"యాప్ పిన్ చేయబడి ఉంది"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"దీని వలన మీరు అన్‌పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్‌పిన్ చేయడానికి వెనుకకు మరియు స్థూలదృష్టి తాకి &amp; అలాగే పట్టుకోండి."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"దీని వలన మీరు అన్‌పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్‌పిన్ చేయడానికి వెనుకకు మరియు హోమ్‌ని తాకి &amp; అలాగే పట్టుకోండి."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"మీరు అన్‌పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్‌పిన్ చేయడానికి, పైకి స్వైప్ చేసి &amp; పట్టుకోండి."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"దీని వలన మీరు అన్‌పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్‌పిన్ చేయడానికి స్థూలదృష్టిని తాకి &amp; అలాగే పట్టుకోండి."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"దీని వలన మీరు అన్‌పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్‌పిన్ చేయడానికి హోమ్‌ని తాకి &amp; అలాగే పట్టుకోండి."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"వ్యక్తిగత డేటా (కాంటాక్ట్‌లు, ఇంకా ఇమెయిల్ కంటెంట్ లాంటివి) యాక్సెస్ చేయబడవచ్చు."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"పిన్ చేయబడిన యాప్ ఇతర యాప్‌లను తెరవవచ్చు."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"ఈ యాప్‌ను అన్‌పిన్ చేయడానికి, \'వెనుకకు\', \'ఓవర్‌వ్యూ\' బటన్‌లను తాకి &amp; అలాగే పట్టుకోండి"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"ఈ యాప్‌ను అన్‌పిన్ చేయడానికి, వెనుకకు, హోమ్ బటన్‌లను తాకి &amp; అలాగే పట్టుకోండి"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"ఈ యాప్‌ను అన్‌పిన్ చేయడానికి, పైకి స్వైప్ చేసి &amp; అలాగే పట్టుకోండి"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"అర్థమైంది"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"వద్దు, ధన్యవాదాలు"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"యాప్ పిన్ చేయబడింది"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"యాప్ అన్‌పిన్ చేయబడింది"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>ని దాచాలా?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"మీరు సెట్టింగ్‌ల్లో దీన్ని ఆన్ చేసిన తదుపరిసారి ఇది కనిపిస్తుంది."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"దాచు"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"సంభాషణ విభాగం ఎగువన ఉంటుంది, తేలుతున్న బబుల్‌లాగా కనిపిస్తుంది, లాక్ స్క్రీన్‌పై ప్రొఫైల్ ఫోటోను ప్రదర్శిస్తుంది"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"సెట్టింగ్‌లు"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ప్రాధాన్యత"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"\'సంభాషణ నిర్దిష్ట సెట్టింగ్\'‌లకు <xliff:g id="APP_NAME">%1$s</xliff:g> సపోర్ట్ చేయదు"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ఇటీవలి బబుల్స్ ఏవీ లేవు"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"ఇటీవలి బబుల్స్, తీసివేసిన బబుల్స్ ఇక్కడ కనిపిస్తాయి"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ఈ నోటిఫికేషన్‌లను సవరించడం వీలుపడదు."</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 37ac4dcd54ed..ae40e83d3985 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"ขยายจนเต็มหน้าจอ"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"ยืดจนเต็มหน้าจอ"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ภาพหน้าจอ"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ปลดล็อกโทรศัพท์เพื่อดูตัวเลือกเพิ่มเติม"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ปลดล็อกแท็บเล็ตเพื่อดูตัวเลือกเพิ่มเติม"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ปลดล็อกอุปกรณ์เพื่อดูตัวเลือกเพิ่มเติม"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ส่งรูปภาพ"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"กำลังบันทึกภาพหน้าจอ..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"กำลังบันทึกภาพหน้าจอ..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"เปิดใช้"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"ปิดใช้"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"เปลี่ยนอุปกรณ์เอาต์พุต"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"ตรึงแอปอยู่"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกตรึง แตะ \"กลับ\" และ \"ภาพรวม\" ค้างไว้เพื่อเลิกตรึง"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกตรึง แตะ \"กลับ\" และ \"หน้าแรก\" ค้างไว้เพื่อเลิกตรึง"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"วิธีนี้ช่วยให้เห็นหน้าจอตลอดจนกว่าจะเลิกตรึง เลื่อนขึ้นค้างไว้เพื่อเลิกตรึง"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกตรึง แตะ \"ภาพรวม\" ค้างไว้เพื่อเลิกตรึง"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"การดำเนินการนี้จะแสดงหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกตรึง แตะ \"หน้าแรก\" ค้างไว้เพื่อเลิกตรึง"</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"อาจมีการเข้าถึงข้อมูลส่วนตัว (เช่น รายชื่อติดต่อและเนื้อหาในอีเมล)"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"แอปที่ตรึงไว้อาจเปิดแอปอื่นๆ"</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"หากต้องการเลิกตรึงแอปนี้ ให้แตะปุ่ม \"กลับ\" และ \"ภาพรวม\" ค้างไว้"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"หากต้องการเลิกตรึงแอปนี้ ให้แตะปุ่ม \"กลับ\" และ \"หน้าแรก\" ค้างไว้"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"หากต้องการเลิกตรึงแอปนี้ ให้เลื่อนขึ้นค้างไว้"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"รับทราบ"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"ไม่เป็นไร ขอบคุณ"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"ตรึงแอปแล้ว"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"เลิกตรึงแอปแล้ว"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"ซ่อน <xliff:g id="TILE_LABEL">%1$s</xliff:g> ไหม"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"จะปรากฏอีกครั้งเมื่อคุณเปิดใช้ในการตั้งค่าครั้งถัดไป"</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"ซ่อน"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"แสดงที่ด้านบนของส่วนการสนทนา ปรากฏเป็นบับเบิลแบบลอย แสดงรูปโปรไฟล์บนหน้าจอล็อก"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"การตั้งค่า"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ลำดับความสำคัญ"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ไม่รองรับการตั้งค่าเฉพาะสำหรับการสนทนา"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"ไม่มีบับเบิลเมื่อเร็วๆ นี้"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"บับเบิลที่แสดงและที่ปิดไปเมื่อเร็วๆ นี้จะปรากฏที่นี่"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"แก้ไขการแจ้งเตือนเหล่านี้ไม่ได้"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 09199dda93ae..b7ff2b6d12ca 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"I-zoom upang punan screen"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"I-stretch upang mapuno screen"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"I-unlock ang iyong telepono para sa higit pang opsyon"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"I-unlock ang iyong tablet para sa higit pang opsyon"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"I-unlock ang iyong device para sa higit pang opsyon"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"nagpadala ng larawan"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Sine-save ang screenshot…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Sine-save ang screenshot…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"i-enable"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"i-disable"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Lumipat ng output device"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Naka-pin ang app"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Pinapanatili nitong nakikita ito hanggang sa mag-unpin ka. Pindutin nang matagal ang Bumalik at Overview upang mag-unpin."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Pinapanatili nitong nakikita ito hanggang sa mag-unpin ka. Pindutin nang matagal ang Bumalik at Home upang mag-unpin."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Pinapanatili nitong nakikita ito hanggang sa mag-unpin ka. Mag-swipe pataas at i-hold para i-unpin."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Pinapanatili nitong nakikita ito hanggang sa mag-unpin ka. Pindutin nang matagal ang Overview upang mag-unpin."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Pinapanatili nitong nakikita ito hanggang sa mag-unpin ka. Pindutin nang matagal ang Home upang mag-unpin."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Puwedeng ma-access ang personal na data (tulad ng mga contact at content ng email)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Puwedeng magbukas ng ibang app ang naka-pin na app."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Para i-unpin ang app na ito, pindutin nang matagal ang mga button na Bumalik at Overview"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Para i-unpin ang app na ito, pindutin nang matagal ang mga button na Bumalik at Home"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Para i-unpin ang app na ito, mag-swipe pataas at pumindot nang matagal"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Nakuha ko"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Hindi, salamat na lang"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Na-pin ang app"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Na-unpin ang app"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Itago ang <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Lalabas itong muli sa susunod na pagkakataon na i-on mo ito sa mga setting."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Itago"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Makikita sa itaas ng seksyon ng pag-uusap, lumalabas bilang floating bubble, ipinapakita sa lock screen ang larawan sa profile"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Mga Setting"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Priyoridad"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"Hindi sinusuportahan ng <xliff:g id="APP_NAME">%1$s</xliff:g> ang mga setting na partikular sa pag-uusap"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Walang kamakailang bubble"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Lalabas dito ang mga kamakailang bubble at na-dismiss na bubble"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Hindi puwedeng baguhin ang mga notification na ito."</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 63f336b61a1b..4cf3bcf62d8a 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Yakınlaştır (ekranı kaplasın)"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Genişlet (ekran kapansın)"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Ekran görüntüsü"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Diğer seçenekler için telefonunuzun kilidini açın"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Diğer seçenekler için tabletinizin kilidini açın"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Diğer seçenekler için cihazınızın kilidini açın"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"bir resim gönderildi"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Ekran görüntüsü kaydediliyor..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Ekran görüntüsü kaydediliyor..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"etkinleştir"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"devre dışı bırak"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Çıkış cihazını değiştir"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Uygulama sabitlenmiştir"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Bu işlem, siz sabitlemeyi kaldırana kadar ekranı görünür durumda tutar. Sabitlemeyi kaldırmak için Geri\'ye ve Genel Bakış\'a dokunup basılı tutun."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Bu işlem, siz sabitlemeyi kaldırana kadar ekranı görünür durumda tutar. Sabitlemeyi kaldırmak için Geri\'ye ve Ana sayfaya dokunup basılı tutun."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Bu, sabitleme kaldırılana kadar öğenin görünmesini sağlar. Sabitlemeyi kaldırmak için yukarı kaydırıp basılı tutun."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Bu işlem, siz sabitlemeyi kaldırana kadar ekranı görünür durumda tutar. Sabitlemeyi kaldırmak için Genel bakış\'a dokunup basılı tutun."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Bu işlem, siz sabitlemeyi kaldırana kadar ekranı görünür durumda tutar. Sabitlemeyi kaldırmak için Ana sayfaya dokunup basılı tutun."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Kişisel verilere erişilebilir (ör. kişiler ve e-posta içerikleri)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Sabitlenmiş uygulama diğer uygulamaları açabilir."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Bu uygulamanın sabitlemesini kaldırmak için Geri ve Genel Bakış düğmelerine dokunup basılı tutun"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Bu ekranın sabitlemesini kaldırmak için Geri ve Ana sayfa düğmelerine dokunup basılı tutun"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Bu ekranın sabitlemesini kaldırmak için hızlıca yukarı kaydırıp tutun"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Anladım"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Hayır, teşekkürler"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Uygulama sabitlendi"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Uygulamanın sabitlemesi kaldırıldı"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> gizlensin mi?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Ayarlardan etkinleştirdiğiniz bir sonraki sefer tekrar görünür."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Gizle"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Görüşme bölümünün üstünde gösterilir, kayan baloncuk olarak görünür, kilit ekranında profil resmini görüntüler"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ayarlar"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Öncelik"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g>, görüşmeye özgü ayarları desteklemiyor"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Son kapatılan baloncuk yok"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Son baloncuklar ve kapattığınız baloncuklar burada görünür"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirimler değiştirilemez."</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 0aa3f7a259ab..49e35d2e27d4 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Масштабув. на весь екран"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Розтягнути на весь екран"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Знімок екрана"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Розблокуйте телефон, щоб переглянути інші параметри"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Розблокуйте планшет, щоб переглянути інші параметри"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Розблокуйте пристрій, щоб переглянути інші параметри"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"надіслане зображення"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Збереження знімка екрана..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Збереження знімка екрана..."</string>
@@ -601,29 +598,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"увімкнути"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"вимкнути"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Увімкніть пристрій виведення"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Додаток закріплено"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ви постійно бачитимете екран, доки не відкріпите його. Щоб відкріпити екран, натисніть і втримуйте кнопки \"Назад\" та \"Огляд\"."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ви бачитимете цей екран, доки не відкріпите його. Для цього натисніть і утримуйте кнопки \"Назад\" та \"Головний екран\"."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Ви бачитимете цей екран, доки не відкріпите його. Для цього проведіть пальцем угору й утримуйте екран."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ви постійно бачитимете екран, доки не відкріпите його. Щоб відкріпити екран, натисніть і втримуйте кнопку \"Огляд\"."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ви бачитимете цей екран, доки не відкріпите його. Для цього натисніть і утримуйте кнопку \"Головний екран\"."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Закріплений додаток може отримувати доступ до персональних даних (наприклад, до контактів або електронних листів)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Закріплений додаток може відкривати інші додатки."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Щоб відкріпити цей додаток, натисніть і утримуйте кнопки \"Назад\" та \"Огляд\""</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Щоб відкріпити цей додаток, натисніть і утримуйте кнопки \"Назад\" та \"Головний екран\""</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Щоб відкріпити цей додаток, проведіть пальцем вгору й утримуйте його на екрані"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Зрозуміло"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Ні, дякую"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Додаток закріплено"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Додаток відкріплено"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Сховати <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"З’явиться знову, коли ви ввімкнете його в налаштуваннях."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Сховати"</string>
@@ -736,7 +725,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"З\'являється вгорі розділу розмов у спливаючому сповіщенні та показує зображення профілю на заблокованому екрані"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Налаштування"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Пріоритет"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> не підтримує налаштування для чату"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Немає нещодавніх спливаючих чатів"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Тут з\'являтимуться нещодавні й закриті спливаючі чати"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Ці сповіщення не можна змінити."</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 47eebc7e3fe2..fb91b52354be 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"پوری سکرین پر زوم کریں"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"پوری سکرین پر پھیلائیں"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"اسکرین شاٹ"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"مزید اختیارات کے لیے اپنا فون غیر مقفل کریں"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"مزید اختیارات کے لیے اپنا ٹیبلیٹ غیر مقفل کریں"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"مزید اختیارات کے لیے اپنا آلہ غیر مقفل کریں"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ایک تصویر بھیجی"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"اسکرین شاٹ محفوظ ہو رہا ہے…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"اسکرین شاٹ محفوظ ہو رہا ہے…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"فعال کریں"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"غیر فعال کریں"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"آؤٹ پٹ آلہ سوئچ کریں"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"ایپ کو پن کر دیا گیا ہے"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"یہ اسے اس وقت تک نظر میں رکھتا ہے جب تک آپ اس سے پن ہٹا نہیں دیتے۔ پن ہٹانے کیلئے پیچھے اور مجموعی جائزہ بٹنز کو ٹچ کریں اور دبائے رکھیں۔"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"یہ اس کو اس وقت تک مد نظر رکھتا ہے جب تک آپ اس سے پن نہیں ہٹا دیتے۔ پن ہٹانے کیلئے \"پیچھے\" اور \"ہوم\" بٹنز کو ٹچ کریں اور دبائے رکھیں۔"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"یہ اس کو اس وقت تک مد نظر رکھتا ہے جب تک آپ اس سے پن نہیں ہٹا دیتے۔ پن ہٹانے کے لیے سوائپ کریں اور پکڑ کر رکھیں۔"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"یہ اسے اس وقت تک نظر میں رکھتا ہے جب تک آپ اس سے پن ہٹا نہیں دیتے۔ پن ہٹانے کیلئے مجموعی جائزہ بٹن کو ٹچ کریں اور دبائے رکھیں۔"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"یہ اس کو اس وقت تک مد نظر رکھتا ہے جب تک آپ اس سے پن نہیں ہٹا دیتے۔ پن ہٹانے کیلئے \"ہوم\" بٹن کو ٹچ کریں اور دبائے رکھیں۔"</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"ذاتی ڈیٹا قابل رسائی ہو سکتا ہے (جیسے رابطے اور ای میل کا مواد)۔"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"پن کردہ ایپ دیگر ایپس کو کھول سکتی ہے۔"</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"اس ایپ سے پن ہٹانے کے لیے، \"واپس جائیں\" اور \"مجموعی جائزہ\" بٹنز کو ٹچ کریں اور دبائے رکھیں"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"اس ایپ سے پن ہٹانے کے لیے، \"واپس جائیں\" اور \"ہوم\" بٹنز کو ٹچ کریں اور دبائے رکھیں"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"اس ایپ سے پن ہٹانے کے لیے، اوپر کی طرف سوائپ کریں اور دبائے رکھیں"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"سمجھ آ گئی"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"نہیں شکریہ"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"ایپ کو پن کر دیا گیا"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"ایپ کا پن ہٹا دیا گیا"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> کو چھپائیں؟"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"اگلی بار جب آپ اسے ترتیبات میں آن کریں گے تو یہ ظاہر ہوگی۔"</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"چھپائیں"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"گفتگو کے سیکشن کے اوپری حصے پر دکھاتا ہے، تیرتے بلبلے کی طرح ظاہر ہوتا ہے، لاک اسکرین پر پروفائل تصویر دکھاتا ہے"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ترتیبات"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"ترجیح"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> گفتگو سے متعلق مخصوص ترتیبات کو سپورٹ نہیں کرتی"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"کوئی حالیہ بلبلہ نہیں"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"حالیہ بلبلے اور برخاست شدہ بلبلے یہاں ظاہر ہوں گے"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"ان اطلاعات کی ترمیم نہیں کی جا سکتی۔"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index be7c62632a4b..0aeb3271deb0 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -592,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"faollashtirish"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"faolsizlantirish"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Audiochiqish qurilmasini almashtirish"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Ilova mahkamlandi"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Ekran yechilmaguncha u o‘zgarmas holatda qoladi. Uni yechish uchun “Orqaga” va “Umumiy ma’lumot” tugmalarini bosib turing."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Ekran yechib olinmagunicha u mahkamlangan holatda qoladi. Uni yechish uchun Orqaga va Asosiy tugmalarni birga bosib turing."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Yechilmaguncha chiqib turadi. Yechish uchun tepaga suring va qoʻlingizni kerakli holatda tutib turing."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Ekran yechilmaguncha u o‘zgarmas holatda qoladi. Uni yechish uchun “Umumiy ma’lumot” tugmasini bosib turing."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Ekran yechib olinmagunicha u mahkamlangan holatda qoladi. Uni yechish uchun Orqaga va Asosiy tugmlarni birga bosib turing."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Shaxsiy maʼlumotlarga kira oladi (masalan, kontaktlar va email ichidagilarga)"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Mahkamlangan ilova boshqa ilovalarni ochishi mumkin."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Bu ilovadan chiqish uchun Orqaga va Menyu tugmalarini bosib turing"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Bu ilovani olib tashlash uchun Orqaga va Bosh ekran tugmalarini bosib turing"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Bu ilovani olib tashlash uchun tepaga surib, bosib turing"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"OK"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Yo‘q, kerakmas"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Ilova mahkamlandi"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Ilova olib tashlandi"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> berkitilsinmi?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Keyingi safar sozlamalardan yoqilgan paydo bo‘ladi."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Berkitish"</string>
@@ -727,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Suhbatlar ruknining tepasida qalqib chiquvchi bulutcha shaklida chiqadi, ekran qulfida profil rasmi chiqadi"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Sozlamalar"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Muhim"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasida suhbat sozlamalari ishlamaydi"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Avvalgi bulutchalar topilmadi"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Bu yerda oxirgi va yopilgan bulutcha shaklidagi bildirishnomalar chiqadi"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirishnomalarni tahrirlash imkonsiz."</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index bd483b8b1c5e..8000686a8fb1 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"T.phóng để lấp đầy m.hình"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Giãn ra để lấp đầy m.hình"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Chụp ảnh màn hình"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Mở khóa điện thoại của bạn để xem thêm tùy chọn"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Mở khóa máy tính bảng của bạn để xem thêm tùy chọn"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Mở khóa thiết bị của bạn để xem thêm tùy chọn"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"đã gửi hình ảnh"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Đang lưu ảnh chụp màn hình..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Đang lưu ảnh chụp màn hình..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"bật"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"tắt"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"Chuyển đổi thiết bị đầu ra"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"Đã ghim ứng dụng"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ Quay lại và Tổng quan để bỏ ghim."</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ nút Quay lại và nút Màn hình chính để bỏ ghim."</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"Màn hình tiếp tục hiển thị cho tới khi bạn bỏ ghim. Hãy vuốt lên và giữ để bỏ ghim."</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ Tổng quan để bỏ ghim."</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ nút Màn hình chính để bỏ ghim."</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"Bạn có thể truy cập được vào dữ liệu cá nhân (chẳng hạn như danh bạ và nội dung email)."</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"Ứng dụng đã ghim có thể mở ứng dụng khác."</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"Để bỏ ghim ứng dụng này, hãy chạm và giữ nút Quay lại và nút Tổng quan"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"Để bỏ ghim ứng dụng này, hãy chạm và giữ nút Quay lại và nút Màn hình chính"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"Để bỏ ghim ứng dụng này, hãy vuốt lên và giữ"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"Ok"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"Không, cảm ơn"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"Đã ghim ứng dụng"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"Đã bỏ ghim ứng dụng"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"Ẩn <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"Thông báo này sẽ xuất hiện lại vào lần tiếp theo bạn bật thông báo trong cài đặt."</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"Ẩn"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Hiển thị cuộc trò chuyện ở đầu phần cuộc trò chuyện và dưới dạng bong bóng nổi, hiển thị ảnh hồ sơ trên màn hình khóa"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Cài đặt"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Mức độ ưu tiên"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"Ứng dụng <xliff:g id="APP_NAME">%1$s</xliff:g> không hỗ trợ tùy chọn cài đặt dành riêng cho cuộc trò chuyện"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Không có bong bóng trò chuyện nào gần đây"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Bong bóng trò chuyện đã đóng và bong bóng trò chuyện gần đây sẽ xuất hiện ở đây"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Không thể sửa đổi các thông báo này."</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 970d21843616..1d5a73dd54c6 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"缩放以填满屏幕"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"拉伸以填满屏幕"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"屏幕截图"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"解锁手机即可查看更多选项"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"解锁平板电脑即可查看更多选项"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"解锁设备即可查看更多选项"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"发送了一张图片"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"正在保存屏幕截图..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"正在保存屏幕截图..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"启用"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"停用"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"切换输出设备"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"应用已固定"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"这将会固定显示此屏幕,直到您取消固定为止。触摸并按住“返回”和“概览”即可取消固定屏幕。"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"这将会固定显示此屏幕,直到您取消固定为止。触摸并按住“返回”和“主屏幕”即可取消固定屏幕。"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"这会使此屏幕固定显示,直到您取消固定为止。向上滑动并按住即可取消固定。"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"这将会固定显示此屏幕,直到您取消固定为止。触摸并按住“概览”即可取消固定屏幕。"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"这将会固定显示此屏幕,直到您取消固定为止。触摸并按住“主屏幕”即可取消固定屏幕。"</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"可访问个人数据(例如通讯录和电子邮件内容)。"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"固定的应用可打开其他应用。"</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"如需取消固定此应用,请轻触并按住“返回”按钮和“概览”按钮"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"如需取消固定此应用,请轻触并按住“返回”按钮和主屏幕按钮"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"如需取消固定此应用,请向上滑动并按住"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"知道了"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"不用了"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"已固定应用"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"已取消固定应用"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"要隐藏“<xliff:g id="TILE_LABEL">%1$s</xliff:g>”吗?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"下次在设置中将其开启后,此快捷设置条目将会重新显示。"</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"隐藏"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"以悬浮对话泡形式显示在对话部分顶部,如果设备处于锁定状态,在锁定屏幕上显示个人资料照片"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"设置"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"优先"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g>不支持对话专用设置"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"最近没有对话泡"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"此处会显示最近的对话泡和已关闭的对话泡"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"无法修改这些通知。"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 909336451d95..53479842563c 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"放大為全螢幕"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"放大為全螢幕"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"螢幕截圖"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"解鎖手機以存取更多選項"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"解鎖平板電腦以存取更多選項"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"解鎖裝置以存取更多選項"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"已傳送圖片"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"正在儲存螢幕擷取畫面..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"正在儲存螢幕擷取畫面..."</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"啟用"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"停用"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"切換輸出裝置"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"已固定應用程式"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"畫面將會繼續顯示,直至您取消固定。按住 [返回] 和 [概覽] 即可取消固定。"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"畫面將會繼續顯示,直至您取消固定為止。按住 [返回] 按鈕和主按鈕即可取消固定。"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"畫面將會繼續顯示,直至您取消固定為止。向上滑動並按住即可取消固定。"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"畫面將會繼續顯示,直至您取消固定。按住 [概覽] 即可取消固定。"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"畫面將會繼續顯示,直至您取消固定為止。按住主按鈕即可取消固定。"</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"該應用程式可存取個人資料 (例如聯絡人和電郵內容)。"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"固定的應用程式可開啟其他應用程式。"</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"如要取消固定此應用程式,請按住「返回」按鈕和「概覽」按鈕"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"如要取消固定此應用程式,請按住「返回」按鈕和主按鈕"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"如要取消固定此應用程式,請向上滑動並按住"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"知道了"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"不用了,謝謝"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"已固定應用程式"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"已取消固定應用程式"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"隱藏 <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"下一次您在設定開啟它時,它將再次出現。"</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"隱藏"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"在對話部分的頂部以浮動對話氣泡顯示,並在上鎖畫面顯示個人檔案相片"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"設定"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"重要"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話專用設定"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"沒有最近曾使用的小視窗"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"最近使用和關閉的小視窗會在這裡顯示"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"無法修改這些通知。"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index f93464c71c00..104aaa4d9b03 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"放大為全螢幕"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"放大為全螢幕"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"擷取螢幕畫面"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"解鎖手機可查看更多選項"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"解鎖平板電腦可查看更多選項"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"解鎖裝置可查看更多選項"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"傳送了一張圖片"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"正在儲存螢幕截圖…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"正在儲存螢幕截圖…"</string>
@@ -595,29 +592,21 @@
<string name="volume_odi_captions_hint_enable" msgid="2073091194012843195">"啟用"</string>
<string name="volume_odi_captions_hint_disable" msgid="2518846326748183407">"停用"</string>
<string name="accessibility_output_chooser" msgid="7807898688967194183">"切換輸出裝置"</string>
- <!-- no translation found for screen_pinning_title (9058007390337841305) -->
- <skip />
+ <string name="screen_pinning_title" msgid="9058007390337841305">"應用程式已固定"</string>
<string name="screen_pinning_description" msgid="8699395373875667743">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住 [返回] 按鈕和 [總覽] 按鈕即可取消固定。"</string>
<string name="screen_pinning_description_recents_invisible" msgid="4564466648700390037">"這會讓應用程式顯示在螢幕上,直到取消固定為止。按住 [返回] 按鈕和主螢幕按鈕即可取消固定。"</string>
<string name="screen_pinning_description_gestural" msgid="7246323931831232068">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。向上滑動並按住即可取消固定。"</string>
<string name="screen_pinning_description_accessible" msgid="7386449191953535332">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住 [總覽] 按鈕即可取消固定。"</string>
<string name="screen_pinning_description_recents_invisible_accessible" msgid="2857071808674481986">"這會讓應用程式顯示在螢幕上,直到取消固定為止。按住主螢幕按鈕即可取消固定。"</string>
- <!-- no translation found for screen_pinning_exposes_personal_data (8189852022981524789) -->
- <skip />
- <!-- no translation found for screen_pinning_can_open_other_apps (7529756813231421455) -->
- <skip />
- <!-- no translation found for screen_pinning_toast (8177286912533744328) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_recents_invisible (6850978077443052594) -->
- <skip />
- <!-- no translation found for screen_pinning_toast_gesture_nav (170699893395336705) -->
- <skip />
+ <string name="screen_pinning_exposes_personal_data" msgid="8189852022981524789">"該應用程式或許可存取個人資料 (例如聯絡人和電子郵件內容)。"</string>
+ <string name="screen_pinning_can_open_other_apps" msgid="7529756813231421455">"已設為固定的應用程式或許可以開啟其他應用程式。"</string>
+ <string name="screen_pinning_toast" msgid="8177286912533744328">"如要取消固定這個應用程式,請輕觸並按住「返回」按鈕和「總覽」按鈕"</string>
+ <string name="screen_pinning_toast_recents_invisible" msgid="6850978077443052594">"如要取消固定這個應用程式,請輕觸並按住「返回」按鈕和主畫面按鈕"</string>
+ <string name="screen_pinning_toast_gesture_nav" msgid="170699893395336705">"如要取消固定這個應用程式,請向上滑動並按住"</string>
<string name="screen_pinning_positive" msgid="3285785989665266984">"知道了"</string>
<string name="screen_pinning_negative" msgid="6882816864569211666">"不用了,謝謝"</string>
- <!-- no translation found for screen_pinning_start (7483998671383371313) -->
- <skip />
- <!-- no translation found for screen_pinning_exit (4553787518387346893) -->
- <skip />
+ <string name="screen_pinning_start" msgid="7483998671383371313">"已固定應用程式"</string>
+ <string name="screen_pinning_exit" msgid="4553787518387346893">"已取消固定應用程式"</string>
<string name="quick_settings_reset_confirmation_title" msgid="463533331480997595">"隱藏<xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
<string name="quick_settings_reset_confirmation_message" msgid="2320586180785674186">"只要在設定頁面中重新啟用,就能再次看到快捷設定選項。"</string>
<string name="quick_settings_reset_confirmation_button" msgid="3341477479055016776">"隱藏"</string>
@@ -730,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"以浮動對話框的形式顯示在對話部分的頂端。如果裝置處於鎖定狀態,則在螢幕鎖定畫面上顯示個人資料相片"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"設定"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"優先"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話專用設定"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"最近沒有任何對話框"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"最近的對話框和已關閉的對話框會顯示在這裡"</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"無法修改這些通知。"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index e8be37d0060d..292d6db3b7a2 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -77,9 +77,6 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Sondeza ukugcwalisa isikrini"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Nweba ukugcwalisa isikrini"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Isithombe-skrini"</string>
- <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Vula ifoni yakho ukuthola izinketho ezengeziwe"</string>
- <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Vula ithebulethi yakho ukuthola izinketho ezengeziwe"</string>
- <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Vula idivayisi yakho ukuthola izinketho ezengeziwe"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"uthumele isithombe"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Ilondoloz umfanekiso weskrini..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Ilondoloz umfanekiso weskrini..."</string>
@@ -722,7 +719,8 @@
<string name="notification_channel_summary_priority" msgid="7952654515769021553">"Iboniswa ngenhla kwesigaba sengxoxo, ivela njengebhamuza elintantayo, ibonisa isithombe sephrofayela kukukhiya isikrini"</string>
<string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Izilungiselelo"</string>
<string name="notification_priority_title" msgid="2079708866333537093">"Okubalulekile"</string>
- <string name="no_shortcut" msgid="7176375126961212514">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayisekeli amasethingi athile engxoxo"</string>
+ <!-- no translation found for no_shortcut (8257177117568230126) -->
+ <skip />
<string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Awekho amabhamuza akamuva"</string>
<string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Amabhamuza akamuva namabhamuza asusiwe azobonakala lapha."</string>
<string name="notification_unblockable_desc" msgid="2073030886006190804">"Lezi zaziso azikwazi ukushintshwa."</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a7d176443c55..73d8e9a0d8a7 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -224,6 +224,7 @@
<dimen name="notification_guts_conversation_icon_size">56dp</dimen>
<dimen name="notification_guts_conversation_action_height">56dp</dimen>
<dimen name="notification_guts_conversation_action_text_padding_start">32dp</dimen>
+ <dimen name="conversation_onboarding_bullet_gap_width">6dp</dimen>
<!-- The height of the header in inline settings -->
<dimen name="notification_guts_header_height">24dp</dimen>
@@ -482,7 +483,8 @@
<dimen name="pull_span_min">25dp</dimen>
<dimen name="qs_tile_height">106dp</dimen>
- <dimen name="qs_tile_layout_margin_side">6dp</dimen>
+ <!--notification_side_paddings + notification_content_margin_start - (qs_quick_tile_size - qs_tile_background_size) / 2 -->
+ <dimen name="qs_tile_layout_margin_side">18dp</dimen>
<dimen name="qs_tile_margin_horizontal">18dp</dimen>
<dimen name="qs_tile_margin_horizontal_two_line">2dp</dimen>
<dimen name="qs_tile_margin_vertical">24dp</dimen>
@@ -498,7 +500,6 @@
<dimen name="qs_quick_tile_size">48dp</dimen>
<dimen name="qs_quick_tile_padding">12dp</dimen>
<dimen name="qs_header_gear_translation">16dp</dimen>
- <dimen name="qs_header_tile_margin_horizontal">4dp</dimen>
<dimen name="qs_header_tile_margin_bottom">18dp</dimen>
<dimen name="qs_page_indicator_width">16dp</dimen>
<dimen name="qs_page_indicator_height">8dp</dimen>
@@ -973,7 +974,9 @@
<dimen name="recents_quick_scrub_onboarding_margin_start">8dp</dimen>
<!-- The height of the gradient indicating the dismiss edge when moving a PIP. -->
- <dimen name="floating_dismiss_gradient_height">176dp</dimen>
+ <dimen name="floating_dismiss_gradient_height">250dp</dimen>
+
+ <dimen name="floating_dismiss_bottom_margin">50dp</dimen>
<!-- The bottom margin of the PIP drag to dismiss info text shown when moving a PIP. -->
<dimen name="pip_dismiss_text_bottom_margin">24dp</dimen>
@@ -1031,8 +1034,23 @@
<dimen name="global_actions_grid_container_shadow_offset">20dp</dimen>
<dimen name="global_actions_grid_container_negative_shadow_offset">-20dp</dimen>
+ <!-- Global actions grid -->
+ <dimen name="global_actions_grid_vertical_padding">3dp</dimen>
+ <dimen name="global_actions_grid_horizontal_padding">3dp</dimen>
+
+ <dimen name="global_actions_grid_item_side_margin">5dp</dimen>
+ <dimen name="global_actions_grid_item_vertical_margin">4dp</dimen>
+ <dimen name="global_actions_grid_item_width">64dp</dimen>
+ <dimen name="global_actions_grid_item_height">64dp</dimen>
+
+ <dimen name="global_actions_grid_item_icon_width">20dp</dimen>
+ <dimen name="global_actions_grid_item_icon_height">20dp</dimen>
+ <dimen name="global_actions_grid_item_icon_top_margin">12dp</dimen>
+ <dimen name="global_actions_grid_item_icon_side_margin">22dp</dimen>
+ <dimen name="global_actions_grid_item_icon_bottom_margin">4dp</dimen>
+
<!-- Margins at the left and right of the power menu and home controls widgets. -->
- <dimen name="global_actions_side_margin">16dp</dimen>
+ <dimen name="global_actions_side_margin">10dp</dimen>
<!-- Amount to shift the layout when exiting/entering for controls activities -->
<dimen name="global_actions_controls_y_translation">20dp</dimen>
@@ -1057,9 +1075,8 @@
<dimen name="edge_margin">8dp</dimen>
<!-- The absolute side margins of quick settings -->
- <dimen name="quick_settings_side_margins">16dp</dimen>
<dimen name="quick_settings_expanded_bottom_margin">16dp</dimen>
- <dimen name="quick_settings_media_extra_bottom_margin">4dp</dimen>
+ <dimen name="quick_settings_media_extra_bottom_margin">6dp</dimen>
<dimen name="rounded_corner_content_padding">0dp</dimen>
<dimen name="nav_content_padding">0dp</dimen>
<dimen name="nav_quick_scrub_track_edge_padding">24dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 97a0d032c4a7..0314fc89d33a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2667,6 +2667,11 @@
<string name="inattentive_sleep_warning_title">Standby</string>
<!-- Priority conversation onboarding screen -->
+ <!-- title of priority onboarding [CHAR LIMIT=75] -->
+ <string name="priority_onboarding_title">Conversation set to priority</string>
+ <!-- Text explaining that the following actions are the behaviors of priority conversations.
+ E.g. priority conversations will show at the top of the conversation section [CHAR LIMIT=75] -->
+ <string name="priority_onboarding_behavior">Priority conversations will:</string>
<!-- Text explaining that priority conversations show at the top of the conversation section [CHAR LIMIT=75] -->
<string name="priority_onboarding_show_at_top_text">Show at top of conversation section</string>
<!-- Text explaining that priority conversations show an avatar on the lock screen [CHAR LIMIT=75] -->
@@ -2677,6 +2682,8 @@
<string name="priority_onboarding_ignores_dnd_text">Interrupt Do Not Disturb</string>
<!-- Title for the affirmative button [CHAR LIMIT=50] -->
<string name="priority_onboarding_done_button_title">Got it</string>
+ <!-- Title for the settings button button [CHAR LIMIT=50] -->
+ <string name="priority_onboarding_settings_button_title">Settings</string>
<!-- Window Magnification strings -->
<!-- Title for Magnification Overlay Window [CHAR LIMIT=NONE] -->
@@ -2774,6 +2781,8 @@
<!-- Close the controls associated with a specific media session [CHAR_LIMIT=NONE] -->
<string name="controls_media_close_session">Close this media session</string>
+ <!-- Label for button to resume media playback [CHAR_LIMIT=NONE] -->
+ <string name="controls_media_resume">Resume</string>
<!-- Error message indicating that a control timed out while waiting for an update [CHAR_LIMIT=30] -->
<string name="controls_error_timeout">Inactive, check app</string>
@@ -2781,7 +2790,13 @@
a retry will be attempted [CHAR LIMIT=30] -->
<string name="controls_error_retryable">Error, retrying\u2026</string>
<!-- Error message indicating that the control is no longer available in the application [CHAR LIMIT=30] -->
- <string name="controls_error_removed">Device removed</string>
+ <string name="controls_error_removed">Not found</string>
+ <!-- Title for dialog indicating that the control is no longer available in the application [CHAR LIMIT=30] -->
+ <string name="controls_error_removed_title">Control is unavailable</string>
+ <!-- Message body for dialog indicating that the control is no longer available in the application [CHAR LIMIT=NONE] -->
+ <string name="controls_error_removed_message">Couldn\u2019t access <xliff:g id="device" example="Backdoor lock">%1$s</xliff:g>. Check the <xliff:g id="application" example="Google Home">%2$s</xliff:g> app to make sure the control is still available and that the app settings haven\u2019t changed.</string>
+ <!-- Text for button to open the corresponding application [CHAR_LIMIT=20] -->
+ <string name="controls_open_app">Open app</string>
<!-- Error message indicating that an unspecified error occurred while getting the status [CHAR LIMIT=30] -->
<string name="controls_error_generic">Can\u2019t load status</string>
<!-- Error message indicating that a control action failed [CHAR_LIMIT=30] -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index ed36bdbe1e7e..39f78bf46028 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -387,6 +387,11 @@
<item name="android:homeAsUpIndicator">@drawable/ic_arrow_back</item>
</style>
+ <style name="qs_security_footer" parent="@style/qs_theme">
+ <item name="android:textColor">?android:attr/textColorSecondary</item>
+ <item name="android:tint">?android:attr/textColorSecondary</item>
+ </style>
+
<style name="systemui_theme_remote_input" parent="@android:style/Theme.DeviceDefault.Light">
<item name="android:colorAccent">@color/remote_input_accent</item>
</style>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 35ad422c56b8..655008b7745a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -23,10 +23,11 @@ import android.os.Bundle;
import android.view.MotionEvent;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
+import com.android.systemui.shared.recents.model.Task;
/**
* Temporary callbacks into SystemUI.
- * Next id = 26
+ * Next id = 27
*/
interface ISystemUiProxy {
@@ -122,6 +123,9 @@ interface ISystemUiProxy {
/**
* Handle the provided image as if it was a screenshot.
+ *
+ * Deprecated, use handleImageBundleAsScreenshot with image bundle and UserTask
+ * @deprecated
*/
void handleImageAsScreenshot(in Bitmap screenImage, in Rect locationInScreen,
in Insets visibleInsets, int taskId) = 21;
@@ -146,4 +150,10 @@ interface ISystemUiProxy {
* @param rotation indicates which Surface.Rotation the gesture was started in
*/
void onQuickSwitchToNewTask(int rotation) = 25;
+
+ /**
+ * Handle the provided image as if it was a screenshot.
+ */
+ void handleImageBundleAsScreenshot(in Bundle screenImageBundle, in Rect locationInScreen,
+ in Insets visibleInsets, in Task.TaskKey task) = 26;
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.aidl
new file mode 100644
index 000000000000..e7cad2acc645
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.recents.model;
+
+parcelable Task.TaskKey; \ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
index dcb134ec933e..186379af4b1d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java
@@ -26,6 +26,8 @@ import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.view.ViewDebug;
import com.android.systemui.shared.recents.utilities.Utilities;
@@ -52,8 +54,10 @@ public class Task {
void onTaskWindowingModeChanged();
}
- /* The Task Key represents the unique primary key for the task */
- public static class TaskKey {
+ /**
+ * The Task Key represents the unique primary key for the task
+ */
+ public static class TaskKey implements Parcelable {
@ViewDebug.ExportedProperty(category="recents")
public final int id;
@ViewDebug.ExportedProperty(category="recents")
@@ -157,6 +161,48 @@ public class Task {
private void updateHashCode() {
mHashCode = Objects.hash(id, windowingMode, userId);
}
+
+ public static final Parcelable.Creator<TaskKey> CREATOR =
+ new Parcelable.Creator<TaskKey>() {
+ @Override
+ public TaskKey createFromParcel(Parcel source) {
+ return TaskKey.readFromParcel(source);
+ }
+
+ @Override
+ public TaskKey[] newArray(int size) {
+ return new TaskKey[size];
+ }
+ };
+
+ @Override
+ public final void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeInt(id);
+ parcel.writeInt(windowingMode);
+ parcel.writeTypedObject(baseIntent, flags);
+ parcel.writeInt(userId);
+ parcel.writeLong(lastActiveTime);
+ parcel.writeInt(displayId);
+ parcel.writeTypedObject(sourceComponent, flags);
+ }
+
+ private static TaskKey readFromParcel(Parcel parcel) {
+ int id = parcel.readInt();
+ int windowingMode = parcel.readInt();
+ Intent baseIntent = parcel.readTypedObject(Intent.CREATOR);
+ int userId = parcel.readInt();
+ long lastActiveTime = parcel.readLong();
+ int displayId = parcel.readInt();
+ ComponentName sourceComponent = parcel.readTypedObject(ComponentName.CREATOR);
+
+ return new TaskKey(id, windowingMode, baseIntent, sourceComponent, userId,
+ lastActiveTime, displayId);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
}
@ViewDebug.ExportedProperty(deepExport=true, prefix="key_")
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java
new file mode 100644
index 000000000000..b79fcbd43972
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shared.recents.utilities;
+
+import android.graphics.Bitmap;
+import android.graphics.ColorSpace;
+import android.graphics.ParcelableColorSpace;
+import android.hardware.HardwareBuffer;
+import android.os.Bundle;
+
+import java.util.Objects;
+
+/**
+ * Utils for working with Bitmaps.
+ */
+public final class BitmapUtil {
+ private static final String KEY_BUFFER = "bitmap_util_buffer";
+ private static final String KEY_COLOR_SPACE = "bitmap_util_color_space";
+
+ private BitmapUtil(){ }
+
+ /**
+ * Creates a Bundle that represents the given Bitmap.
+ * <p>The Bundle will contain a wrapped version of the Bitmaps HardwareBuffer, so will avoid
+ * copies when passing across processes, only pass to processes you trust.
+ *
+ * <p>Returns a new Bundle rather than modifying an exiting one to avoid key collisions, the
+ * returned Bundle should be treated as a standalone object.
+ *
+ * @param bitmap to convert to bundle
+ * @return a Bundle representing the bitmap, should only be parsed by
+ * {@link #bundleToHardwareBitmap(Bundle)}
+ */
+ public static Bundle hardwareBitmapToBundle(Bitmap bitmap) {
+ if (bitmap.getConfig() != Bitmap.Config.HARDWARE) {
+ throw new IllegalArgumentException(
+ "Passed bitmap must have hardware config, found: " + bitmap.getConfig());
+ }
+
+ // Bitmap assumes SRGB for null color space
+ ParcelableColorSpace colorSpace =
+ bitmap.getColorSpace() == null
+ ? new ParcelableColorSpace(ColorSpace.get(ColorSpace.Named.SRGB))
+ : new ParcelableColorSpace(bitmap.getColorSpace());
+
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(KEY_BUFFER, bitmap.getHardwareBuffer());
+ bundle.putParcelable(KEY_COLOR_SPACE, colorSpace);
+
+ return bundle;
+ }
+
+ /**
+ * Extracts the Bitmap added to a Bundle with {@link #hardwareBitmapToBundle(Bitmap)} .}
+ *
+ * <p>This Bitmap contains the HardwareBuffer from the original caller, be careful passing this
+ * Bitmap on to any other source.
+ *
+ * @param bundle containing the bitmap
+ * @return a hardware Bitmap
+ */
+ public static Bitmap bundleToHardwareBitmap(Bundle bundle) {
+ if (!bundle.containsKey(KEY_BUFFER) || !bundle.containsKey(KEY_COLOR_SPACE)) {
+ throw new IllegalArgumentException("Bundle does not contain a hardware bitmap");
+ }
+
+ HardwareBuffer buffer = bundle.getParcelable(KEY_BUFFER);
+ ParcelableColorSpace colorSpace = bundle.getParcelable(KEY_COLOR_SPACE);
+
+ return Bitmap.wrapHardwareBuffer(Objects.requireNonNull(buffer), colorSpace);
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
index dd5cc7c9bbd4..796aaeefb62f 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
@@ -114,4 +114,7 @@ public abstract class TaskStackChangeListener {
/** @see ITaskStackListener#onRecentTaskListFrozenChanged(boolean) */
public void onRecentTaskListFrozenChanged(boolean frozen) { }
+
+ /** @see ITaskStackListener#onActivityRotation()*/
+ public void onActivityRotation() { }
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index a76a901c5c81..13f7993f57d4 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -237,6 +237,11 @@ public class TaskStackChangeListeners extends TaskStackListener {
mHandler.obtainMessage(H.ON_TASK_DESCRIPTION_CHANGED, taskInfo).sendToTarget();
}
+ @Override
+ public void onActivityRotation() {
+ mHandler.obtainMessage(H.ON_ACTIVITY_ROTATION).sendToTarget();
+ }
+
private final class H extends Handler {
private static final int ON_TASK_STACK_CHANGED = 1;
private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
@@ -260,6 +265,7 @@ public class TaskStackChangeListeners extends TaskStackListener {
private static final int ON_SINGLE_TASK_DISPLAY_EMPTY = 22;
private static final int ON_TASK_LIST_FROZEN_UNFROZEN = 23;
private static final int ON_TASK_DESCRIPTION_CHANGED = 24;
+ private static final int ON_ACTIVITY_ROTATION = 25;
public H(Looper looper) {
@@ -427,6 +433,12 @@ public class TaskStackChangeListeners extends TaskStackListener {
}
break;
}
+ case ON_ACTIVITY_ROTATION: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityRotation();
+ }
+ break;
+ }
}
}
if (msg.obj instanceof SomeArgs) {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
index dd613263e5c2..73783ae7ece2 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java
@@ -15,6 +15,7 @@
*/
package com.android.systemui.shared.system;
+import android.graphics.HardwareRenderer;
import android.view.SurfaceControl;
import android.view.View;
import android.view.ViewRootImpl;
@@ -50,7 +51,13 @@ public class ViewRootImplCompat {
public void registerRtFrameCallback(LongConsumer callback) {
if (mViewRoot != null) {
- mViewRoot.registerRtFrameCallback(callback::accept);
+ mViewRoot.registerRtFrameCallback(
+ new HardwareRenderer.FrameDrawingCallback() {
+ @Override
+ public void onFrameDraw(long l) {
+ callback.accept(l);
+ }
+ });
}
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
new file mode 100644
index 000000000000..8cd68ef8acbc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardFaceListenModel.kt
@@ -0,0 +1,26 @@
+package com.android.keyguard
+
+import android.annotation.CurrentTimeMillisLong
+
+/**
+ * Data class for tracking information associated with [KeyguardUpdateMonitor.shouldListenForFace]
+ * method calls.
+ */
+data class KeyguardFaceListenModel(
+ @CurrentTimeMillisLong val timeMillis: Long,
+ val userId: Int,
+ val isListeningForFace: Boolean,
+ val isBouncer: Boolean,
+ val isAuthInterruptActive: Boolean,
+ val isKeyguardAwake: Boolean,
+ val isListeningForFaceAssistant: Boolean,
+ val isSwitchingUser: Boolean,
+ val isFaceDisabled: Boolean,
+ val isBecauseCannotSkipBouncer: Boolean,
+ val isKeyguardGoingAway: Boolean,
+ val isFaceSettingEnabledForUser: Boolean,
+ val isLockIconPressed: Boolean,
+ val isScanningAllowedByStrongAuth: Boolean,
+ val isPrimaryUser: Boolean,
+ val isSecureCameraLaunched: Boolean
+)
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 0db713e9c276..ee31706c0b94 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -58,6 +58,7 @@ import android.hardware.face.FaceManager;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
+import android.os.Build;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IRemoteCallback;
@@ -108,9 +109,13 @@ import com.google.android.collect.Lists;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
+import java.text.SimpleDateFormat;
+import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.Date;
import java.util.HashMap;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TimeZone;
@@ -131,7 +136,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private static final String TAG = "KeyguardUpdateMonitor";
private static final boolean DEBUG = KeyguardConstants.DEBUG;
private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES;
- private static final boolean DEBUG_FACE = true;
+ private static final boolean DEBUG_FACE = Build.IS_DEBUGGABLE;
private static final boolean DEBUG_SPEW = false;
private static final int LOW_BATTERY_THRESHOLD = 20;
@@ -362,6 +367,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
@VisibleForTesting
SparseArray<BiometricAuthenticated> mUserFaceAuthenticated = new SparseArray<>();
+ // Keep track of recent calls to shouldListenForFace() for debugging.
+ private static final int FACE_LISTEN_CALLS_QUEUE_SIZE = 20;
+ private ArrayDeque<KeyguardFaceListenModel> mFaceListenModels;
+
private static int sCurrentUser;
private Runnable mUpdateBiometricListeningState = this::updateBiometricListeningState;
@@ -1945,25 +1954,48 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
&& strongAuthAllowsScanning && mIsPrimaryUser
&& !mSecureCameraLaunched;
+ // Aggregate relevant fields for debug logging.
+ if (DEBUG_FACE || DEBUG_SPEW) {
+ final KeyguardFaceListenModel model = new KeyguardFaceListenModel(
+ System.currentTimeMillis(),
+ user,
+ shouldListen,
+ mBouncer,
+ mAuthInterruptActive,
+ awakeKeyguard,
+ shouldListenForFaceAssistant(),
+ mSwitchingUser,
+ isFaceDisabled(user),
+ becauseCannotSkipBouncer,
+ mKeyguardGoingAway,
+ mFaceSettingEnabledForUser.get(user),
+ mLockIconPressed,
+ strongAuthAllowsScanning,
+ mIsPrimaryUser,
+ mSecureCameraLaunched);
+ maybeLogFaceListenerModelData(model);
+ }
+
+ return shouldListen;
+ }
+
+ private void maybeLogFaceListenerModelData(KeyguardFaceListenModel model) {
// Too chatty, but very useful when debugging issues.
if (DEBUG_SPEW) {
- Log.v(TAG, "shouldListenForFace(" + user + ")=" + shouldListen + "... "
- + ", mBouncer: " + mBouncer
- + ", mAuthInterruptActive: " + mAuthInterruptActive
- + ", awakeKeyguard: " + awakeKeyguard
- + ", shouldListenForFaceAssistant: " + shouldListenForFaceAssistant()
- + ", mSwitchingUser: " + mSwitchingUser
- + ", isFaceDisabled(" + user + "): " + isFaceDisabled(user)
- + ", becauseCannotSkipBouncer: " + becauseCannotSkipBouncer
- + ", mKeyguardGoingAway: " + mKeyguardGoingAway
- + ", mFaceSettingEnabledForUser(" + user + "): "
- + mFaceSettingEnabledForUser.get(user)
- + ", mLockIconPressed: " + mLockIconPressed
- + ", strongAuthAllowsScanning: " + strongAuthAllowsScanning
- + ", isPrimaryUser: " + mIsPrimaryUser
- + ", mSecureCameraLaunched: " + mSecureCameraLaunched);
+ Log.v(TAG, model.toString());
+ }
+
+ // Add model data to the historical buffer.
+ if (DEBUG_FACE && mFaceRunningState != BIOMETRIC_STATE_RUNNING
+ && model.isListeningForFace()) {
+ if (mFaceListenModels == null) {
+ mFaceListenModels = new ArrayDeque<>(FACE_LISTEN_CALLS_QUEUE_SIZE);
+ }
+ if (mFaceListenModels.size() >= FACE_LISTEN_CALLS_QUEUE_SIZE) {
+ mFaceListenModels.remove();
+ }
+ mFaceListenModels.add(model);
}
- return shouldListen;
}
/**
@@ -2919,5 +2951,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
pw.println(" enabledByUser=" + mFaceSettingEnabledForUser.get(userId));
pw.println(" mSecureCameraLaunched=" + mSecureCameraLaunched);
}
+ if (mFaceListenModels != null && !mFaceListenModels.isEmpty()) {
+ final SimpleDateFormat dateFormat =
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.US);
+ pw.println(" Face listen results (last " + FACE_LISTEN_CALLS_QUEUE_SIZE + " calls):");
+ for (final KeyguardFaceListenModel model : mFaceListenModels) {
+ final String time = dateFormat.format(new Date(model.getTimeMillis()));
+ pw.println(" " + time + " " + model.toString());
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 87990cd3bffa..ccb506de6d8b 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -124,7 +124,7 @@ public final class Prefs {
String HAS_SEEN_BUBBLES_MANAGE_EDUCATION = "HasSeenBubblesManageOnboarding";
String CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT = "ControlsStructureSwipeTooltipCount";
/** Tracks whether the user has seen the onboarding screen for priority conversations */
- String HAS_SEEN_PRIORITY_ONBOARDING = "HasSeenPriorityOnboarding";
+ String HAS_SEEN_PRIORITY_ONBOARDING = "HaveShownPriorityOnboarding";
}
public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
index f1cb66784263..708002d5b946 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@@ -27,8 +27,10 @@ import android.os.UserHandle;
import android.util.Slog;
import com.android.internal.os.BinderInternal;
+import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpHandler;
+import com.android.systemui.dump.LogBufferFreezer;
import com.android.systemui.dump.SystemUIAuxiliaryDumpService;
import java.io.FileDescriptor;
@@ -40,21 +42,32 @@ public class SystemUIService extends Service {
private final Handler mMainHandler;
private final DumpHandler mDumpHandler;
+ private final BroadcastDispatcher mBroadcastDispatcher;
+ private final LogBufferFreezer mLogBufferFreezer;
@Inject
public SystemUIService(
@Main Handler mainHandler,
- DumpHandler dumpHandler) {
+ DumpHandler dumpHandler,
+ BroadcastDispatcher broadcastDispatcher,
+ LogBufferFreezer logBufferFreezer) {
super();
mMainHandler = mainHandler;
mDumpHandler = dumpHandler;
+ mBroadcastDispatcher = broadcastDispatcher;
+ mLogBufferFreezer = logBufferFreezer;
}
@Override
public void onCreate() {
super.onCreate();
+
+ // Start all of SystemUI
((SystemUIApplication) getApplication()).startServicesIfNeeded();
+ // Finish initializing dump logic
+ mLogBufferFreezer.attach(mBroadcastDispatcher);
+
// For debugging RescueParty
if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_sysui", false)) {
throw new RuntimeException();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 15eda0689101..97a73043aa08 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -21,6 +21,7 @@ import static android.view.Display.INVALID_DISPLAY;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
+import android.annotation.DimenRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
@@ -104,27 +105,39 @@ class Bubble implements BubbleViewProvider {
private Path mDotPath;
private int mFlags;
+ @NonNull
+ private UserHandle mUser;
+ @NonNull
+ private String mPackageName;
+ private int mDesiredHeight;
+ @DimenRes
+ private int mDesiredHeightResId;
+
/**
* Create a bubble with limited information based on given {@link ShortcutInfo}.
* Note: Currently this is only being used when the bubble is persisted to disk.
*/
- Bubble(@NonNull final String key, @NonNull final ShortcutInfo shortcutInfo) {
+ Bubble(@NonNull final String key, @NonNull final ShortcutInfo shortcutInfo,
+ final int desiredHeight, final int desiredHeightResId) {
Objects.requireNonNull(key);
Objects.requireNonNull(shortcutInfo);
mShortcutInfo = shortcutInfo;
mKey = key;
mFlags = 0;
+ mUser = shortcutInfo.getUserHandle();
+ mPackageName = shortcutInfo.getPackage();
+ mDesiredHeight = desiredHeight;
+ mDesiredHeightResId = desiredHeightResId;
}
/** Used in tests when no UI is required. */
@VisibleForTesting(visibility = PRIVATE)
- Bubble(NotificationEntry e,
- BubbleController.NotificationSuppressionChangedListener listener) {
- mEntry = e;
+ Bubble(@NonNull final NotificationEntry e,
+ @Nullable final BubbleController.NotificationSuppressionChangedListener listener) {
+ Objects.requireNonNull(e);
mKey = e.getKey();
- mLastUpdated = e.getSbn().getPostTime();
mSuppressionListener = listener;
- mFlags = e.getSbn().getNotification().flags;
+ setEntry(e);
}
@Override
@@ -137,17 +150,14 @@ class Bubble implements BubbleViewProvider {
return mEntry;
}
- @Nullable
+ @NonNull
public UserHandle getUser() {
- if (mEntry != null) return mEntry.getSbn().getUser();
- if (mShortcutInfo != null) return mShortcutInfo.getUserHandle();
- return null;
+ return mUser;
}
+ @NonNull
public String getPackageName() {
- return mEntry == null
- ? mShortcutInfo == null ? null : mShortcutInfo.getPackage()
- : mEntry.getSbn().getPackageName();
+ return mPackageName;
}
@Override
@@ -318,9 +328,18 @@ class Bubble implements BubbleViewProvider {
/**
* Sets the entry associated with this bubble.
*/
- void setEntry(NotificationEntry entry) {
+ void setEntry(@NonNull final NotificationEntry entry) {
+ Objects.requireNonNull(entry);
+ Objects.requireNonNull(entry.getSbn());
mEntry = entry;
mLastUpdated = entry.getSbn().getPostTime();
+ mFlags = entry.getSbn().getNotification().flags;
+ mPackageName = entry.getSbn().getPackageName();
+ mUser = entry.getSbn().getUser();
+ if (entry.getBubbleMetadata() != null) {
+ mDesiredHeight = entry.getBubbleMetadata().getDesiredHeight();
+ mDesiredHeightResId = entry.getBubbleMetadata().getDesiredHeightResId();
+ }
}
/**
@@ -434,28 +453,30 @@ class Bubble implements BubbleViewProvider {
return mFlyoutMessage;
}
+ int getRawDesiredHeight() {
+ return mDesiredHeight;
+ }
+
+ int getRawDesiredHeightResId() {
+ return mDesiredHeightResId;
+ }
+
float getDesiredHeight(Context context) {
- if (mEntry == null) return 0;
- Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
- boolean useRes = data.getDesiredHeightResId() != 0;
+ boolean useRes = mDesiredHeightResId != 0;
if (useRes) {
- return getDimenForPackageUser(context, data.getDesiredHeightResId(),
- mEntry.getSbn().getPackageName(),
- mEntry.getSbn().getUser().getIdentifier());
+ return getDimenForPackageUser(context, mDesiredHeightResId, mPackageName,
+ mUser.getIdentifier());
} else {
- return data.getDesiredHeight()
- * context.getResources().getDisplayMetrics().density;
+ return mDesiredHeight * context.getResources().getDisplayMetrics().density;
}
}
String getDesiredHeightString() {
- if (mEntry == null) return String.valueOf(0);
- Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
- boolean useRes = data.getDesiredHeightResId() != 0;
+ boolean useRes = mDesiredHeightResId != 0;
if (useRes) {
- return String.valueOf(data.getDesiredHeightResId());
+ return String.valueOf(mDesiredHeightResId);
} else {
- return String.valueOf(data.getDesiredHeight());
+ return String.valueOf(mDesiredHeight);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index f05d547edd0c..734199eee72e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -212,6 +212,13 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
private final List<NotifCallback> mCallbacks = new ArrayList<>();
/**
+ * Whether the IME is visible, as reported by the BubbleStackView. If it is, we'll make the
+ * Bubbles window NOT_FOCUSABLE so that touches on the Bubbles UI doesn't steal focus from the
+ * ActivityView and hide the IME.
+ */
+ private boolean mImeVisible = false;
+
+ /**
* Listener to find out about stack expansion / collapse events.
*/
public interface BubbleExpandListener {
@@ -571,6 +578,18 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
}
/**
+ * Called when the status bar has become visible or invisible (either permanently or
+ * temporarily).
+ */
+ public void onStatusBarVisibilityChanged(boolean visible) {
+ if (mStackView != null) {
+ // Hide the stack temporarily if the status bar has been made invisible, and the stack
+ // is collapsed. An expanded stack should remain visible until collapsed.
+ mStackView.setTemporarilyInvisible(!visible && !isStackExpanded());
+ }
+ }
+
+ /**
* Sets whether to perform inflation on the same thread as the caller. This method should only
* be used in tests, not in production.
*/
@@ -598,7 +617,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
if (mStackView == null) {
mStackView = new BubbleStackView(
mContext, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator,
- mSysUiState, mNotificationShadeWindowController, this::onAllBubblesAnimatedOut);
+ mSysUiState, mNotificationShadeWindowController, this::onAllBubblesAnimatedOut,
+ this::onImeVisibilityChanged);
mStackView.addView(mBubbleScrim);
if (mExpandListener != null) {
mStackView.setExpandListener(mExpandListener);
@@ -649,6 +669,11 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
}
}
+ private void onImeVisibilityChanged(boolean imeVisible) {
+ mImeVisible = imeVisible;
+ updateWmFlags();
+ }
+
/** Removes the BubbleStackView from the WindowManager if it's there. */
private void removeFromWindowManagerMaybe() {
if (!mAddedToWindowManager) {
@@ -676,13 +701,14 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
* the new params if the stack has been added.
*/
private void updateWmFlags() {
- if (isStackExpanded()) {
- // If we're expanded, we want to be focusable so that the ActivityView can receive focus
- // and show the IME.
+ if (isStackExpanded() && !mImeVisible) {
+ // If we're expanded, and the IME isn't visible, we want to be focusable. This ensures
+ // that any taps within Bubbles (including on the ActivityView) results in Bubbles
+ // receiving focus and clearing it from any other windows that might have it.
mWmLayoutParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
} else {
- // If we're collapsed, we don't want to be able to receive focus. Doing so would
- // preclude applications from using the IME since we are always above them.
+ // If we're collapsed, we don't want to be focusable since tapping on the stack would
+ // steal focus from apps. We also don't want to be focusable if the IME is visible,
mWmLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
}
@@ -784,6 +810,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi
mBubbleIconFactory = new BubbleIconFactory(mContext);
mStackView.onDisplaySizeChanged();
}
+
+ mStackView.onLayoutDirectionChanged();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
index c2b9195c8ba3..d20f40559b5d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt
@@ -77,7 +77,8 @@ internal class BubbleDataRepository @Inject constructor(
var shortcutId = b.shortcutInfo?.id
if (shortcutId == null) shortcutId = b.entry?.bubbleMetadata?.shortcutId
if (shortcutId == null) return@mapNotNull null
- BubbleEntity(userId, b.packageName, shortcutId, b.key)
+ BubbleEntity(userId, b.packageName, shortcutId, b.key, b.rawDesiredHeight,
+ b.rawDesiredHeightResId)
}
}
@@ -158,7 +159,8 @@ internal class BubbleDataRepository @Inject constructor(
val bubbles = entities.mapNotNull { entity ->
shortcutMap[ShortcutKey(entity.userId, entity.packageName)]
?.first { shortcutInfo -> entity.shortcutId == shortcutInfo.id }
- ?.let { shortcutInfo -> Bubble(entity.key, shortcutInfo) }
+ ?.let { shortcutInfo -> Bubble(entity.key, shortcutInfo, entity.desiredHeight,
+ entity.desiredHeightResId) }
}
uiScope.launch { cb(bubbles) }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 64dc2ccc8b52..790d6a2070a2 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -34,6 +34,7 @@ import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.ActivityView;
@@ -239,6 +240,7 @@ public class BubbleExpandedView extends LinearLayout {
mPointerMargin = res.getDimensionPixelSize(R.dimen.bubble_pointer_margin);
}
+ @SuppressLint("ClickableViewAccessibility")
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@@ -290,6 +292,34 @@ public class BubbleExpandedView extends LinearLayout {
}
return view.onApplyWindowInsets(insets);
});
+
+ final int expandedViewPadding =
+ res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding);
+
+ setPadding(
+ expandedViewPadding, expandedViewPadding, expandedViewPadding, expandedViewPadding);
+ setOnTouchListener((view, motionEvent) -> {
+ if (!usingActivityView()) {
+ return false;
+ }
+
+ final Rect avBounds = new Rect();
+ mActivityView.getBoundsOnScreen(avBounds);
+
+ // Consume and ignore events on the expanded view padding that are within the
+ // ActivityView's vertical bounds. These events are part of a back gesture, and so they
+ // should not collapse the stack (which all other touches on areas around the AV would
+ // do).
+ if (motionEvent.getRawY() >= avBounds.top && motionEvent.getRawY() <= avBounds.bottom) {
+ return true;
+ }
+
+ return false;
+ });
+
+ // BubbleStackView is forced LTR, but we want to respect the locale for expanded view layout
+ // so the Manage button appears on the right.
+ setLayoutDirection(LAYOUT_DIRECTION_LOCALE);
}
private String getBubbleKey() {
@@ -323,9 +353,19 @@ public class BubbleExpandedView extends LinearLayout {
}
}
+ /**
+ * Hides the IME if it's showing. This is currently done by dispatching a back press to the AV.
+ */
+ void hideImeIfVisible() {
+ if (mKeyboardVisible) {
+ performBackPressIfNeeded();
+ }
+ }
+
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
+ hideImeIfVisible();
mKeyboardVisible = false;
mNeedsNewHeight = false;
if (mActivityView != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
index e12b325f5d05..8c76cda3290f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
@@ -186,6 +186,9 @@ public class BubbleFlyoutView extends FrameLayout {
}
});
+ // Use locale direction so the text is aligned correctly.
+ setLayoutDirection(LAYOUT_DIRECTION_LOCALE);
+
mBgPaint.setColor(mFloatingBackgroundColor);
mLeftTriangleShape =
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java
index 0327cb4b2919..c5faae0d703e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleLoggerImpl.java
@@ -17,6 +17,7 @@
package com.android.systemui.bubbles;
import android.service.notification.StatusBarNotification;
+
import com.android.internal.logging.UiEventLoggerImpl;
/**
@@ -31,6 +32,10 @@ public class BubbleLoggerImpl extends UiEventLoggerImpl implements BubbleLogger
* @param e UI event
*/
public void log(Bubble b, UiEventEnum e) {
+ if (b.getEntry() == null) {
+ // Added from persistence -- TODO log this with specific event?
+ return;
+ }
StatusBarNotification sbn = b.getEntry().getSbn();
logWithInstanceId(e, sbn.getUid(), sbn.getPackageName(), sbn.getInstanceId());
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
index bea4ba776beb..3e694b9f5d2a 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java
@@ -22,6 +22,7 @@ import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME
import android.app.Activity;
import android.content.Context;
+import android.content.pm.ShortcutInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -204,6 +205,8 @@ public class BubbleOverflowActivity extends Activity {
}
class BubbleOverflowAdapter extends RecyclerView.Adapter<BubbleOverflowAdapter.ViewHolder> {
+ private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleOverflowAdapter" : TAG_BUBBLES;
+
private Context mContext;
private Consumer<Bubble> mPromoteBubbleFromOverflow;
private List<Bubble> mBubbles;
@@ -282,11 +285,19 @@ class BubbleOverflowAdapter extends RecyclerView.Adapter<BubbleOverflowAdapter.V
}
});
- Bubble.FlyoutMessage message = b.getFlyoutMessage();
- if (message != null && message.senderName != null) {
- vh.textView.setText(message.senderName.toString());
+ // If the bubble was persisted, the entry is null but it should have shortcut info
+ ShortcutInfo info = b.getEntry() == null
+ ? b.getShortcutInfo()
+ : b.getEntry().getRanking().getShortcutInfo();
+ if (info == null) {
+ Log.d(TAG, "ShortcutInfo required to bubble but none found for " + b);
} else {
- vh.textView.setText(b.getAppName());
+ CharSequence label = info.getLabel();
+ if (label == null) {
+ vh.textView.setText(b.getAppName());
+ } else {
+ vh.textView.setText(label.toString());
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 239132ea292b..91f361b15945 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -47,6 +47,7 @@ import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
+import android.graphics.drawable.TransitionDrawable;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
@@ -79,6 +80,7 @@ import androidx.dynamicanimation.animation.SpringForce;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ContrastColorUtil;
import com.android.internal.widget.ViewClippingUtil;
+import com.android.systemui.Interpolators;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.bubbles.animation.ExpandedAnimationController;
@@ -88,6 +90,7 @@ import com.android.systemui.model.SysUiState;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.util.DismissCircleView;
import com.android.systemui.util.FloatingContentCoordinator;
@@ -133,6 +136,9 @@ public class BubbleStackView extends FrameLayout
/** Percent to darken the bubbles when they're in the dismiss target. */
private static final float DARKEN_PERCENT = 0.3f;
+ /** Duration of the dismiss scrim fading in/out. */
+ private static final int DISMISS_TRANSITION_DURATION_MS = 200;
+
/** How long to wait, in milliseconds, before hiding the flyout. */
@VisibleForTesting
static final int FLYOUT_HIDE_AFTER = 5000;
@@ -239,6 +245,9 @@ public class BubbleStackView extends FrameLayout
/** Whether a touch gesture, such as a stack/bubble drag or flyout drag, is in progress. */
private boolean mIsGestureInProgress = false;
+ /** Whether or not the stack is temporarily invisible off the side of the screen. */
+ private boolean mTemporarilyInvisible = false;
+
/** Description of current animation controller state. */
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("Stack view state:");
@@ -261,7 +270,7 @@ public class BubbleStackView extends FrameLayout
private boolean mShowingDismiss = false;
/** The view to desaturate/darken when magneted to the dismiss target. */
- private View mDesaturateAndDarkenTargetView;
+ @Nullable private View mDesaturateAndDarkenTargetView;
private LayoutInflater mInflater;
@@ -342,6 +351,12 @@ public class BubbleStackView extends FrameLayout
private final NotificationShadeWindowController mNotificationShadeWindowController;
/**
+ * Callback to run when the IME visibility changes - BubbleController uses this to update the
+ * Bubbles window focusability flags with the WindowManager.
+ */
+ public final Consumer<Boolean> mOnImeVisibilityChanged;
+
+ /**
* The currently magnetized object, which is being dragged and will be attracted to the magnetic
* dismiss target.
*
@@ -667,7 +682,8 @@ public class BubbleStackView extends FrameLayout
FloatingContentCoordinator floatingContentCoordinator,
SysUiState sysUiState,
NotificationShadeWindowController notificationShadeWindowController,
- Runnable allBubblesAnimatedOutAction) {
+ Runnable allBubblesAnimatedOutAction,
+ Consumer<Boolean> onImeVisibilityChanged) {
super(context);
mBubbleData = data;
@@ -716,6 +732,12 @@ public class BubbleStackView extends FrameLayout
setUpUserEducation();
+ // Force LTR by default since most of the Bubbles UI is positioned manually by the user, or
+ // is centered. It greatly simplifies translation positioning/animations. Views that will
+ // actually lay out differently in RTL, such as the flyout and expanded view, will set their
+ // layout direction to LOCALE.
+ setLayoutDirection(LAYOUT_DIRECTION_LTR);
+
mBubbleContainer = new PhysicsAnimationLayout(context);
mBubbleContainer.setActiveController(mStackAnimationController);
mBubbleContainer.setElevation(elevation);
@@ -724,8 +746,6 @@ public class BubbleStackView extends FrameLayout
mExpandedViewContainer = new FrameLayout(context);
mExpandedViewContainer.setElevation(elevation);
- mExpandedViewContainer.setPadding(mExpandedViewPadding, mExpandedViewPadding,
- mExpandedViewPadding, mExpandedViewPadding);
mExpandedViewContainer.setClipChildren(false);
addView(mExpandedViewContainer);
@@ -741,7 +761,7 @@ public class BubbleStackView extends FrameLayout
final View targetView = new DismissCircleView(context);
final FrameLayout.LayoutParams newParams =
new FrameLayout.LayoutParams(targetSize, targetSize);
- newParams.gravity = Gravity.CENTER;
+ newParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
targetView.setLayoutParams(newParams);
mDismissTargetAnimator = PhysicsAnimator.getInstance(targetView);
@@ -750,9 +770,16 @@ public class BubbleStackView extends FrameLayout
MATCH_PARENT,
getResources().getDimensionPixelSize(R.dimen.floating_dismiss_gradient_height),
Gravity.BOTTOM));
+
+ final int bottomMargin =
+ getResources().getDimensionPixelSize(R.dimen.floating_dismiss_bottom_margin);
+ mDismissTargetContainer.setPadding(0, 0, 0, bottomMargin);
+ mDismissTargetContainer.setClipToPadding(false);
mDismissTargetContainer.setClipChildren(false);
mDismissTargetContainer.addView(targetView);
mDismissTargetContainer.setVisibility(View.INVISIBLE);
+ mDismissTargetContainer.setBackgroundResource(
+ R.drawable.floating_dismiss_gradient_transition);
addView(mDismissTargetContainer);
// Start translated down so the target springs up.
@@ -793,7 +820,11 @@ public class BubbleStackView extends FrameLayout
setUpOverflow();
+ mOnImeVisibilityChanged = onImeVisibilityChanged;
+
setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
+ onImeVisibilityChanged.accept(insets.getInsets(WindowInsets.Type.ime()).bottom > 0);
+
if (!mIsExpanded || mIsExpansionAnimating) {
return view.onApplyWindowInsets(insets);
}
@@ -877,7 +908,10 @@ public class BubbleStackView extends FrameLayout
// Update the paint and apply it to the bubble container.
mDesaturateAndDarkenPaint.setColorFilter(new ColorMatrixColorFilter(animatedMatrix));
- mDesaturateAndDarkenTargetView.setLayerPaint(mDesaturateAndDarkenPaint);
+
+ if (mDesaturateAndDarkenTargetView != null) {
+ mDesaturateAndDarkenTargetView.setLayerPaint(mDesaturateAndDarkenPaint);
+ }
});
// If the stack itself is touched, it means none of its touchable views (bubbles, flyouts,
@@ -893,6 +927,38 @@ public class BubbleStackView extends FrameLayout
return true;
});
+
+ animate()
+ .setInterpolator(Interpolators.PANEL_CLOSE_ACCELERATED)
+ .setDuration(CollapsedStatusBarFragment.FADE_IN_DURATION);
+ }
+
+ /**
+ * Sets whether or not the stack should become temporarily invisible by moving off the side of
+ * the screen.
+ *
+ * If a flyout comes in while it's invisible, it will animate back in while the flyout is
+ * showing but disappear again when the flyout is gone.
+ */
+ public void setTemporarilyInvisible(boolean invisible) {
+ mTemporarilyInvisible = invisible;
+ animateTemporarilyInvisible();
+ }
+
+ /**
+ * Animates onto or off the screen depending on whether we're temporarily invisible, and whether
+ * a flyout is visible.
+ */
+ private void animateTemporarilyInvisible() {
+ if (mTemporarilyInvisible && mFlyout.getVisibility() != View.VISIBLE) {
+ if (mStackAnimationController.isStackOnLeftSide()) {
+ animate().translationX(-mBubbleSize).start();
+ } else {
+ animate().translationX(mBubbleSize).start();
+ }
+ } else {
+ animate().translationX(0).start();
+ }
}
private void setUpManageMenu() {
@@ -952,6 +1018,9 @@ public class BubbleStackView extends FrameLayout
mManageSettingsIcon = mManageMenu.findViewById(R.id.bubble_manage_menu_settings_icon);
mManageSettingsText = mManageMenu.findViewById(R.id.bubble_manage_menu_settings_name);
+
+ // The menu itself should respect locale direction so the icons are on the correct side.
+ mManageMenu.setLayoutDirection(LAYOUT_DIRECTION_LOCALE);
addView(mManageMenu);
}
@@ -1075,6 +1144,16 @@ public class BubbleStackView extends FrameLayout
mShowingManage = false;
}
+ /** Tells the views with locale-dependent layout direction to resolve the new direction. */
+ public void onLayoutDirectionChanged() {
+ mManageMenu.resolveLayoutDirection();
+ mFlyout.resolveLayoutDirection();
+
+ if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+ mExpandedBubble.getExpandedView().resolveLayoutDirection();
+ }
+ }
+
/** Respond to the display size change by recalculating view size and location. */
public void onDisplaySizeChanged() {
setUpOverflow();
@@ -1818,6 +1897,10 @@ public class BubbleStackView extends FrameLayout
private void animateDesaturateAndDarken(View targetView, boolean desaturateAndDarken) {
mDesaturateAndDarkenTargetView = targetView;
+ if (mDesaturateAndDarkenTargetView == null) {
+ return;
+ }
+
if (desaturateAndDarken) {
// Use the animated paint for the bubbles.
mDesaturateAndDarkenTargetView.setLayerType(
@@ -1839,9 +1922,14 @@ public class BubbleStackView extends FrameLayout
}
private void resetDesaturationAndDarken() {
+
mDesaturateAndDarkenAnimator.removeAllListeners();
mDesaturateAndDarkenAnimator.cancel();
- mDesaturateAndDarkenTargetView.setLayerType(View.LAYER_TYPE_NONE, null);
+
+ if (mDesaturateAndDarkenTargetView != null) {
+ mDesaturateAndDarkenTargetView.setLayerType(View.LAYER_TYPE_NONE, null);
+ mDesaturateAndDarkenTargetView = null;
+ }
}
/** Animates in the dismiss target. */
@@ -1856,6 +1944,9 @@ public class BubbleStackView extends FrameLayout
mDismissTargetContainer.setZ(Short.MAX_VALUE - 1);
mDismissTargetContainer.setVisibility(VISIBLE);
+ ((TransitionDrawable) mDismissTargetContainer.getBackground()).startTransition(
+ DISMISS_TRANSITION_DURATION_MS);
+
mDismissTargetAnimator.cancel();
mDismissTargetAnimator
.spring(DynamicAnimation.TRANSLATION_Y, 0f, mDismissTargetSpring)
@@ -1873,6 +1964,9 @@ public class BubbleStackView extends FrameLayout
mShowingDismiss = false;
+ ((TransitionDrawable) mDismissTargetContainer.getBackground()).reverseTransition(
+ DISMISS_TRANSITION_DURATION_MS);
+
mDismissTargetAnimator
.spring(DynamicAnimation.TRANSLATION_Y, mDismissTargetContainer.getHeight(),
mDismissTargetSpring)
@@ -1944,6 +2038,9 @@ public class BubbleStackView extends FrameLayout
// Stop suppressing the dot now that the flyout has morphed into the dot.
bubbleView.removeDotSuppressionFlag(
BadgedImageView.SuppressionFlag.FLYOUT_VISIBLE);
+
+ mFlyout.setVisibility(INVISIBLE);
+ animateTemporarilyInvisible();
};
mFlyout.setVisibility(INVISIBLE);
@@ -1961,6 +2058,7 @@ public class BubbleStackView extends FrameLayout
final Runnable expandFlyoutAfterDelay = () -> {
mAnimateInFlyout = () -> {
mFlyout.setVisibility(VISIBLE);
+ animateTemporarilyInvisible();
mFlyoutDragDeltaX =
mStackAnimationController.isStackOnLeftSide()
? -mFlyout.getWidth()
@@ -2086,16 +2184,21 @@ public class BubbleStackView extends FrameLayout
mExpandedBubble.getExpandedView().getManageButtonBoundsOnScreen(mTempRect);
- // When the menu is open, it should be at these coordinates. This will make the menu's
- // bottom left corner match up with the button's bottom left corner.
- final float targetX = mTempRect.left;
+ final boolean isLtr =
+ getResources().getConfiguration().getLayoutDirection() == LAYOUT_DIRECTION_LTR;
+
+ // When the menu is open, it should be at these coordinates. The menu pops out to the right
+ // in LTR and to the left in RTL.
+ final float targetX = isLtr ? mTempRect.left : mTempRect.right - mManageMenu.getWidth();
final float targetY = mTempRect.bottom - mManageMenu.getHeight();
+ final float xOffsetForAnimation = (isLtr ? 1 : -1) * mManageMenu.getWidth() / 4f;
+
if (show) {
mManageMenu.setScaleX(0.5f);
mManageMenu.setScaleY(0.5f);
- mManageMenu.setTranslationX(targetX - mManageMenu.getWidth() / 4);
- mManageMenu.setTranslationY(targetY + mManageMenu.getHeight() / 4);
+ mManageMenu.setTranslationX(targetX - xOffsetForAnimation);
+ mManageMenu.setTranslationY(targetY + mManageMenu.getHeight() / 4f);
mManageMenu.setAlpha(0f);
PhysicsAnimator.getInstance(mManageMenu)
@@ -2112,8 +2215,8 @@ public class BubbleStackView extends FrameLayout
.spring(DynamicAnimation.ALPHA, 0f)
.spring(DynamicAnimation.SCALE_X, 0.5f)
.spring(DynamicAnimation.SCALE_Y, 0.5f)
- .spring(DynamicAnimation.TRANSLATION_X, targetX - mManageMenu.getWidth() / 4)
- .spring(DynamicAnimation.TRANSLATION_Y, targetY + mManageMenu.getHeight() / 4)
+ .spring(DynamicAnimation.TRANSLATION_X, targetX - xOffsetForAnimation)
+ .spring(DynamicAnimation.TRANSLATION_Y, targetY + mManageMenu.getHeight() / 4f)
.withEndActions(() -> mManageMenu.setVisibility(View.INVISIBLE))
.start();
}
@@ -2126,6 +2229,13 @@ public class BubbleStackView extends FrameLayout
if (DEBUG_BUBBLE_STACK_VIEW) {
Log.d(TAG, "updateExpandedBubble()");
}
+
+ if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) {
+ // Hide the currently expanded bubble's IME if it's visible before switching to a new
+ // bubble.
+ mExpandedBubble.getExpandedView().hideImeIfVisible();
+ }
+
mExpandedViewContainer.removeAllViews();
if (mIsExpanded && mExpandedBubble != null
&& mExpandedBubble.getExpandedView() != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
index 942b9a74bb86..98a7cc23c67e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
@@ -1037,6 +1037,11 @@ public class PhysicsAnimationLayout extends FrameLayout {
if (view != null) {
final SpringAnimation animation =
(SpringAnimation) view.getTag(getTagIdForProperty(property));
+
+ if (animation == null) {
+ return;
+ }
+
final SpringForce animationSpring = animation.getSpring();
if (animationSpring == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
index 43482616da2c..355c4b115c8d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt
@@ -15,11 +15,14 @@
*/
package com.android.systemui.bubbles.storage
+import android.annotation.DimenRes
import android.annotation.UserIdInt
data class BubbleEntity(
@UserIdInt val userId: Int,
val packageName: String,
val shortcutId: String,
- val key: String
+ val key: String,
+ val desiredHeight: Int,
+ @DimenRes val desiredHeightResId: Int
)
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt
index 1df9f72022f0..a8faf258da07 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt
@@ -31,6 +31,8 @@ private const val ATTR_USER_ID = "uid"
private const val ATTR_PACKAGE = "pkg"
private const val ATTR_SHORTCUT_ID = "sid"
private const val ATTR_KEY = "key"
+private const val ATTR_DESIRED_HEIGHT = "h"
+private const val ATTR_DESIRED_HEIGHT_RES_ID = "hid"
/**
* Writes the bubbles in xml format into given output stream.
@@ -59,6 +61,8 @@ private fun writeXmlEntry(serializer: XmlSerializer, bubble: BubbleEntity) {
serializer.attribute(null, ATTR_PACKAGE, bubble.packageName)
serializer.attribute(null, ATTR_SHORTCUT_ID, bubble.shortcutId)
serializer.attribute(null, ATTR_KEY, bubble.key)
+ serializer.attribute(null, ATTR_DESIRED_HEIGHT, bubble.desiredHeight.toString())
+ serializer.attribute(null, ATTR_DESIRED_HEIGHT_RES_ID, bubble.desiredHeightResId.toString())
serializer.endTag(null, TAG_BUBBLE)
} catch (e: IOException) {
throw RuntimeException(e)
@@ -86,7 +90,9 @@ private fun readXmlEntry(parser: XmlPullParser): BubbleEntity? {
parser.getAttributeWithName(ATTR_USER_ID)?.toInt() ?: return null,
parser.getAttributeWithName(ATTR_PACKAGE) ?: return null,
parser.getAttributeWithName(ATTR_SHORTCUT_ID) ?: return null,
- parser.getAttributeWithName(ATTR_KEY) ?: return null
+ parser.getAttributeWithName(ATTR_KEY) ?: return null,
+ parser.getAttributeWithName(ATTR_DESIRED_HEIGHT)?.toInt() ?: return null,
+ parser.getAttributeWithName(ATTR_DESIRED_HEIGHT_RES_ID)?.toInt() ?: return null
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index fd9fda3662a3..93f0c7f41ce3 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -44,6 +44,7 @@ import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dump.DumpManager
+import com.android.systemui.globalactions.GlobalActionsDialog
import com.android.systemui.util.concurrency.DelayableExecutor
import java.io.FileDescriptor
import java.io.PrintWriter
@@ -79,6 +80,7 @@ class ControlsControllerImpl @Inject constructor (
}
private var userChanging: Boolean = true
+ private var userStructure: UserStructure
private var seedingInProgress = false
private val seedingCallbacks = mutableListOf<Consumer<Boolean>>()
@@ -97,7 +99,7 @@ class ControlsControllerImpl @Inject constructor (
internal var auxiliaryPersistenceWrapper: AuxiliaryPersistenceWrapper
init {
- val userStructure = UserStructure(context, currentUser)
+ userStructure = UserStructure(context, currentUser)
persistenceWrapper = optionalWrapper.orElseGet {
ControlsFavoritePersistenceWrapper(
@@ -116,7 +118,7 @@ class ControlsControllerImpl @Inject constructor (
private fun setValuesForUser(newUser: UserHandle) {
Log.d(TAG, "Changing to user: $newUser")
currentUser = newUser
- val userStructure = UserStructure(context, currentUser)
+ userStructure = UserStructure(context, currentUser)
persistenceWrapper.changeFileAndBackupManager(
userStructure.file,
BackupManager(userStructure.userContext)
@@ -192,6 +194,16 @@ class ControlsControllerImpl @Inject constructor (
it.componentName
}.toSet()
+ // When a component is uninstalled, allow seeding to happen again if the user
+ // reinstalls the app
+ val prefs = userStructure.userContext.getSharedPreferences(
+ GlobalActionsDialog.PREFS_CONTROLS_FILE, Context.MODE_PRIVATE)
+ val completedSeedingPackageSet = prefs.getStringSet(
+ GlobalActionsDialog.PREFS_CONTROLS_SEEDING_COMPLETED, mutableSetOf<String>())
+ val favoritePackageSet = favoriteComponentSet.map { it.packageName }
+ prefs.edit().putStringSet(GlobalActionsDialog.PREFS_CONTROLS_SEEDING_COMPLETED,
+ completedSeedingPackageSet.intersect(favoritePackageSet)).apply()
+
var changed = false
favoriteComponentSet.subtract(serviceInfoSet).forEach {
changed = true
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
index 10e913743224..2a40b76eb326 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
@@ -58,16 +58,14 @@ class ControlActionCoordinatorImpl @Inject constructor(
override fun toggle(cvh: ControlViewHolder, templateId: String, isChecked: Boolean) {
bouncerOrRun {
- val effect = if (!isChecked) Vibrations.toggleOnEffect else Vibrations.toggleOffEffect
- vibrate(effect)
+ cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)
cvh.action(BooleanAction(templateId, !isChecked))
}
}
override fun touch(cvh: ControlViewHolder, templateId: String, control: Control) {
- vibrate(Vibrations.toggleOnEffect)
-
bouncerOrRun {
+ cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)
if (cvh.usePanel()) {
showDialog(cvh, control.getAppIntent().getIntent())
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index f07f3168d246..994557cf696b 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -118,6 +118,7 @@ class ControlViewHolder(
var behavior: Behavior? = null
var lastAction: ControlAction? = null
var isLoading = false
+ var visibleDialog: Dialog? = null
private var lastChallengeDialog: Dialog? = null
private val onDialogCancel: () -> Unit = { lastChallengeDialog = null }
@@ -197,18 +198,24 @@ class ControlViewHolder(
fun dismiss() {
lastChallengeDialog?.dismiss()
lastChallengeDialog = null
+ visibleDialog?.dismiss()
+ visibleDialog = null
}
fun setTransientStatus(tempStatus: String) {
val previousText = status.getText()
cancelUpdate = uiExecutor.executeDelayed({
- setStatusText(previousText)
- updateContentDescription()
+ animateStatusChange(/* animated */ true, {
+ setStatusText(previousText, /* immediately */ true)
+ updateContentDescription()
+ })
}, UPDATE_DELAY_IN_MILLIS)
- setStatusText(tempStatus)
- updateContentDescription()
+ animateStatusChange(/* animated */ true, {
+ setStatusText(tempStatus, /* immediately */ true)
+ updateContentDescription()
+ })
}
private fun updateContentDescription() =
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index 35ebac5b1ed5..d31b6eb9d857 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -129,7 +129,10 @@ class ControlsUiControllerImpl @Inject constructor (
SelectionItem(it.loadLabel(), "", it.loadIcon(), it.componentName)
}
uiExecutor.execute {
- onResult(lastItems)
+ parent.removeAllViews()
+ if (lastItems.size > 0) {
+ onResult(lastItems)
+ }
}
}
}
@@ -189,8 +192,6 @@ class ControlsUiControllerImpl @Inject constructor (
}
private fun showSeedingView(items: List<SelectionItem>) {
- parent.removeAllViews()
-
val inflater = LayoutInflater.from(context)
inflater.inflate(R.layout.controls_no_favorites, parent, true)
val subtitle = parent.requireViewById<TextView>(R.id.controls_subtitle)
@@ -198,8 +199,6 @@ class ControlsUiControllerImpl @Inject constructor (
}
private fun showInitialSetupView(items: List<SelectionItem>) {
- parent.removeAllViews()
-
val inflater = LayoutInflater.from(context)
inflater.inflate(R.layout.controls_no_favorites, parent, true)
@@ -263,7 +262,6 @@ class ControlsUiControllerImpl @Inject constructor (
}
private fun showControlsView(items: List<SelectionItem>) {
- parent.removeAllViews()
controlViewsById.clear()
createListView()
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
index f97015282222..9ec14523a809 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt
@@ -64,6 +64,10 @@ class DetailDialog(
}
override fun onActivityViewDestroyed(view: ActivityView) {}
+
+ override fun onTaskRemovalStarted(taskId: Int) {
+ dismiss()
+ }
}
init {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/StatusBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/StatusBehavior.kt
index bf3835dba4fd..6bf189744033 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/StatusBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/StatusBehavior.kt
@@ -16,7 +16,13 @@
package com.android.systemui.controls.ui
+import android.app.AlertDialog
+import android.app.PendingIntent
+import android.content.DialogInterface
+import android.content.pm.PackageManager
import android.service.controls.Control
+import android.view.View
+import android.view.WindowManager
import com.android.systemui.R
@@ -31,7 +37,17 @@ class StatusBehavior : Behavior {
val status = cws.control?.status ?: Control.STATUS_UNKNOWN
val msg = when (status) {
Control.STATUS_ERROR -> R.string.controls_error_generic
- Control.STATUS_NOT_FOUND -> R.string.controls_error_removed
+ Control.STATUS_DISABLED -> R.string.controls_error_timeout
+ Control.STATUS_NOT_FOUND -> {
+ cvh.layout.setOnClickListener(View.OnClickListener() {
+ showNotFoundDialog(cvh, cws)
+ })
+ cvh.layout.setOnLongClickListener(View.OnLongClickListener() {
+ showNotFoundDialog(cvh, cws)
+ true
+ })
+ R.string.controls_error_removed
+ }
else -> {
cvh.isLoading = true
com.android.internal.R.string.loading
@@ -40,4 +56,42 @@ class StatusBehavior : Behavior {
cvh.setStatusText(cvh.context.getString(msg))
cvh.applyRenderInfo(false, colorOffset)
}
+
+ private fun showNotFoundDialog(cvh: ControlViewHolder, cws: ControlWithState) {
+ val pm = cvh.context.getPackageManager()
+ val ai = pm.getApplicationInfo(cws.componentName.packageName, PackageManager.GET_META_DATA)
+ val appLabel = pm.getApplicationLabel(ai)
+ val builder = AlertDialog.Builder(
+ cvh.context,
+ android.R.style.Theme_DeviceDefault_Dialog_Alert
+ ).apply {
+ val res = cvh.context.resources
+ setTitle(res.getString(R.string.controls_error_removed_title))
+ setMessage(res.getString(
+ R.string.controls_error_removed_message, cvh.title.getText(), appLabel))
+ setPositiveButton(
+ R.string.controls_open_app,
+ DialogInterface.OnClickListener { dialog, _ ->
+ try {
+ cws.control?.getAppIntent()?.send()
+ } catch (e: PendingIntent.CanceledException) {
+ cvh.setTransientStatus(
+ cvh.context.resources.getString(R.string.controls_error_failed))
+ }
+ dialog.dismiss()
+ })
+ setNegativeButton(
+ android.R.string.cancel,
+ DialogInterface.OnClickListener { dialog, _ ->
+ dialog.cancel()
+ }
+ )
+ }
+ cvh.visibleDialog = builder.create().apply {
+ getWindow().apply {
+ setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY)
+ show()
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
index 1f0ca9be2ecc..4003f41b33dc 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
@@ -231,9 +231,11 @@ class ToggleRangeBehavior : Behavior {
rangeAnimator?.cancel()
if (isDragging) {
- clipLayer.level = newLevel
val isEdge = newLevel == MIN_LEVEL || newLevel == MAX_LEVEL
- cvh.controlActionCoordinator.drag(isEdge)
+ if (clipLayer.level != newLevel) {
+ cvh.controlActionCoordinator.drag(isEdge)
+ clipLayer.level = newLevel
+ }
} else if (newLevel != clipLayer.level) {
rangeAnimator = ValueAnimator.ofInt(cvh.clipLayer.level, newLevel).apply {
addUpdateListener {
@@ -266,7 +268,7 @@ class ToggleRangeBehavior : Behavior {
private fun format(primaryFormat: String, backupFormat: String, value: Float): String {
return try {
- String.format(primaryFormat, value)
+ String.format(primaryFormat, findNearestStep(value))
} catch (e: IllegalFormatException) {
Log.w(ControlsUiController.TAG, "Illegal format in range template", e)
if (backupFormat == "") {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/Vibrations.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/Vibrations.kt
index c0f6aabe2427..29b7e985fabc 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/Vibrations.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/Vibrations.kt
@@ -20,35 +20,9 @@ import android.os.VibrationEffect
import android.os.VibrationEffect.Composition.PRIMITIVE_TICK
object Vibrations {
- private const val TOGGLE_TICK_COUNT = 40
-
- val toggleOnEffect = initToggleOnEffect()
- val toggleOffEffect = initToggleOffEffect()
val rangeEdgeEffect = initRangeEdgeEffect()
val rangeMiddleEffect = initRangeMiddleEffect()
- private fun initToggleOnEffect(): VibrationEffect {
- val composition = VibrationEffect.startComposition()
- composition.addPrimitive(PRIMITIVE_TICK, 0.05f, 200)
- var i = 0
- while (i++ < TOGGLE_TICK_COUNT) {
- composition.addPrimitive(PRIMITIVE_TICK, 0.05f, 0)
- }
- composition.addPrimitive(PRIMITIVE_TICK, 0.5f, 100)
- return composition.compose()
- }
-
- private fun initToggleOffEffect(): VibrationEffect {
- val composition = VibrationEffect.startComposition()
- composition.addPrimitive(PRIMITIVE_TICK, 0.5f, 0)
- composition.addPrimitive(PRIMITIVE_TICK, 0.05f, 100)
- var i = 0
- while (i++ < TOGGLE_TICK_COUNT) {
- composition.addPrimitive(PRIMITIVE_TICK, 0.05f, 0)
- }
- return composition.compose()
- }
-
private fun initRangeEdgeEffect(): VibrationEffect {
val composition = VibrationEffect.startComposition()
composition.addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f)
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 95a9006c854a..951dc9936e1c 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -71,7 +71,7 @@ public class DozeFactory {
DockManager dockManager, @Nullable IWallpaperManager wallpaperManager,
ProximitySensor proximitySensor,
DelayedWakeLock.Builder delayedWakeLockBuilder, @Main Handler handler,
- DelayableExecutor delayableExecutor,
+ @Main DelayableExecutor delayableExecutor,
BiometricUnlockController biometricUnlockController,
BroadcastDispatcher broadcastDispatcher, DozeHost dozeHost) {
mFalsingManager = falsingManager;
diff --git a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
index a4141b1b7cf0..bbb77504ec27 100644
--- a/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/dump/DumpManager.kt
@@ -140,6 +140,20 @@ class DumpManager @Inject constructor() {
}
}
+ @Synchronized
+ fun freezeBuffers() {
+ for (buffer in buffers.values) {
+ buffer.dumpable.freeze()
+ }
+ }
+
+ @Synchronized
+ fun unfreezeBuffers() {
+ for (buffer in buffers.values) {
+ buffer.dumpable.unfreeze()
+ }
+ }
+
private fun dumpDumpable(
dumpable: RegisteredDumpable<Dumpable>,
fd: FileDescriptor,
@@ -174,3 +188,5 @@ private data class RegisteredDumpable<T>(
val name: String,
val dumpable: T
)
+
+private const val TAG = "DumpManager" \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/dump/LogBufferFreezer.kt b/packages/SystemUI/src/com/android/systemui/dump/LogBufferFreezer.kt
new file mode 100644
index 000000000000..29f464285e5d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dump/LogBufferFreezer.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dump
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.UserHandle
+import android.util.Log
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.util.concurrency.DelayableExecutor
+import java.util.concurrent.TimeUnit
+import javax.inject.Inject
+
+class LogBufferFreezer constructor(
+ private val dumpManager: DumpManager,
+ @Main private val executor: DelayableExecutor,
+ private val freezeDuration: Long
+) {
+ @Inject constructor(
+ dumpManager: DumpManager,
+ @Main executor: DelayableExecutor
+ ) : this(dumpManager, executor, TimeUnit.MINUTES.toMillis(5))
+
+ private var pendingToken: Runnable? = null
+
+ fun attach(broadcastDispatcher: BroadcastDispatcher) {
+ broadcastDispatcher.registerReceiver(
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context?, intent: Intent?) {
+ onBugreportStarted()
+ }
+ },
+ IntentFilter("com.android.internal.intent.action.BUGREPORT_STARTED"),
+ executor,
+ UserHandle.ALL)
+ }
+
+ private fun onBugreportStarted() {
+ pendingToken?.run()
+
+ Log.i(TAG, "Freezing log buffers")
+ dumpManager.freezeBuffers()
+
+ pendingToken = executor.executeDelayed({
+ Log.i(TAG, "Unfreezing log buffers")
+ pendingToken = null
+ dumpManager.unfreezeBuffers()
+ }, freezeDuration)
+ }
+}
+
+private const val TAG = "LogBufferFreezer" \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 1b13d4a49fec..5e5ebe92e559 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -175,7 +175,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private static final String GLOBAL_ACTION_KEY_SILENT = "silent";
private static final String GLOBAL_ACTION_KEY_USERS = "users";
private static final String GLOBAL_ACTION_KEY_SETTINGS = "settings";
- private static final String GLOBAL_ACTION_KEY_LOCKDOWN = "lockdown";
+ static final String GLOBAL_ACTION_KEY_LOCKDOWN = "lockdown";
private static final String GLOBAL_ACTION_KEY_VOICEASSIST = "voiceassist";
private static final String GLOBAL_ACTION_KEY_ASSIST = "assist";
static final String GLOBAL_ACTION_KEY_RESTART = "restart";
@@ -183,8 +183,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
static final String GLOBAL_ACTION_KEY_EMERGENCY = "emergency";
static final String GLOBAL_ACTION_KEY_SCREENSHOT = "screenshot";
- private static final String PREFS_CONTROLS_SEEDING_COMPLETED = "SeedingCompleted";
- private static final String PREFS_CONTROLS_FILE = "controls_prefs";
+ public static final String PREFS_CONTROLS_SEEDING_COMPLETED = "SeedingCompleted";
+ public static final String PREFS_CONTROLS_FILE = "controls_prefs";
private static final int SEEDING_MAX = 2;
private final Context mContext;
@@ -213,7 +213,9 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
@VisibleForTesting
protected final ArrayList<Action> mItems = new ArrayList<>();
@VisibleForTesting
- final ArrayList<Action> mOverflowItems = new ArrayList<>();
+ protected final ArrayList<Action> mOverflowItems = new ArrayList<>();
+ @VisibleForTesting
+ protected final ArrayList<Action> mPowerItems = new ArrayList<>();
@VisibleForTesting
protected ActionsDialog mDialog;
@@ -223,6 +225,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private MyAdapter mAdapter;
private MyOverflowAdapter mOverflowAdapter;
+ private MyPowerOptionsAdapter mPowerAdapter;
private boolean mKeyguardShowing = false;
private boolean mDeviceProvisioned = false;
@@ -391,7 +394,15 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
if (controlsComponent.getControlsListingController().isPresent()) {
controlsComponent.getControlsListingController().get()
- .addCallback(list -> mControlsServiceInfos = list);
+ .addCallback(list -> {
+ mControlsServiceInfos = list;
+ // This callback may occur after the dialog has been shown.
+ // If so, add controls into the already visible space
+ if (mDialog != null && !mDialog.isShowingControls()
+ && shouldShowControls()) {
+ mDialog.showControls(mControlsUiControllerOptional.get());
+ }
+ });
}
// Need to be user-specific with the context to make sure we read the correct prefs
@@ -576,14 +587,19 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mItems.clear();
mOverflowItems.clear();
-
+ mPowerItems.clear();
String[] defaultActions = getDefaultActions();
+
+ ShutDownAction shutdownAction = new ShutDownAction();
+ RestartAction restartAction = new RestartAction();
+ ArraySet<String> addedKeys = new ArraySet<String>();
+
// make sure emergency affordance action is first, if needed
if (mEmergencyAffordanceManager.needsEmergencyAffordance()) {
addActionItem(new EmergencyAffordanceAction());
+ addedKeys.add(GLOBAL_ACTION_KEY_EMERGENCY);
}
- ArraySet<String> addedKeys = new ArraySet<String>();
for (int i = 0; i < defaultActions.length; i++) {
String actionKey = defaultActions[i];
if (addedKeys.contains(actionKey)) {
@@ -591,7 +607,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
continue;
}
if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) {
- addActionItem(new PowerAction());
+ addActionItem(shutdownAction);
} else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) {
addActionItem(mAirplaneModeOn);
} else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) {
@@ -610,10 +626,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
} else if (GLOBAL_ACTION_KEY_SETTINGS.equals(actionKey)) {
addActionItem(getSettingsAction());
} else if (GLOBAL_ACTION_KEY_LOCKDOWN.equals(actionKey)) {
- int userId = getCurrentUser().id;
- if (Settings.Secure.getIntForUser(mContentResolver,
- Settings.Secure.LOCKDOWN_IN_POWER_MENU, 0, userId) != 0
- && shouldDisplayLockdown(userId)) {
+ if (shouldDisplayLockdown(getCurrentUser())) {
addActionItem(getLockdownAction());
}
} else if (GLOBAL_ACTION_KEY_VOICEASSIST.equals(actionKey)) {
@@ -621,7 +634,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
} else if (GLOBAL_ACTION_KEY_ASSIST.equals(actionKey)) {
addActionItem(getAssistAction());
} else if (GLOBAL_ACTION_KEY_RESTART.equals(actionKey)) {
- addActionItem(new RestartAction());
+ addActionItem(restartAction);
} else if (GLOBAL_ACTION_KEY_SCREENSHOT.equals(actionKey)) {
addActionItem(new ScreenshotAction());
} else if (GLOBAL_ACTION_KEY_LOGOUT.equals(actionKey)) {
@@ -630,15 +643,32 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
addActionItem(new LogoutAction());
}
} else if (GLOBAL_ACTION_KEY_EMERGENCY.equals(actionKey)) {
- if (!mEmergencyAffordanceManager.needsEmergencyAffordance()) {
- addActionItem(new EmergencyDialerAction());
- }
+ addActionItem(new EmergencyDialerAction());
} else {
Log.e(TAG, "Invalid global action key " + actionKey);
}
// Add here so we don't add more than one.
addedKeys.add(actionKey);
}
+
+ // replace power and restart with a single power options action, if needed
+ if (mItems.contains(shutdownAction) && mItems.contains(restartAction)
+ && mOverflowItems.size() > 0) {
+ // transfer shutdown and restart to their own list of power actions
+ mItems.remove(shutdownAction);
+ mItems.remove(restartAction);
+ mPowerItems.add(shutdownAction);
+ mPowerItems.add(restartAction);
+
+ // add the PowerOptionsAction after Emergency, if present
+ int powerIndex = addedKeys.contains(GLOBAL_ACTION_KEY_EMERGENCY) ? 1 : 0;
+ mItems.add(powerIndex, new PowerOptionsAction());
+
+ // transfer the first overflow action to the main set of items
+ Action firstOverflowAction = mOverflowItems.get(0);
+ mOverflowItems.remove(0);
+ mItems.add(firstOverflowAction);
+ }
}
private void onRotate() {
@@ -656,6 +686,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mAdapter = new MyAdapter();
mOverflowAdapter = new MyOverflowAdapter();
+ mPowerAdapter = new MyPowerOptionsAdapter();
mDepthController.setShowingHomeControls(true);
GlobalActionsPanelPlugin.PanelViewController walletViewController =
@@ -668,7 +699,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
walletViewController, mDepthController, mSysuiColorExtractor,
mStatusBarService, mNotificationShadeWindowController,
controlsAvailable(), uiController,
- mSysUiState, this::onRotate, mKeyguardShowing);
+ mSysUiState, this::onRotate, mKeyguardShowing, mPowerAdapter);
boolean walletViewAvailable = walletViewController != null
&& walletViewController.getPanelContent() != null;
if (shouldShowLockMessage(walletViewAvailable)) {
@@ -681,7 +712,20 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
return dialog;
}
- private boolean shouldDisplayLockdown(int userId) {
+ @VisibleForTesting
+ protected boolean shouldDisplayLockdown(UserInfo user) {
+ if (user == null) {
+ return false;
+ }
+
+ int userId = user.id;
+
+ // No lockdown option if it's not turned on in Settings
+ if (Settings.Secure.getIntForUser(mContentResolver,
+ Settings.Secure.LOCKDOWN_IN_POWER_MENU, 0, userId) == 0) {
+ return false;
+ }
+
// Lockdown is meaningless without a place to go.
if (!mKeyguardStateController.isMethodSecure()) {
return false;
@@ -732,8 +776,32 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mActivityStarter.startPendingIntentDismissingKeyguard(pendingIntent);
}
- private final class PowerAction extends SinglePressAction implements LongPressAction {
- private PowerAction() {
+ @VisibleForTesting
+ protected final class PowerOptionsAction extends SinglePressAction {
+ private PowerOptionsAction() {
+ super(R.drawable.ic_lock_power_off, R.string.global_action_power_options);
+ }
+
+ @Override
+ public boolean showDuringKeyguard() {
+ return true;
+ }
+
+ @Override
+ public boolean showBeforeProvisioning() {
+ return true;
+ }
+
+ @Override
+ public void onPress() {
+ if (mDialog != null) {
+ mDialog.showPowerOptionsMenu();
+ }
+ }
+ }
+
+ private final class ShutDownAction extends SinglePressAction implements LongPressAction {
+ private ShutDownAction() {
super(R.drawable.ic_lock_power_off,
R.string.global_action_power_off);
}
@@ -764,7 +832,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
}
}
- private abstract class EmergencyAction extends SinglePressAction {
+ @VisibleForTesting
+ protected abstract class EmergencyAction extends SinglePressAction {
EmergencyAction(int iconResId, int messageResId) {
super(iconResId, messageResId);
}
@@ -1309,7 +1378,10 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
Action item = mAdapter.getItem(position);
if (!(item instanceof SilentModeTriStateAction)) {
if (mDialog != null) {
- mDialog.dismiss();
+ // don't dismiss the dialog if we're opening the power options menu
+ if (!(item instanceof PowerOptionsAction)) {
+ mDialog.dismiss();
+ }
} else {
Log.w(TAG, "Action clicked while mDialog is null.");
}
@@ -1326,6 +1398,70 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
/**
* The adapter used for items in the overflow menu.
*/
+ public class MyPowerOptionsAdapter extends BaseAdapter {
+ @Override
+ public int getCount() {
+ return mPowerItems.size();
+ }
+
+ @Override
+ public Action getItem(int position) {
+ return mPowerItems.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ Action action = getItem(position);
+ if (action == null) {
+ Log.w(TAG, "No power options action found at position: " + position);
+ return null;
+ }
+ int viewLayoutResource = com.android.systemui.R.layout.controls_more_item;
+ View view = convertView != null ? convertView
+ : LayoutInflater.from(mContext).inflate(viewLayoutResource, parent, false);
+ TextView textView = (TextView) view;
+ if (action.getMessageResId() != 0) {
+ textView.setText(action.getMessageResId());
+ } else {
+ textView.setText(action.getMessage());
+ }
+ return textView;
+ }
+
+ private boolean onLongClickItem(int position) {
+ final Action action = getItem(position);
+ if (action instanceof LongPressAction) {
+ if (mDialog != null) {
+ mDialog.dismiss();
+ } else {
+ Log.w(TAG, "Action long-clicked while mDialog is null.");
+ }
+ return ((LongPressAction) action).onLongPress();
+ }
+ return false;
+ }
+
+ private void onClickItem(int position) {
+ Action item = getItem(position);
+ if (!(item instanceof SilentModeTriStateAction)) {
+ if (mDialog != null) {
+ mDialog.dismiss();
+ } else {
+ Log.w(TAG, "Action clicked while mDialog is null.");
+ }
+ item.onPress();
+ }
+ }
+ }
+
+ /**
+ * The adapter used for items in the power options menu, triggered by the PowerOptionsAction.
+ */
public class MyOverflowAdapter extends BaseAdapter {
@Override
public int getCount() {
@@ -1365,7 +1501,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
final Action action = getItem(position);
if (action instanceof LongPressAction) {
if (mDialog != null) {
- mDialog.hidePowerOverflowMenu();
mDialog.dismiss();
} else {
Log.w(TAG, "Action long-clicked while mDialog is null.");
@@ -1379,7 +1514,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
Action item = getItem(position);
if (!(item instanceof SilentModeTriStateAction)) {
if (mDialog != null) {
- mDialog.hidePowerOverflowMenu();
mDialog.dismiss();
} else {
Log.w(TAG, "Action clicked while mDialog is null.");
@@ -1487,7 +1621,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
}
}
-
public int getMessageResId() {
return mMessageResId;
}
@@ -1838,6 +1971,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mAirplaneState = inAirplaneMode ? ToggleState.On : ToggleState.Off;
mAirplaneModeOn.updateState(mAirplaneState);
mAdapter.notifyDataSetChanged();
+ mOverflowAdapter.notifyDataSetChanged();
+ mPowerAdapter.notifyDataSetChanged();
}
};
@@ -1920,6 +2055,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private final Context mContext;
private final MyAdapter mAdapter;
private final MyOverflowAdapter mOverflowAdapter;
+ private final MyPowerOptionsAdapter mPowerOptionsAdapter;
private final IStatusBarService mStatusBarService;
private final IBinder mToken = new Binder();
private MultiListLayout mGlobalActionsLayout;
@@ -1935,6 +2071,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
private final NotificationShadeDepthController mDepthController;
private final SysUiState mSysUiState;
private ListPopupWindow mOverflowPopup;
+ private ListPopupWindow mPowerOptionsPopup;
private final Runnable mOnRotateCallback;
private final boolean mControlsAvailable;
@@ -1950,11 +2087,13 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
NotificationShadeWindowController notificationShadeWindowController,
boolean controlsAvailable, @Nullable ControlsUiController controlsUiController,
- SysUiState sysuiState, Runnable onRotateCallback, boolean keyguardShowing) {
+ SysUiState sysuiState, Runnable onRotateCallback, boolean keyguardShowing,
+ MyPowerOptionsAdapter powerAdapter) {
super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
mContext = context;
mAdapter = adapter;
mOverflowAdapter = overflowAdapter;
+ mPowerOptionsAdapter = powerAdapter;
mDepthController = depthController;
mColorExtractor = sysuiColorExtractor;
mStatusBarService = statusBarService;
@@ -2068,6 +2207,21 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
}
}
+ private ListPopupWindow createPowerOptionsPopup() {
+ GlobalActionsPopupMenu popup = new GlobalActionsPopupMenu(
+ new ContextThemeWrapper(
+ mContext,
+ com.android.systemui.R.style.Control_ListPopupWindow
+ ), false /* isDropDownMode */);
+ popup.setOnItemClickListener(
+ (parent, view, position, id) -> mPowerOptionsAdapter.onClickItem(position));
+ popup.setOnItemLongClickListener(
+ (parent, view, position, id) -> mPowerOptionsAdapter.onLongClickItem(position));
+ popup.setAnchorView(mGlobalActionsLayout);
+ popup.setAdapter(mPowerOptionsAdapter);
+ return popup;
+ }
+
private ListPopupWindow createPowerOverflowPopup() {
GlobalActionsPopupMenu popup = new GlobalActionsPopupMenu(
new ContextThemeWrapper(
@@ -2085,16 +2239,16 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
return popup;
}
+ public void showPowerOptionsMenu() {
+ mPowerOptionsPopup = createPowerOptionsPopup();
+ mPowerOptionsPopup.show();
+ }
+
private void showPowerOverflowMenu() {
mOverflowPopup = createPowerOverflowPopup();
mOverflowPopup.show();
}
- private void hidePowerOverflowMenu() {
- mOverflowPopup.dismiss();
- mOverflowPopup = null;
- }
-
private void initializeLayout() {
setContentView(com.android.systemui.R.layout.global_actions_grid_v2);
fixNavBarClipping();
@@ -2270,6 +2424,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
// close first, as popup windows will not fade during the animation
dismissOverflow(false);
+ dismissPowerOptions(false);
if (mControlsUiController != null) mControlsUiController.closeDialogs(false);
});
}
@@ -2294,6 +2449,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
resetOrientation();
dismissWallet();
dismissOverflow(true);
+ dismissPowerOptions(true);
if (mControlsUiController != null) mControlsUiController.hide();
mNotificationShadeWindowController.setForceHasTopUi(mHadTopUi);
mDepthController.updateGlobalDialogVisibility(0, null /* view */);
@@ -2318,6 +2474,16 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
}
}
+ private void dismissPowerOptions(boolean immediate) {
+ if (mPowerOptionsPopup != null) {
+ if (immediate) {
+ mPowerOptionsPopup.dismissImmediate();
+ } else {
+ mPowerOptionsPopup.dismiss();
+ }
+ }
+ }
+
private void setRotationSuggestionsEnabled(boolean enabled) {
try {
final int userId = Binder.getCallingUserHandle().getIdentifier();
@@ -2361,6 +2527,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
// ensure dropdown menus are dismissed before re-initializing the dialog
dismissWallet();
dismissOverflow(true);
+ dismissPowerOptions(true);
if (mControlsUiController != null) {
mControlsUiController.hide();
}
diff --git a/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
index 342db346e14b..78d70877a90e 100644
--- a/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/LogBuffer.kt
@@ -74,6 +74,9 @@ class LogBuffer(
) {
private val buffer: ArrayDeque<LogMessageImpl> = ArrayDeque()
+ var frozen = false
+ private set
+
fun attach(dumpManager: DumpManager) {
dumpManager.registerBuffer(name, this)
}
@@ -112,9 +115,11 @@ class LogBuffer(
initializer: LogMessage.() -> Unit,
noinline printer: LogMessage.() -> String
) {
- val message = obtain(tag, level, printer)
- initializer(message)
- push(message)
+ if (!frozen) {
+ val message = obtain(tag, level, printer)
+ initializer(message)
+ push(message)
+ }
}
/**
@@ -139,17 +144,16 @@ class LogBuffer(
*
* In general, you should call [log] or [document] instead of this method.
*/
+ @Synchronized
fun obtain(
tag: String,
level: LogLevel,
printer: (LogMessage) -> String
): LogMessageImpl {
- val message = synchronized(buffer) {
- if (buffer.size > maxLogs - poolSize) {
- buffer.removeFirst()
- } else {
- LogMessageImpl.create()
- }
+ val message = when {
+ frozen -> LogMessageImpl.create()
+ buffer.size > maxLogs - poolSize -> buffer.removeFirst()
+ else -> LogMessageImpl.create()
}
message.reset(tag, level, System.currentTimeMillis(), printer)
return message
@@ -158,33 +162,58 @@ class LogBuffer(
/**
* Pushes a message into buffer, possibly evicting an older message if the buffer is full.
*/
+ @Synchronized
fun push(message: LogMessage) {
- synchronized(buffer) {
- if (buffer.size == maxLogs) {
- Log.e(TAG, "LogBuffer $name has exceeded its pool size")
- buffer.removeFirst()
- }
- buffer.add(message as LogMessageImpl)
- if (logcatEchoTracker.isBufferLoggable(name, message.level) ||
- logcatEchoTracker.isTagLoggable(message.tag, message.level)) {
- echoToLogcat(message)
- }
+ if (frozen) {
+ return
+ }
+ if (buffer.size == maxLogs) {
+ Log.e(TAG, "LogBuffer $name has exceeded its pool size")
+ buffer.removeFirst()
+ }
+ buffer.add(message as LogMessageImpl)
+ if (logcatEchoTracker.isBufferLoggable(name, message.level) ||
+ logcatEchoTracker.isTagLoggable(message.tag, message.level)) {
+ echoToLogcat(message)
}
}
/** Converts the entire buffer to a newline-delimited string */
+ @Synchronized
fun dump(pw: PrintWriter, tailLength: Int) {
- synchronized(buffer) {
- val start = if (tailLength <= 0) { 0 } else { buffer.size - tailLength }
+ val start = if (tailLength <= 0) { 0 } else { buffer.size - tailLength }
- for ((i, message) in buffer.withIndex()) {
- if (i >= start) {
- dumpMessage(message, pw)
- }
+ for ((i, message) in buffer.withIndex()) {
+ if (i >= start) {
+ dumpMessage(message, pw)
}
}
}
+ /**
+ * "Freezes" the contents of the buffer, making them immutable until [unfreeze] is called.
+ * Calls to [log], [document], [obtain], and [push] will not affect the buffer and will return
+ * dummy values if necessary.
+ */
+ @Synchronized
+ fun freeze() {
+ if (!frozen) {
+ log(TAG, LogLevel.DEBUG, { str1 = name }, { "$str1 frozen" })
+ frozen = true
+ }
+ }
+
+ /**
+ * Undoes the effects of calling [freeze].
+ */
+ @Synchronized
+ fun unfreeze() {
+ if (frozen) {
+ log(TAG, LogLevel.DEBUG, { str1 = name }, { "$str1 unfrozen" })
+ frozen = false
+ }
+ }
+
private fun dumpMessage(message: LogMessage, pw: PrintWriter) {
pw.print(DATE_FORMAT.format(message.timestamp))
pw.print(" ")
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 5595201a670f..f039fc2d84ae 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -17,12 +17,8 @@
package com.android.systemui.media;
import android.app.PendingIntent;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -35,7 +31,6 @@ import android.graphics.drawable.RippleDrawable;
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
-import android.service.media.MediaBrowserService;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
@@ -54,16 +49,17 @@ import com.android.settingslib.Utils;
import com.android.settingslib.media.MediaOutputSliceConstants;
import com.android.settingslib.widget.AdaptiveIcon;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.qs.QSMediaBrowser;
import com.android.systemui.util.animation.TransitionLayout;
-import com.android.systemui.util.concurrency.DelayableExecutor;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.concurrent.Executor;
+import javax.inject.Inject;
+
/**
* A view controller used for Media Playback.
*/
@@ -81,7 +77,6 @@ public class MediaControlPanel {
private final SeekBarViewModel mSeekBarViewModel;
private SeekBarObserver mSeekBarObserver;
- private final Executor mForegroundExecutor;
protected final Executor mBackgroundExecutor;
private final ActivityStarter mActivityStarter;
@@ -91,51 +86,23 @@ public class MediaControlPanel {
private MediaSession.Token mToken;
private MediaController mController;
private int mBackgroundColor;
- protected ComponentName mServiceComponent;
- private boolean mIsRegistered = false;
- private String mKey;
private int mAlbumArtSize;
private int mAlbumArtRadius;
- private int mViewWidth;
-
- public static final String MEDIA_PREFERENCES = "media_control_prefs";
- public static final String MEDIA_PREFERENCE_KEY = "browser_components";
- private SharedPreferences mSharedPrefs;
- private boolean mCheckedForResumption = false;
- private QSMediaBrowser mQSMediaBrowser;
-
- private final MediaController.Callback mSessionCallback = new MediaController.Callback() {
- @Override
- public void onSessionDestroyed() {
- Log.d(TAG, "session destroyed");
- mController.unregisterCallback(mSessionCallback);
- clearControls();
- }
- @Override
- public void onPlaybackStateChanged(PlaybackState state) {
- final int s = state != null ? state.getState() : PlaybackState.STATE_NONE;
- if (s == PlaybackState.STATE_NONE) {
- Log.d(TAG, "playback state change will trigger resumption, state=" + state);
- clearControls();
- }
- }
- };
/**
* Initialize a new control panel
* @param context
- * @param foregroundExecutor foreground executor
* @param backgroundExecutor background executor, used for processing artwork
* @param activityStarter activity starter
*/
- public MediaControlPanel(Context context, Executor foregroundExecutor,
- DelayableExecutor backgroundExecutor, ActivityStarter activityStarter,
- MediaHostStatesManager mediaHostStatesManager) {
+ @Inject
+ public MediaControlPanel(Context context, @Background Executor backgroundExecutor,
+ ActivityStarter activityStarter, MediaHostStatesManager mediaHostStatesManager,
+ SeekBarViewModel seekBarViewModel) {
mContext = context;
- mForegroundExecutor = foregroundExecutor;
mBackgroundExecutor = backgroundExecutor;
mActivityStarter = activityStarter;
- mSeekBarViewModel = new SeekBarViewModel(backgroundExecutor);
+ mSeekBarViewModel = seekBarViewModel;
mMediaViewController = new MediaViewController(context, mediaHostStatesManager);
loadDimens();
}
@@ -214,45 +181,18 @@ public class MediaControlPanel {
MediaSession.Token token = data.getToken();
mBackgroundColor = data.getBackgroundColor();
if (mToken == null || !mToken.equals(token)) {
- if (mQSMediaBrowser != null) {
- Log.d(TAG, "Disconnecting old media browser");
- mQSMediaBrowser.disconnect();
- mQSMediaBrowser = null;
- }
mToken = token;
- mServiceComponent = null;
- mCheckedForResumption = false;
}
- mController = new MediaController(mContext, mToken);
+ if (mToken != null) {
+ mController = new MediaController(mContext, mToken);
+ } else {
+ mController = null;
+ }
ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
- // Try to find a browser service component for this app
- // TODO also check for a media button receiver intended for restarting (b/154127084)
- // Only check if we haven't tried yet or the session token changed
- final String pkgName = data.getPackageName();
- if (mServiceComponent == null && !mCheckedForResumption) {
- Log.d(TAG, "Checking for service component");
- PackageManager pm = mContext.getPackageManager();
- Intent resumeIntent = new Intent(MediaBrowserService.SERVICE_INTERFACE);
- List<ResolveInfo> resumeInfo = pm.queryIntentServices(resumeIntent, 0);
- // TODO: look into this resumption
- if (resumeInfo != null) {
- for (ResolveInfo inf : resumeInfo) {
- if (inf.serviceInfo.packageName.equals(mController.getPackageName())) {
- mBackgroundExecutor.execute(() ->
- tryUpdateResumptionList(inf.getComponentInfo().getComponentName()));
- break;
- }
- }
- }
- mCheckedForResumption = true;
- }
-
- mController.registerCallback(mSessionCallback);
-
mViewHolder.getPlayer().setBackgroundTintList(
ColorStateList.valueOf(mBackgroundColor));
@@ -267,12 +207,22 @@ public class MediaControlPanel {
ImageView albumView = mViewHolder.getAlbumView();
// TODO: migrate this to a view with rounded corners instead of baking the rounding
// into the bitmap
- Drawable artwork = createRoundedBitmap(data.getArtwork());
- albumView.setImageDrawable(artwork);
+ boolean hasArtwork = data.getArtwork() != null;
+ if (hasArtwork) {
+ Drawable artwork = createRoundedBitmap(data.getArtwork());
+ albumView.setImageDrawable(artwork);
+ }
+ setVisibleAndAlpha(collapsedSet, R.id.album_art, hasArtwork);
+ setVisibleAndAlpha(expandedSet, R.id.album_art, hasArtwork);
// App icon
ImageView appIcon = mViewHolder.getAppIcon();
- appIcon.setImageDrawable(data.getAppIcon());
+ if (data.getAppIcon() != null) {
+ appIcon.setImageDrawable(data.getAppIcon());
+ } else {
+ Drawable iconDrawable = mContext.getDrawable(R.drawable.ic_music_note);
+ appIcon.setImageDrawable(iconDrawable);
+ }
// Song name
TextView titleText = mViewHolder.getTitleText();
@@ -294,7 +244,7 @@ public class MediaControlPanel {
final Intent intent = new Intent()
.setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT)
.putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME,
- mController.getPackageName())
+ data.getPackageName())
.putExtra(MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN, mToken);
mActivityStarter.startActivity(intent, false, true /* dismissShade */,
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
@@ -350,15 +300,11 @@ public class MediaControlPanel {
MediaAction mediaAction = actionIcons.get(i);
button.setImageDrawable(mediaAction.getDrawable());
button.setContentDescription(mediaAction.getContentDescription());
- PendingIntent actionIntent = mediaAction.getIntent();
+ Runnable action = mediaAction.getAction();
button.setOnClickListener(v -> {
- if (actionIntent != null) {
- try {
- actionIntent.send();
- } catch (PendingIntent.CanceledException e) {
- e.printStackTrace();
- }
+ if (action != null) {
+ action.run();
}
});
boolean visibleInCompat = actionsWhenCollapsed.contains(i);
@@ -444,14 +390,6 @@ public class MediaControlPanel {
}
/**
- * Return the original notification's key
- * @return The notification key
- */
- public String getKey() {
- return mKey;
- }
-
- /**
* Check whether this player has an attached media session.
* @return whether there is a controller with a current media session.
*/
@@ -485,150 +423,8 @@ public class MediaControlPanel {
return (state.getState() == PlaybackState.STATE_PLAYING);
}
- /**
- * Puts controls into a resumption state if possible, or calls removePlayer if no component was
- * found that could resume playback
- */
- public void clearControls() {
- Log.d(TAG, "clearControls to resumption state package=" + getMediaPlayerPackage());
- if (mServiceComponent == null) {
- // If we don't have a way to resume, just remove the player altogether
- Log.d(TAG, "Removing unresumable controls");
- removePlayer();
- return;
- }
- resetButtons();
- }
-
- /**
- * Hide the media buttons and show only a restart button
- */
- protected void resetButtons() {
- if (mViewHolder == null) {
- return;
- }
- // Hide all the old buttons
-
- ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
- ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
- for (int i = 1; i < ACTION_IDS.length; i++) {
- setVisibleAndAlpha(expandedSet, ACTION_IDS[i], false /*visible */);
- setVisibleAndAlpha(collapsedSet, ACTION_IDS[i], false /*visible */);
- }
-
- // Add a restart button
- ImageButton btn = mViewHolder.getAction0();
- btn.setOnClickListener(v -> {
- Log.d(TAG, "Attempting to restart session");
- if (mQSMediaBrowser != null) {
- mQSMediaBrowser.disconnect();
- }
- mQSMediaBrowser = new QSMediaBrowser(mContext, new QSMediaBrowser.Callback(){
- @Override
- public void onConnected() {
- Log.d(TAG, "Successfully restarted");
- }
- @Override
- public void onError() {
- Log.e(TAG, "Error restarting");
- mQSMediaBrowser.disconnect();
- mQSMediaBrowser = null;
- }
- }, mServiceComponent);
- mQSMediaBrowser.restart();
- });
- btn.setImageDrawable(mContext.getResources().getDrawable(R.drawable.lb_ic_play));
- setVisibleAndAlpha(expandedSet, ACTION_IDS[0], true /*visible */);
- setVisibleAndAlpha(collapsedSet, ACTION_IDS[0], true /*visible */);
-
- mSeekBarViewModel.clearController();
- // TODO: fix guts
- // View guts = mMediaNotifView.findViewById(R.id.media_guts);
- View options = mViewHolder.getOptions();
-
- mViewHolder.getPlayer().setOnLongClickListener(v -> {
- // Replace player view with close/cancel view
-// guts.setVisibility(View.GONE);
- options.setVisibility(View.VISIBLE);
- return true; // consumed click
- });
- mMediaViewController.refreshState();
- }
-
private void setVisibleAndAlpha(ConstraintSet set, int actionId, boolean visible) {
set.setVisibility(actionId, visible? ConstraintSet.VISIBLE : ConstraintSet.GONE);
set.setAlpha(actionId, visible ? 1.0f : 0.0f);
}
-
- /**
- * Verify that we can connect to the given component with a MediaBrowser, and if so, add that
- * component to the list of resumption components
- */
- private void tryUpdateResumptionList(ComponentName componentName) {
- Log.d(TAG, "Testing if we can connect to " + componentName);
- if (mQSMediaBrowser != null) {
- mQSMediaBrowser.disconnect();
- }
- mQSMediaBrowser = new QSMediaBrowser(mContext,
- new QSMediaBrowser.Callback() {
- @Override
- public void onConnected() {
- Log.d(TAG, "yes we can resume with " + componentName);
- mServiceComponent = componentName;
- updateResumptionList(componentName);
- mQSMediaBrowser.disconnect();
- mQSMediaBrowser = null;
- }
-
- @Override
- public void onError() {
- Log.d(TAG, "Cannot resume with " + componentName);
- mServiceComponent = null;
- if (!hasMediaSession()) {
- // If it's not active and we can't resume, remove
- removePlayer();
- }
- mQSMediaBrowser.disconnect();
- mQSMediaBrowser = null;
- }
- },
- componentName);
- mQSMediaBrowser.testConnection();
- }
-
- /**
- * Add the component to the saved list of media browser services, checking for duplicates and
- * removing older components that exceed the maximum limit
- * @param componentName
- */
- private synchronized void updateResumptionList(ComponentName componentName) {
- // Add to front of saved list
- if (mSharedPrefs == null) {
- mSharedPrefs = mContext.getSharedPreferences(MEDIA_PREFERENCES, 0);
- }
- String componentString = componentName.flattenToString();
- String listString = mSharedPrefs.getString(MEDIA_PREFERENCE_KEY, null);
- if (listString == null) {
- listString = componentString;
- } else {
- String[] components = listString.split(QSMediaBrowser.DELIMITER);
- StringBuilder updated = new StringBuilder(componentString);
- int nBrowsers = 1;
- for (int i = 0; i < components.length
- && nBrowsers < QSMediaBrowser.MAX_RESUMPTION_CONTROLS; i++) {
- if (componentString.equals(components[i])) {
- continue;
- }
- updated.append(QSMediaBrowser.DELIMITER).append(components[i]);
- nBrowsers++;
- }
- listString = updated.toString();
- }
- mSharedPrefs.edit().putString(MEDIA_PREFERENCE_KEY, listString).apply();
- }
-
- /**
- * Called when a player can't be resumed to give it an opportunity to hide or remove itself
- */
- protected void removePlayer() { }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
index a94f6a87d58a..5d28178a3b1b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaData.kt
@@ -32,17 +32,19 @@ data class MediaData(
val artwork: Icon?,
val actions: List<MediaAction>,
val actionsToShowInCompact: List<Int>,
- val packageName: String?,
+ val packageName: String,
val token: MediaSession.Token?,
val clickIntent: PendingIntent?,
val device: MediaDeviceData?,
- val notificationKey: String = "INVALID"
+ var resumeAction: Runnable?,
+ val notificationKey: String = "INVALID",
+ var hasCheckedForResume: Boolean = false
)
/** State of a media action. */
data class MediaAction(
val drawable: Drawable?,
- val intent: PendingIntent?,
+ val action: Runnable?,
val contentDescription: CharSequence?
)
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt
index cce9838bb8e2..11cbc482459a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt
@@ -32,9 +32,15 @@ class MediaDataCombineLatest @Inject constructor(
init {
dataSource.addListener(object : MediaDataManager.Listener {
- override fun onMediaDataLoaded(key: String, data: MediaData) {
- entries[key] = data to entries[key]?.second
- update(key)
+ override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
+ if (oldKey != null && !oldKey.equals(key)) {
+ val s = entries[oldKey]?.second
+ entries[key] = data to entries[oldKey]?.second
+ entries.remove(oldKey)
+ } else {
+ entries[key] = data to entries[key]?.second
+ }
+ update(key, oldKey)
}
override fun onMediaDataRemoved(key: String) {
remove(key)
@@ -43,7 +49,7 @@ class MediaDataCombineLatest @Inject constructor(
deviceSource.addListener(object : MediaDeviceManager.Listener {
override fun onMediaDeviceChanged(key: String, data: MediaDeviceData?) {
entries[key] = entries[key]?.first to data
- update(key)
+ update(key, key)
}
override fun onKeyRemoved(key: String) {
remove(key)
@@ -61,19 +67,21 @@ class MediaDataCombineLatest @Inject constructor(
*/
fun removeListener(listener: MediaDataManager.Listener) = listeners.remove(listener)
- private fun update(key: String) {
+ private fun update(key: String, oldKey: String?) {
val (entry, device) = entries[key] ?: null to null
if (entry != null && device != null) {
val data = entry.copy(device = device)
- listeners.forEach {
- it.onMediaDataLoaded(key, data)
+ val listenersCopy = listeners.toSet()
+ listenersCopy.forEach {
+ it.onMediaDataLoaded(key, oldKey, data)
}
}
}
private fun remove(key: String) {
entries.remove(key)?.let {
- listeners.forEach {
+ val listenersCopy = listeners.toSet()
+ listenersCopy.forEach {
it.onMediaDataRemoved(key)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index d94985703083..094c5bef3c18 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -17,6 +17,7 @@
package com.android.systemui.media
import android.app.Notification
+import android.app.PendingIntent
import android.content.ContentResolver
import android.content.Context
import android.graphics.Bitmap
@@ -25,6 +26,7 @@ import android.graphics.Color
import android.graphics.ImageDecoder
import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
+import android.media.MediaDescription
import android.media.MediaMetadata
import android.media.session.MediaSession
import android.net.Uri
@@ -32,8 +34,10 @@ import android.service.notification.StatusBarNotification
import android.text.TextUtils
import android.util.Log
import com.android.internal.graphics.ColorUtils
+import com.android.systemui.R
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.statusbar.NotificationMediaManager
import com.android.systemui.statusbar.notification.MediaNotificationProcessor
import com.android.systemui.statusbar.notification.NotificationEntryManager
import com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON
@@ -58,7 +62,7 @@ private const val LUMINOSITY_THRESHOLD = 0.05f
private const val SATURATION_MULTIPLIER = 0.8f
private val LOADING = MediaData(false, 0, null, null, null, null, null,
- emptyList(), emptyList(), null, null, null, null)
+ emptyList(), emptyList(), "INVALID", null, null, null, null)
fun isMediaNotification(sbn: StatusBarNotification): Boolean {
if (!sbn.notification.hasMediaSession()) {
@@ -81,34 +85,92 @@ class MediaDataManager @Inject constructor(
private val mediaControllerFactory: MediaControllerFactory,
private val mediaTimeoutListener: MediaTimeoutListener,
private val notificationEntryManager: NotificationEntryManager,
+ private val mediaResumeListener: MediaResumeListener,
@Background private val backgroundExecutor: Executor,
@Main private val foregroundExecutor: Executor
) {
private val listeners: MutableSet<Listener> = mutableSetOf()
private val mediaEntries: LinkedHashMap<String, MediaData> = LinkedHashMap()
+ private val useMediaResumption: Boolean = Utils.useMediaResumption(context)
init {
mediaTimeoutListener.timeoutCallback = { token: String, timedOut: Boolean ->
setTimedOut(token, timedOut) }
addListener(mediaTimeoutListener)
+
+ if (useMediaResumption) {
+ mediaResumeListener.addTrackToResumeCallback = { desc: MediaDescription,
+ resumeAction: Runnable, token: MediaSession.Token, appName: String,
+ appIntent: PendingIntent, packageName: String ->
+ addResumptionControls(desc, resumeAction, token, appName, appIntent, packageName)
+ }
+ mediaResumeListener.resumeComponentFoundCallback = { key: String, action: Runnable? ->
+ mediaEntries.get(key)?.resumeAction = action
+ mediaEntries.get(key)?.hasCheckedForResume = true
+ }
+ addListener(mediaResumeListener)
+ }
}
fun onNotificationAdded(key: String, sbn: StatusBarNotification) {
if (Utils.useQsMediaPlayer(context) && isMediaNotification(sbn)) {
Assert.isMainThread()
- if (!mediaEntries.containsKey(key)) {
- mediaEntries.put(key, LOADING)
+ val oldKey = findExistingEntry(key, sbn.packageName)
+ if (oldKey == null) {
+ val temp = LOADING.copy(packageName = sbn.packageName)
+ mediaEntries.put(key, temp)
+ } else if (oldKey != key) {
+ // Move to new key
+ val oldData = mediaEntries.remove(oldKey)!!
+ mediaEntries.put(key, oldData)
}
- loadMediaData(key, sbn)
+ loadMediaData(key, sbn, oldKey)
} else {
onNotificationRemoved(key)
}
}
- private fun loadMediaData(key: String, sbn: StatusBarNotification) {
+ private fun addResumptionControls(
+ desc: MediaDescription,
+ action: Runnable,
+ token: MediaSession.Token,
+ appName: String,
+ appIntent: PendingIntent,
+ packageName: String
+ ) {
+ // Resume controls don't have a notification key, so store by package name instead
+ if (!mediaEntries.containsKey(packageName)) {
+ val resumeData = LOADING.copy(packageName = packageName, resumeAction = action)
+ mediaEntries.put(packageName, resumeData)
+ }
backgroundExecutor.execute {
- loadMediaDataInBg(key, sbn)
+ loadMediaDataInBg(desc, action, token, appName, appIntent, packageName)
+ }
+ }
+
+ /**
+ * Check if there is an existing entry that matches the key or package name.
+ * Returns the key that matches, or null if not found.
+ */
+ private fun findExistingEntry(key: String, packageName: String): String? {
+ if (mediaEntries.containsKey(key)) {
+ return key
+ }
+ // Check if we already had a resume player
+ if (mediaEntries.containsKey(packageName)) {
+ return packageName
+ }
+ return null
+ }
+
+ private fun loadMediaData(
+ key: String,
+ sbn: StatusBarNotification,
+ oldKey: String?
+ ) {
+ backgroundExecutor.execute {
+ loadMediaDataInBg(key, sbn, oldKey)
}
}
@@ -132,7 +194,50 @@ class MediaDataManager @Inject constructor(
}
}
- private fun loadMediaDataInBg(key: String, sbn: StatusBarNotification) {
+ private fun loadMediaDataInBg(
+ desc: MediaDescription,
+ resumeAction: Runnable,
+ token: MediaSession.Token,
+ appName: String,
+ appIntent: PendingIntent,
+ packageName: String
+ ) {
+ if (resumeAction == null) {
+ Log.e(TAG, "Resume action cannot be null")
+ return
+ }
+
+ if (TextUtils.isEmpty(desc.title)) {
+ Log.e(TAG, "Description incomplete")
+ return
+ }
+
+ Log.d(TAG, "adding track from browser: $desc")
+
+ // Album art
+ var artworkBitmap = desc.iconBitmap
+ if (artworkBitmap == null && desc.iconUri != null) {
+ artworkBitmap = loadBitmapFromUri(desc.iconUri!!)
+ }
+ val artworkIcon = if (artworkBitmap != null) {
+ Icon.createWithBitmap(artworkBitmap)
+ } else {
+ null
+ }
+
+ val mediaAction = getResumeMediaAction(resumeAction)
+ foregroundExecutor.execute {
+ onMediaDataLoaded(packageName, null, MediaData(true, Color.DKGRAY, appName,
+ null, desc.subtitle, desc.title, artworkIcon, listOf(mediaAction), listOf(0),
+ packageName, token, appIntent, null, resumeAction, packageName))
+ }
+ }
+
+ private fun loadMediaDataInBg(
+ key: String,
+ sbn: StatusBarNotification,
+ oldKey: String?
+ ) {
val token = sbn.notification.extras.getParcelable(Notification.EXTRA_MEDIA_SESSION)
as MediaSession.Token?
val metadata = mediaControllerFactory.create(token).metadata
@@ -234,16 +339,23 @@ class MediaDataManager @Inject constructor(
}
val mediaAction = MediaAction(
action.getIcon().loadDrawable(packageContext),
- action.actionIntent,
+ Runnable {
+ try {
+ action.actionIntent.send()
+ } catch (e: PendingIntent.CanceledException) {
+ Log.d(TAG, "Intent canceled", e)
+ }
+ },
action.title)
actionIcons.add(mediaAction)
}
}
+ val resumeAction: Runnable? = mediaEntries.get(key)?.resumeAction
foregroundExecutor.execute {
- onMediaDataLoaded(key, MediaData(true, bgColor, app, smallIconDrawable, artist, song,
- artWorkIcon, actionIcons, actionsToShowCollapsed, sbn.packageName, token,
- notif.contentIntent, null, key))
+ onMediaDataLoaded(key, oldKey, MediaData(true, bgColor, app, smallIconDrawable, artist,
+ song, artWorkIcon, actionIcons, actionsToShowCollapsed, sbn.packageName, token,
+ notif.contentIntent, null, resumeAction, key))
}
}
@@ -257,7 +369,7 @@ class MediaDataManager @Inject constructor(
val albumArt = loadBitmapFromUri(Uri.parse(uriString))
if (albumArt != null) {
Log.d(TAG, "loaded art from $uri")
- break
+ return albumArt
}
}
}
@@ -283,27 +395,52 @@ class MediaDataManager @Inject constructor(
val source = ImageDecoder.createSource(context.getContentResolver(), uri)
return try {
- ImageDecoder.decodeBitmap(source)
+ ImageDecoder.decodeBitmap(source) {
+ decoder, info, source -> decoder.isMutableRequired = true
+ }
} catch (e: IOException) {
e.printStackTrace()
null
}
}
- fun onMediaDataLoaded(key: String, data: MediaData) {
+ private fun getResumeMediaAction(action: Runnable): MediaAction {
+ return MediaAction(
+ context.getDrawable(R.drawable.lb_ic_play),
+ action,
+ context.getString(R.string.controls_media_resume)
+ )
+ }
+
+ fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
Assert.isMainThread()
if (mediaEntries.containsKey(key)) {
// Otherwise this was removed already
mediaEntries.put(key, data)
val listenersCopy = listeners.toSet()
listenersCopy.forEach {
- it.onMediaDataLoaded(key, data)
+ it.onMediaDataLoaded(key, oldKey, data)
}
}
}
fun onNotificationRemoved(key: String) {
Assert.isMainThread()
+ if (useMediaResumption && mediaEntries.get(key)?.resumeAction != null) {
+ Log.d(TAG, "Not removing $key because resumable")
+ // Move to resume key aka package name
+ val data = mediaEntries.remove(key)!!
+ val resumeAction = getResumeMediaAction(data.resumeAction!!)
+ val updated = data.copy(token = null, actions = listOf(resumeAction),
+ actionsToShowInCompact = listOf(0))
+ mediaEntries.put(data.packageName, updated)
+ // Notify listeners of "new" controls
+ val listenersCopy = listeners.toSet()
+ listenersCopy.forEach {
+ it.onMediaDataLoaded(data.packageName, key, updated)
+ }
+ return
+ }
val removed = mediaEntries.remove(key)
if (removed != null) {
val listenersCopy = listeners.toSet()
@@ -316,19 +453,32 @@ class MediaDataManager @Inject constructor(
/**
* Are there any media notifications active?
*/
- fun hasActiveMedia() = mediaEntries.isNotEmpty()
+ fun hasActiveMedia() = mediaEntries.any({ isActive(it.value) })
- fun hasAnyMedia(): Boolean {
- // TODO: implement this when we implemented resumption
- return hasActiveMedia()
+ fun isActive(data: MediaData): Boolean {
+ if (data.token == null) {
+ return false
+ }
+ val controller = mediaControllerFactory.create(data.token)
+ val state = controller?.playbackState?.state
+ return state != null && NotificationMediaManager.isActiveState(state)
}
+ /**
+ * Are there any media entries, including resume controls?
+ */
+ fun hasAnyMedia() = mediaEntries.isNotEmpty()
+
interface Listener {
/**
- * Called whenever there's new MediaData Loaded for the consumption in views
+ * Called whenever there's new MediaData Loaded for the consumption in views.
+ *
+ * oldKey is provided to check whether the view has changed keys, which can happen when a
+ * player has gone from resume state (key is package name) to active state (key is
+ * notification key) or vice versa.
*/
- fun onMediaDataLoaded(key: String, data: MediaData) {}
+ fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {}
/**
* Called whenever a previously existing Media notification was removed
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
index 552fea63a278..2f521ea39242 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
@@ -16,11 +16,8 @@
package com.android.systemui.media
-import android.app.Notification
import android.content.Context
-import android.service.notification.StatusBarNotification
import android.media.MediaRouter2Manager
-import android.media.session.MediaSession
import android.media.session.MediaController
import com.android.settingslib.media.LocalMediaManager
import com.android.settingslib.media.MediaDevice
@@ -38,11 +35,16 @@ class MediaDeviceManager @Inject constructor(
private val localMediaManagerFactory: LocalMediaManagerFactory,
private val mr2manager: MediaRouter2Manager,
private val featureFlag: MediaFeatureFlag,
- @Main private val fgExecutor: Executor
-) {
+ @Main private val fgExecutor: Executor,
+ private val mediaDataManager: MediaDataManager
+) : MediaDataManager.Listener {
private val listeners: MutableSet<Listener> = mutableSetOf()
private val entries: MutableMap<String, Token> = mutableMapOf()
+ init {
+ mediaDataManager.addListener(this)
+ }
+
/**
* Add a listener for changes to the media route (ie. device).
*/
@@ -53,23 +55,25 @@ class MediaDeviceManager @Inject constructor(
*/
fun removeListener(listener: Listener) = listeners.remove(listener)
- fun onNotificationAdded(key: String, sbn: StatusBarNotification) {
- if (featureFlag.enabled && isMediaNotification(sbn)) {
+ override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
+ if (featureFlag.enabled) {
+ if (oldKey != null && oldKey != key) {
+ val oldToken = entries.remove(oldKey)
+ oldToken?.stop()
+ }
var tok = entries[key]
- if (tok == null) {
- val token = sbn.notification.extras.getParcelable(Notification.EXTRA_MEDIA_SESSION)
- as MediaSession.Token?
- val controller = MediaController(context, token)
- tok = Token(key, controller, localMediaManagerFactory.create(sbn.packageName))
+ if (tok == null && data.token != null) {
+ val controller = MediaController(context, data.token!!)
+ tok = Token(key, controller, localMediaManagerFactory.create(data.packageName))
entries[key] = tok
tok.start()
}
} else {
- onNotificationRemoved(key)
+ onMediaDataRemoved(key)
}
}
- fun onNotificationRemoved(key: String) {
+ override fun onMediaDataRemoved(key: String) {
val token = entries.remove(key)
token?.stop()
token?.let {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
index e904e935b0e0..2bd8c0cbeab2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
@@ -50,7 +50,7 @@ class MediaHost @Inject constructor(
}
private val listener = object : MediaDataManager.Listener {
- override fun onMediaDataLoaded(key: String, data: MediaData) {
+ override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
updateViewVisibility()
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
new file mode 100644
index 000000000000..6bbe0d1651dd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media
+
+import android.app.PendingIntent
+import android.content.BroadcastReceiver
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.PackageManager
+import android.media.MediaDescription
+import android.media.session.MediaController
+import android.media.session.MediaSession
+import android.os.UserHandle
+import android.service.media.MediaBrowserService
+import android.util.Log
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.util.Utils
+import java.util.concurrent.ConcurrentLinkedQueue
+import java.util.concurrent.Executor
+import javax.inject.Inject
+import javax.inject.Singleton
+
+private const val TAG = "MediaResumeListener"
+
+private const val MEDIA_PREFERENCES = "media_control_prefs"
+private const val MEDIA_PREFERENCE_KEY = "browser_components"
+
+@Singleton
+class MediaResumeListener @Inject constructor(
+ private val context: Context,
+ private val broadcastDispatcher: BroadcastDispatcher,
+ @Background private val backgroundExecutor: Executor
+) : MediaDataManager.Listener {
+
+ private val useMediaResumption: Boolean = Utils.useMediaResumption(context)
+ private val resumeComponents: ConcurrentLinkedQueue<ComponentName> = ConcurrentLinkedQueue()
+
+ lateinit var addTrackToResumeCallback: (
+ MediaDescription,
+ Runnable,
+ MediaSession.Token,
+ String,
+ PendingIntent,
+ String
+ ) -> Unit
+ lateinit var resumeComponentFoundCallback: (String, Runnable?) -> Unit
+
+ private var mediaBrowser: ResumeMediaBrowser? = null
+
+ private val unlockReceiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ if (Intent.ACTION_USER_UNLOCKED == intent.action) {
+ loadMediaResumptionControls()
+ }
+ }
+ }
+
+ private val mediaBrowserCallback = object : ResumeMediaBrowser.Callback() {
+ override fun addTrack(
+ desc: MediaDescription,
+ component: ComponentName,
+ browser: ResumeMediaBrowser
+ ) {
+ val token = browser.token
+ val appIntent = browser.appIntent
+ val pm = context.getPackageManager()
+ var appName: CharSequence = component.packageName
+ val resumeAction = getResumeAction(component)
+ try {
+ appName = pm.getApplicationLabel(
+ pm.getApplicationInfo(component.packageName, 0))
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.e(TAG, "Error getting package information", e)
+ }
+
+ Log.d(TAG, "Adding resume controls $desc")
+ addTrackToResumeCallback(desc, resumeAction, token, appName.toString(), appIntent,
+ component.packageName)
+ }
+ }
+
+ init {
+ if (useMediaResumption) {
+ val unlockFilter = IntentFilter()
+ unlockFilter.addAction(Intent.ACTION_USER_UNLOCKED)
+ broadcastDispatcher.registerReceiver(unlockReceiver, unlockFilter, null, UserHandle.ALL)
+ loadSavedComponents()
+ }
+ }
+
+ private fun loadSavedComponents() {
+ val userContext = context.createContextAsUser(context.getUser(), 0)
+ val prefs = userContext.getSharedPreferences(MEDIA_PREFERENCES, Context.MODE_PRIVATE)
+ val listString = prefs.getString(MEDIA_PREFERENCE_KEY, null)
+ val components = listString?.split(ResumeMediaBrowser.DELIMITER.toRegex())
+ ?.dropLastWhile { it.isEmpty() }
+ components?.forEach {
+ val info = it.split("/")
+ val packageName = info[0]
+ val className = info[1]
+ val component = ComponentName(packageName, className)
+ resumeComponents.add(component)
+ }
+ Log.d(TAG, "loaded resume components ${resumeComponents.toArray().contentToString()}")
+ }
+
+ /**
+ * Load controls for resuming media, if available
+ */
+ private fun loadMediaResumptionControls() {
+ if (!useMediaResumption) {
+ return
+ }
+
+ resumeComponents.forEach {
+ val browser = ResumeMediaBrowser(context, mediaBrowserCallback, it)
+ browser.findRecentMedia()
+ }
+ broadcastDispatcher.unregisterReceiver(unlockReceiver) // only need to load once
+ }
+
+ override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
+ if (useMediaResumption) {
+ // If this had been started from a resume state, disconnect now that it's live
+ mediaBrowser?.disconnect()
+ // If we don't have a resume action, check if we haven't already
+ if (data.resumeAction == null && !data.hasCheckedForResume) {
+ // TODO also check for a media button receiver intended for restarting (b/154127084)
+ Log.d(TAG, "Checking for service component for " + data.packageName)
+ val pm = context.packageManager
+ val serviceIntent = Intent(MediaBrowserService.SERVICE_INTERFACE)
+ val resumeInfo = pm.queryIntentServices(serviceIntent, 0)
+
+ val inf = resumeInfo?.filter {
+ it.serviceInfo.packageName == data.packageName
+ }
+ if (inf != null && inf.size > 0) {
+ backgroundExecutor.execute {
+ tryUpdateResumptionList(key, inf!!.get(0).componentInfo.componentName)
+ }
+ } else {
+ // No service found
+ resumeComponentFoundCallback(key, null)
+ }
+ }
+ }
+ }
+
+ /**
+ * Verify that we can connect to the given component with a MediaBrowser, and if so, add that
+ * component to the list of resumption components
+ */
+ private fun tryUpdateResumptionList(key: String, componentName: ComponentName) {
+ Log.d(TAG, "Testing if we can connect to $componentName")
+ mediaBrowser?.disconnect()
+ mediaBrowser = ResumeMediaBrowser(context,
+ object : ResumeMediaBrowser.Callback() {
+ override fun onConnected() {
+ Log.d(TAG, "yes we can resume with $componentName")
+ resumeComponentFoundCallback(key, getResumeAction(componentName))
+ updateResumptionList(componentName)
+ mediaBrowser?.disconnect()
+ mediaBrowser = null
+ }
+
+ override fun onError() {
+ Log.e(TAG, "Cannot resume with $componentName")
+ resumeComponentFoundCallback(key, null)
+ mediaBrowser?.disconnect()
+ mediaBrowser = null
+ }
+ },
+ componentName)
+ mediaBrowser?.testConnection()
+ }
+
+ /**
+ * Add the component to the saved list of media browser services, checking for duplicates and
+ * removing older components that exceed the maximum limit
+ * @param componentName
+ */
+ private fun updateResumptionList(componentName: ComponentName) {
+ // Remove if exists
+ resumeComponents.remove(componentName)
+ // Insert at front of queue
+ resumeComponents.add(componentName)
+ // Remove old components if over the limit
+ if (resumeComponents.size > ResumeMediaBrowser.MAX_RESUMPTION_CONTROLS) {
+ resumeComponents.remove()
+ }
+
+ // Save changes
+ val sb = StringBuilder()
+ resumeComponents.forEach {
+ sb.append(it.flattenToString())
+ sb.append(ResumeMediaBrowser.DELIMITER)
+ }
+ val userContext = context.createContextAsUser(context.getUser(), 0)
+ val prefs = userContext.getSharedPreferences(MEDIA_PREFERENCES, Context.MODE_PRIVATE)
+ prefs.edit().putString(MEDIA_PREFERENCE_KEY, sb.toString()).apply()
+ }
+
+ /**
+ * Get a runnable which will resume media playback
+ */
+ private fun getResumeAction(componentName: ComponentName): Runnable {
+ return Runnable {
+ mediaBrowser?.disconnect()
+ mediaBrowser = ResumeMediaBrowser(context,
+ object : ResumeMediaBrowser.Callback() {
+ override fun onConnected() {
+ if (mediaBrowser?.token == null) {
+ Log.e(TAG, "Error after connect")
+ mediaBrowser?.disconnect()
+ mediaBrowser = null
+ return
+ }
+ Log.d(TAG, "Connected for restart $componentName")
+ val controller = MediaController(context, mediaBrowser!!.token)
+ val controls = controller.transportControls
+ controls.prepare()
+ controls.play()
+ }
+
+ override fun onError() {
+ Log.e(TAG, "Resume failed for $componentName")
+ mediaBrowser?.disconnect()
+ mediaBrowser = null
+ }
+ },
+ componentName)
+ mediaBrowser?.restart()
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
index 92a1ab1b1871..3c3f4a977ee7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
@@ -45,7 +45,7 @@ class MediaTimeoutListener @Inject constructor(
lateinit var timeoutCallback: (String, Boolean) -> Unit
- override fun onMediaDataLoaded(key: String, data: MediaData) {
+ override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
if (mediaListeners.containsKey(key)) {
return
}
@@ -67,27 +67,35 @@ class MediaTimeoutListener @Inject constructor(
var timedOut = false
- private val mediaController = mediaControllerFactory.create(data.token)
+ // Resume controls may have null token
+ private val mediaController = if (data.token != null) {
+ mediaControllerFactory.create(data.token)
+ } else {
+ null
+ }
private var cancellation: Runnable? = null
init {
- mediaController.registerCallback(this)
+ mediaController?.registerCallback(this)
}
fun destroy() {
- mediaController.unregisterCallback(this)
+ mediaController?.unregisterCallback(this)
}
override fun onPlaybackStateChanged(state: PlaybackState?) {
if (DEBUG) {
Log.v(TAG, "onPlaybackStateChanged: $state")
}
- expireMediaTimeout(key, "playback state ativity - $state, $key")
if (state == null || !isPlayingState(state.state)) {
if (DEBUG) {
Log.v(TAG, "schedule timeout for $key")
}
+ if (cancellation != null) {
+ if (DEBUG) Log.d(TAG, "cancellation already exists, continuing.")
+ return
+ }
expireMediaTimeout(key, "PLAYBACK STATE CHANGED - $state")
cancellation = mainExecutor.executeDelayed({
cancellation = null
@@ -98,6 +106,7 @@ class MediaTimeoutListener @Inject constructor(
timeoutCallback(key, timedOut)
}, PAUSED_MEDIA_TIMEOUT)
} else {
+ expireMediaTimeout(key, "playback started - $state, $key")
timedOut = false
timeoutCallback(key, timedOut)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewManager.kt
index 8ab30c75c7eb..9b9a6b4b13ab 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewManager.kt
@@ -11,16 +11,12 @@ import android.widget.HorizontalScrollView
import android.widget.LinearLayout
import androidx.core.view.GestureDetectorCompat
import com.android.systemui.R
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.qs.PageIndicator
import com.android.systemui.statusbar.notification.VisualStabilityManager
import com.android.systemui.util.animation.UniqueObjectHostView
import com.android.systemui.util.animation.requiresRemeasuring
-import com.android.systemui.util.concurrency.DelayableExecutor
-import java.util.concurrent.Executor
import javax.inject.Inject
+import javax.inject.Provider
import javax.inject.Singleton
private const val FLING_SLOP = 1000000
@@ -32,10 +28,8 @@ private const val FLING_SLOP = 1000000
@Singleton
class MediaViewManager @Inject constructor(
private val context: Context,
- @Main private val foregroundExecutor: Executor,
- @Background private val backgroundExecutor: DelayableExecutor,
+ private val mediaControlPanelFactory: Provider<MediaControlPanel>,
private val visualStabilityManager: VisualStabilityManager,
- private val activityStarter: ActivityStarter,
private val mediaHostStatesManager: MediaHostStatesManager,
mediaManager: MediaDataCombineLatest
) {
@@ -147,8 +141,8 @@ class MediaViewManager @Inject constructor(
visualStabilityManager.addReorderingAllowedCallback(visualStabilityCallback,
true /* persistent */)
mediaManager.addListener(object : MediaDataManager.Listener {
- override fun onMediaDataLoaded(key: String, data: MediaData) {
- updateView(key, data)
+ override fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {
+ updateView(key, oldKey, data)
updatePlayerVisibilities()
mediaCarousel.requiresRemeasuring = true
}
@@ -259,11 +253,16 @@ class MediaViewManager @Inject constructor(
}
}
- private fun updateView(key: String, data: MediaData) {
+ private fun updateView(key: String, oldKey: String?, data: MediaData) {
+ // If the key was changed, update entry
+ val oldData = mediaPlayers[oldKey]
+ if (oldData != null) {
+ val oldData = mediaPlayers.remove(oldKey)
+ mediaPlayers.put(key, oldData!!)
+ }
var existingPlayer = mediaPlayers[key]
if (existingPlayer == null) {
- existingPlayer = MediaControlPanel(context, foregroundExecutor, backgroundExecutor,
- activityStarter, mediaHostStatesManager)
+ existingPlayer = mediaControlPanelFactory.get()
existingPlayer.attach(PlayerViewHolder.create(LayoutInflater.from(context),
mediaContent))
mediaPlayers[key] = existingPlayer
@@ -286,7 +285,7 @@ class MediaViewManager @Inject constructor(
needsReordering = true
}
}
- existingPlayer.bind(data)
+ existingPlayer?.bind(data)
updateMediaPaddings()
updatePageIndicator()
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSMediaBrowser.java b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
index a5b73dcbd289..1e9a30364607 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSMediaBrowser.java
+++ b/packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowser.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.qs;
+package com.android.systemui.media;
import android.app.PendingIntent;
import android.content.ComponentName;
@@ -27,14 +27,17 @@ import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.os.Bundle;
import android.service.media.MediaBrowserService;
+import android.text.TextUtils;
import android.util.Log;
+import com.android.systemui.util.Utils;
+
import java.util.List;
/**
- * Media browser for managing resumption in QS media controls
+ * Media browser for managing resumption in media controls
*/
-public class QSMediaBrowser {
+public class ResumeMediaBrowser {
/** Maximum number of controls to show on boot */
public static final int MAX_RESUMPTION_CONTROLS = 5;
@@ -42,7 +45,8 @@ public class QSMediaBrowser {
/** Delimiter for saved component names */
public static final String DELIMITER = ":";
- private static final String TAG = "QSMediaBrowser";
+ private static final String TAG = "ResumeMediaBrowser";
+ private boolean mIsEnabled = false;
private final Context mContext;
private final Callback mCallback;
private MediaBrowser mMediaBrowser;
@@ -54,21 +58,25 @@ public class QSMediaBrowser {
* @param callback used to report media items found
* @param componentName Component name of the MediaBrowserService this browser will connect to
*/
- public QSMediaBrowser(Context context, Callback callback, ComponentName componentName) {
+ public ResumeMediaBrowser(Context context, Callback callback, ComponentName componentName) {
+ mIsEnabled = Utils.useMediaResumption(context);
mContext = context;
mCallback = callback;
mComponentName = componentName;
}
/**
- * Connects to the MediaBrowserService and looks for valid media. If a media item is returned
- * by the service, QSMediaBrowser.Callback#addTrack will be called with its MediaDescription.
- * QSMediaBrowser.Callback#onConnected and QSMediaBrowser.Callback#onError will also be called
- * when the initial connection is successful, or an error occurs. Note that it is possible for
- * the service to connect but for no playable tracks to be found later.
- * QSMediaBrowser#disconnect will be called automatically with this function.
+ * Connects to the MediaBrowserService and looks for valid media. If a media item is returned,
+ * ResumeMediaBrowser.Callback#addTrack will be called with the MediaDescription.
+ * ResumeMediaBrowser.Callback#onConnected and ResumeMediaBrowser.Callback#onError will also be
+ * called when the initial connection is successful, or an error occurs.
+ * Note that it is possible for the service to connect but for no playable tracks to be found.
+ * ResumeMediaBrowser#disconnect will be called automatically with this function.
*/
public void findRecentMedia() {
+ if (!mIsEnabled) {
+ return;
+ }
Log.d(TAG, "Connecting to " + mComponentName);
disconnect();
Bundle rootHints = new Bundle();
@@ -86,7 +94,7 @@ public class QSMediaBrowser {
public void onChildrenLoaded(String parentId,
List<MediaBrowser.MediaItem> children) {
if (children.size() == 0) {
- Log.e(TAG, "No children found for " + mComponentName);
+ Log.d(TAG, "No children found for " + mComponentName);
return;
}
// We ask apps to return a playable item as the first child when sending
@@ -94,23 +102,24 @@ public class QSMediaBrowser {
MediaBrowser.MediaItem child = children.get(0);
MediaDescription desc = child.getDescription();
if (child.isPlayable()) {
- mCallback.addTrack(desc, mMediaBrowser.getServiceComponent(), QSMediaBrowser.this);
+ mCallback.addTrack(desc, mMediaBrowser.getServiceComponent(),
+ ResumeMediaBrowser.this);
} else {
- Log.e(TAG, "Child found but not playable for " + mComponentName);
+ Log.d(TAG, "Child found but not playable for " + mComponentName);
}
disconnect();
}
@Override
public void onError(String parentId) {
- Log.e(TAG, "Subscribe error for " + mComponentName + ": " + parentId);
+ Log.d(TAG, "Subscribe error for " + mComponentName + ": " + parentId);
mCallback.onError();
disconnect();
}
@Override
public void onError(String parentId, Bundle options) {
- Log.e(TAG, "Subscribe error for " + mComponentName + ": " + parentId
+ Log.d(TAG, "Subscribe error for " + mComponentName + ": " + parentId
+ ", options: " + options);
mCallback.onError();
disconnect();
@@ -149,7 +158,7 @@ public class QSMediaBrowser {
*/
@Override
public void onConnectionFailed() {
- Log.e(TAG, "Connection failed for " + mComponentName);
+ Log.d(TAG, "Connection failed for " + mComponentName);
mCallback.onError();
disconnect();
}
@@ -167,11 +176,15 @@ public class QSMediaBrowser {
}
/**
- * Connects to the MediaBrowserService and starts playback. QSMediaBrowser.Callback#onError or
- * QSMediaBrowser.Callback#onConnected will be called depending on whether it was successful.
- * QSMediaBrowser#disconnect should be called after this to ensure the connection is closed.
+ * Connects to the MediaBrowserService and starts playback.
+ * ResumeMediaBrowser.Callback#onError or ResumeMediaBrowser.Callback#onConnected will be called
+ * depending on whether it was successful.
+ * ResumeMediaBrowser#disconnect should be called after this to ensure the connection is closed.
*/
public void restart() {
+ if (!mIsEnabled) {
+ return;
+ }
disconnect();
Bundle rootHints = new Bundle();
rootHints.putBoolean(MediaBrowserService.BrowserRoot.EXTRA_RECENT, true);
@@ -224,18 +237,21 @@ public class QSMediaBrowser {
/**
* Used to test if SystemUI is allowed to connect to the given component as a MediaBrowser.
- * QSMediaBrowser.Callback#onError or QSMediaBrowser.Callback#onConnected will be called
+ * ResumeMediaBrowser.Callback#onError or ResumeMediaBrowser.Callback#onConnected will be called
* depending on whether it was successful.
- * QSMediaBrowser#disconnect should be called after this to ensure the connection is closed.
+ * ResumeMediaBrowser#disconnect should be called after this to ensure the connection is closed.
*/
public void testConnection() {
+ if (!mIsEnabled) {
+ return;
+ }
disconnect();
final MediaBrowser.ConnectionCallback connectionCallback =
new MediaBrowser.ConnectionCallback() {
@Override
public void onConnected() {
Log.d(TAG, "connected");
- if (mMediaBrowser.getRoot() == null) {
+ if (TextUtils.isEmpty(mMediaBrowser.getRoot())) {
mCallback.onError();
} else {
mCallback.onConnected();
@@ -264,7 +280,7 @@ public class QSMediaBrowser {
}
/**
- * Interface to handle results from QSMediaBrowser
+ * Interface to handle results from ResumeMediaBrowser
*/
public static class Callback {
/**
@@ -286,7 +302,7 @@ public class QSMediaBrowser {
* @param browser reference to the browser
*/
public void addTrack(MediaDescription track, ComponentName component,
- QSMediaBrowser browser) {
+ ResumeMediaBrowser browser) {
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
index 06821cd615a5..efc476d0c86f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
@@ -27,8 +27,10 @@ import androidx.annotation.AnyThread
import androidx.annotation.WorkerThread
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.LiveData
-
-import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.util.concurrency.RepeatableExecutor
+import java.util.concurrent.Executor
+import javax.inject.Inject
private const val POSITION_UPDATE_INTERVAL_MILLIS = 100L
@@ -65,7 +67,7 @@ private fun PlaybackState.computePosition(duration: Long): Long {
}
/** ViewModel for seek bar in QS media player. */
-class SeekBarViewModel(val bgExecutor: DelayableExecutor) {
+class SeekBarViewModel @Inject constructor(@Background private val bgExecutor: RepeatableExecutor) {
private var _data = Progress(false, false, null, null)
set(value) {
@@ -89,17 +91,25 @@ class SeekBarViewModel(val bgExecutor: DelayableExecutor) {
private var callback = object : MediaController.Callback() {
override fun onPlaybackStateChanged(state: PlaybackState) {
playbackState = state
- if (shouldPollPlaybackPosition()) {
- checkPlaybackPosition()
+ if (PlaybackState.STATE_NONE.equals(playbackState)) {
+ clearController()
+ } else {
+ checkIfPollingNeeded()
}
}
+
+ override fun onSessionDestroyed() {
+ clearController()
+ }
}
+ private var cancel: Runnable? = null
/** Listening state (QS open or closed) is used to control polling of progress. */
var listening = true
- set(value) {
- if (value) {
- checkPlaybackPosition()
+ set(value) = bgExecutor.execute {
+ if (field != value) {
+ field = value
+ checkIfPollingNeeded()
}
}
@@ -131,9 +141,7 @@ class SeekBarViewModel(val bgExecutor: DelayableExecutor) {
playbackState?.getState() == PlaybackState.STATE_NONE ||
(duration != null && duration <= 0)) false else true
_data = Progress(enabled, seekAvailable, position, duration)
- if (shouldPollPlaybackPosition()) {
- checkPlaybackPosition()
- }
+ checkIfPollingNeeded()
}
/**
@@ -145,6 +153,8 @@ class SeekBarViewModel(val bgExecutor: DelayableExecutor) {
fun clearController() = bgExecutor.execute {
controller = null
playbackState = null
+ cancel?.run()
+ cancel = null
_data = _data.copy(enabled = false)
}
@@ -152,26 +162,34 @@ class SeekBarViewModel(val bgExecutor: DelayableExecutor) {
* Call to clean up any resources.
*/
@AnyThread
- fun onDestroy() {
+ fun onDestroy() = bgExecutor.execute {
controller = null
playbackState = null
+ cancel?.run()
+ cancel = null
}
- @AnyThread
- private fun checkPlaybackPosition(): Runnable = bgExecutor.executeDelayed({
+ @WorkerThread
+ private fun checkPlaybackPosition() {
val duration = _data.duration ?: -1
val currentPosition = playbackState?.computePosition(duration.toLong())?.toInt()
if (currentPosition != null && _data.elapsedTime != currentPosition) {
_data = _data.copy(elapsedTime = currentPosition)
}
- if (shouldPollPlaybackPosition()) {
- checkPlaybackPosition()
- }
- }, POSITION_UPDATE_INTERVAL_MILLIS)
+ }
@WorkerThread
- private fun shouldPollPlaybackPosition(): Boolean {
- return listening && playbackState?.isInMotion() ?: false
+ private fun checkIfPollingNeeded() {
+ val needed = listening && playbackState?.isInMotion() ?: false
+ if (needed) {
+ if (cancel == null) {
+ cancel = bgExecutor.executeRepeatedly(this::checkPlaybackPosition, 0L,
+ POSITION_UPDATE_INTERVAL_MILLIS)
+ }
+ } else {
+ cancel?.run()
+ cancel = null
+ }
}
/** Gets a listener to attach to the seek bar to handle seeking. */
@@ -188,7 +206,7 @@ class SeekBarViewModel(val bgExecutor: DelayableExecutor) {
private class SeekBarChangeListener(
val viewModel: SeekBarViewModel,
- val bgExecutor: DelayableExecutor
+ val bgExecutor: Executor
) : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(bar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
index 7f7e1085d497..03b1ddca4648 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
@@ -17,6 +17,7 @@
package com.android.systemui.pip;
import android.animation.Animator;
+import android.animation.RectEvaluator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.content.Context;
@@ -26,6 +27,7 @@ import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Interpolators;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -74,15 +76,12 @@ public class PipAnimationController {
|| direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN;
}
- private final Interpolator mFastOutSlowInInterpolator;
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
private PipTransitionAnimator mCurrentAnimator;
@Inject
PipAnimationController(Context context, PipSurfaceTransactionHelper helper) {
- mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
- com.android.internal.R.interpolator.fast_out_slow_in);
mSurfaceTransactionHelper = helper;
}
@@ -104,10 +103,11 @@ public class PipAnimationController {
}
@SuppressWarnings("unchecked")
- PipTransitionAnimator getAnimator(SurfaceControl leash, Rect startBounds, Rect endBounds) {
+ PipTransitionAnimator getAnimator(SurfaceControl leash, Rect startBounds, Rect endBounds,
+ Rect sourceHintRect) {
if (mCurrentAnimator == null) {
mCurrentAnimator = setupPipTransitionAnimator(
- PipTransitionAnimator.ofBounds(leash, startBounds, endBounds));
+ PipTransitionAnimator.ofBounds(leash, startBounds, endBounds, sourceHintRect));
} else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA
&& mCurrentAnimator.isRunning()) {
// If we are still animating the fade into pip, then just move the surface and ensure
@@ -122,7 +122,7 @@ public class PipAnimationController {
} else {
mCurrentAnimator.cancel();
mCurrentAnimator = setupPipTransitionAnimator(
- PipTransitionAnimator.ofBounds(leash, startBounds, endBounds));
+ PipTransitionAnimator.ofBounds(leash, startBounds, endBounds, sourceHintRect));
}
return mCurrentAnimator;
}
@@ -133,7 +133,7 @@ public class PipAnimationController {
private PipTransitionAnimator setupPipTransitionAnimator(PipTransitionAnimator animator) {
animator.setSurfaceTransactionHelper(mSurfaceTransactionHelper);
- animator.setInterpolator(mFastOutSlowInInterpolator);
+ animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
animator.setFloatValues(FRACTION_START, FRACTION_END);
return animator;
}
@@ -331,6 +331,7 @@ public class PipAnimationController {
@Override
void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {
getSurfaceTransactionHelper()
+ .resetScale(tx, leash, getDestinationBounds())
.crop(tx, leash, getDestinationBounds())
.round(tx, leash, shouldApplyCornerRadius());
tx.show(leash);
@@ -346,35 +347,46 @@ public class PipAnimationController {
}
static PipTransitionAnimator<Rect> ofBounds(SurfaceControl leash,
- Rect startValue, Rect endValue) {
+ Rect startValue, Rect endValue, Rect sourceHintRect) {
+ // Just for simplicity we'll interpolate between the source rect hint insets and empty
+ // insets to calculate the window crop
+ final Rect initialStartValue = new Rect(startValue);
+ final Rect sourceHintRectInsets = sourceHintRect != null
+ ? new Rect(sourceHintRect.left - startValue.left,
+ sourceHintRect.top - startValue.top,
+ startValue.right - sourceHintRect.right,
+ startValue.bottom - sourceHintRect.bottom)
+ : null;
+ final Rect sourceInsets = new Rect(0, 0, 0, 0);
+
// construct new Rect instances in case they are recycled
return new PipTransitionAnimator<Rect>(leash, ANIM_TYPE_BOUNDS,
endValue, new Rect(startValue), new Rect(endValue)) {
- private final Rect mTmpRect = new Rect();
-
- private int getCastedFractionValue(float start, float end, float fraction) {
- return (int) (start * (1 - fraction) + end * fraction + .5f);
- }
+ private final RectEvaluator mRectEvaluator = new RectEvaluator(new Rect());
+ private final RectEvaluator mInsetsEvaluator = new RectEvaluator(new Rect());
@Override
void applySurfaceControlTransaction(SurfaceControl leash,
SurfaceControl.Transaction tx, float fraction) {
final Rect start = getStartValue();
final Rect end = getEndValue();
- mTmpRect.set(
- getCastedFractionValue(start.left, end.left, fraction),
- getCastedFractionValue(start.top, end.top, fraction),
- getCastedFractionValue(start.right, end.right, fraction),
- getCastedFractionValue(start.bottom, end.bottom, fraction));
- setCurrentValue(mTmpRect);
+ Rect bounds = mRectEvaluator.evaluate(fraction, start, end);
+ setCurrentValue(bounds);
if (inScaleTransition()) {
if (isOutPipDirection(getTransitionDirection())) {
- getSurfaceTransactionHelper().scale(tx, leash, end, mTmpRect);
+ getSurfaceTransactionHelper().scale(tx, leash, end, bounds);
} else {
- getSurfaceTransactionHelper().scale(tx, leash, start, mTmpRect);
+ getSurfaceTransactionHelper().scale(tx, leash, start, bounds);
}
} else {
- getSurfaceTransactionHelper().crop(tx, leash, mTmpRect);
+ if (sourceHintRectInsets != null) {
+ Rect insets = mInsetsEvaluator.evaluate(fraction, sourceInsets,
+ sourceHintRectInsets);
+ getSurfaceTransactionHelper().scaleAndCrop(tx, leash, initialStartValue,
+ bounds, insets);
+ } else {
+ getSurfaceTransactionHelper().scale(tx, leash, start, bounds);
+ }
}
tx.apply();
}
@@ -390,11 +402,11 @@ public class PipAnimationController {
@Override
void onEndTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) {
- if (!inScaleTransition()) return;
// NOTE: intentionally does not apply the transaction here.
// this end transaction should get executed synchronously with the final
// WindowContainerTransaction in task organizer
- getSurfaceTransactionHelper().resetScale(tx, leash, getDestinationBounds())
+ getSurfaceTransactionHelper()
+ .resetScale(tx, leash, getDestinationBounds())
.crop(tx, leash, getDestinationBounds());
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
index 0d3a16ec1028..26576940740f 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
@@ -296,6 +296,14 @@ public class PipBoundsHandler {
*/
public boolean onDisplayRotationChanged(Rect outBounds, Rect oldBounds, Rect outInsetBounds,
int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) {
+ // Calculate the snap fraction of the current stack along the old movement bounds
+ final Rect postChangeStackBounds = new Rect(oldBounds);
+ final float snapFraction = getSnapFraction(postChangeStackBounds);
+
+ // Update the display layout, note that we have to do this on every rotation even if we
+ // aren't in PIP since we need to update the display layout to get the right resources
+ mDisplayLayout.rotateTo(mContext.getResources(), toRotation);
+
// Bail early if the event is not sent to current {@link #mDisplayInfo}
if ((displayId != mDisplayInfo.displayId) || (fromRotation == toRotation)) {
return false;
@@ -312,13 +320,6 @@ public class PipBoundsHandler {
return false;
}
- // Calculate the snap fraction of the current stack along the old movement bounds
- final Rect postChangeStackBounds = new Rect(oldBounds);
- final float snapFraction = getSnapFraction(postChangeStackBounds);
-
- // Update the display layout
- mDisplayLayout.rotateTo(mContext.getResources(), toRotation);
-
// Populate the new {@link #mDisplayInfo}.
// The {@link DisplayInfo} queried from DisplayManager would be the one before rotation,
// therefore, the width/height may require a swap first.
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java
index fc41d2ea8862..65ea887259be 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java
@@ -44,6 +44,7 @@ public class PipSurfaceTransactionHelper implements ConfigurationController.Conf
private final float[] mTmpFloat9 = new float[9];
private final RectF mTmpSourceRectF = new RectF();
private final RectF mTmpDestinationRectF = new RectF();
+ private final Rect mTmpDestinationRect = new Rect();
@Inject
public PipSurfaceTransactionHelper(Context context, ConfigurationController configController) {
@@ -90,7 +91,30 @@ public class PipSurfaceTransactionHelper implements ConfigurationController.Conf
mTmpDestinationRectF.set(destinationBounds);
mTmpTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL);
tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
- .setPosition(leash, destinationBounds.left, destinationBounds.top);
+ .setPosition(leash, mTmpDestinationRectF.left, mTmpDestinationRectF.top);
+ return this;
+ }
+
+ /**
+ * Operates the scale (setMatrix) on a given transaction and leash
+ * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
+ */
+ PipSurfaceTransactionHelper scaleAndCrop(SurfaceControl.Transaction tx, SurfaceControl leash,
+ Rect sourceBounds, Rect destinationBounds, Rect insets) {
+ mTmpSourceRectF.set(sourceBounds);
+ mTmpDestinationRect.set(sourceBounds);
+ mTmpDestinationRect.inset(insets);
+ // Scale by the shortest edge and offset such that the top/left of the scaled inset source
+ // rect aligns with the top/left of the destination bounds
+ final float scale = sourceBounds.width() <= sourceBounds.height()
+ ? (float) destinationBounds.width() / sourceBounds.width()
+ : (float) destinationBounds.height() / sourceBounds.height();
+ final float left = destinationBounds.left - insets.left * scale;
+ final float top = destinationBounds.top - insets.top * scale;
+ mTmpTransform.setScale(scale, scale);
+ tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
+ .setWindowCrop(leash, mTmpDestinationRect)
+ .setPosition(leash, left, top);
return this;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index c6f144aa57a1..42e0c56d6cc8 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -143,8 +143,10 @@ public class PipTaskOrganizer extends TaskOrganizer implements
case MSG_RESIZE_ANIMATE: {
Rect currentBounds = (Rect) args.arg2;
Rect toBounds = (Rect) args.arg3;
+ Rect sourceHintRect = (Rect) args.arg4;
int duration = args.argi2;
- animateResizePip(currentBounds, toBounds, args.argi1 /* direction */, duration);
+ animateResizePip(currentBounds, toBounds, sourceHintRect,
+ args.argi1 /* direction */, duration);
if (updateBoundsCallback != null) {
updateBoundsCallback.accept(toBounds);
}
@@ -294,7 +296,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements
public void onTransactionReady(int id, SurfaceControl.Transaction t) {
t.apply();
scheduleAnimateResizePip(mLastReportedBounds, destinationBounds,
- direction, animationDurationMs, null /* updateBoundsCallback */);
+ null /* sourceHintRect */, direction, animationDurationMs,
+ null /* updateBoundsCallback */);
mInPip = false;
}
});
@@ -357,7 +360,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements
final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
- scheduleAnimateResizePip(currentBounds, destinationBounds,
+ final Rect sourceHintRect = getValidSourceHintRect(info, currentBounds);
+ scheduleAnimateResizePip(currentBounds, destinationBounds, sourceHintRect,
TRANSITION_DIRECTION_TO_PIP, mEnterExitAnimationDuration,
null /* updateBoundsCallback */);
} else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
@@ -368,6 +372,21 @@ public class PipTaskOrganizer extends TaskOrganizer implements
}
}
+ /**
+ * Returns the source hint rect if it is valid (if provided and is contained by the current
+ * task bounds).
+ */
+ private Rect getValidSourceHintRect(ActivityManager.RunningTaskInfo info, Rect sourceBounds) {
+ final Rect sourceHintRect = info.pictureInPictureParams != null
+ && info.pictureInPictureParams.hasSourceBoundsHint()
+ ? info.pictureInPictureParams.getSourceRectHint()
+ : null;
+ if (sourceHintRect != null && sourceBounds.contains(sourceHintRect)) {
+ return sourceHintRect;
+ }
+ return null;
+ }
+
private void enterPipWithAlphaAnimation(Rect destinationBounds, long durationMs) {
// If we are fading the PIP in, then we should move the pip to the final location as
// soon as possible, but set the alpha immediately since the transaction can take a
@@ -552,13 +571,13 @@ public class PipTaskOrganizer extends TaskOrganizer implements
Log.d(TAG, "skip scheduleAnimateResizePip, entering pip deferred");
return;
}
- scheduleAnimateResizePip(mLastReportedBounds, toBounds,
+ scheduleAnimateResizePip(mLastReportedBounds, toBounds, null /* sourceHintRect */,
TRANSITION_DIRECTION_NONE, duration, updateBoundsCallback);
}
private void scheduleAnimateResizePip(Rect currentBounds, Rect destinationBounds,
- @PipAnimationController.TransitionDirection int direction, int durationMs,
- Consumer<Rect> updateBoundsCallback) {
+ Rect sourceHintRect, @PipAnimationController.TransitionDirection int direction,
+ int durationMs, Consumer<Rect> updateBoundsCallback) {
if (!mInPip) {
// can be initiated in other component, ignore if we are no longer in PIP
return;
@@ -568,6 +587,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements
args.arg1 = updateBoundsCallback;
args.arg2 = currentBounds;
args.arg3 = destinationBounds;
+ args.arg4 = sourceHintRect;
args.argi1 = direction;
args.argi2 = durationMs;
mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_RESIZE_ANIMATE, args));
@@ -667,7 +687,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements
}
final Rect destinationBounds = new Rect(originalBounds);
destinationBounds.offset(xOffset, yOffset);
- animateResizePip(originalBounds, destinationBounds, TRANSITION_DIRECTION_SAME, durationMs);
+ animateResizePip(originalBounds, destinationBounds, null /* sourceHintRect */,
+ TRANSITION_DIRECTION_SAME, durationMs);
}
private void resizePip(Rect destinationBounds) {
@@ -745,7 +766,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements
WindowOrganizer.applyTransaction(wct);
}
- private void animateResizePip(Rect currentBounds, Rect destinationBounds,
+ private void animateResizePip(Rect currentBounds, Rect destinationBounds, Rect sourceHintRect,
@PipAnimationController.TransitionDirection int direction, int durationMs) {
if (Looper.myLooper() != mUpdateHandler.getLooper()) {
throw new RuntimeException("Callers should call scheduleAnimateResizePip() instead of "
@@ -757,7 +778,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements
return;
}
mPipAnimationController
- .getAnimator(mLeash, currentBounds, destinationBounds)
+ .getAnimator(mLeash, currentBounds, destinationBounds, sourceHintRect)
.setTransitionDirection(direction)
.setPipAnimationCallback(mPipAnimationCallback)
.setDuration(durationMs)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
index 0d614497190f..2c76d70fb3cc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
@@ -45,9 +45,6 @@ public class PageIndicator extends ViewGroup {
}
public void setNumPages(int numPages) {
- if (numPages == getChildCount()) {
- return;
- }
TypedArray array = getContext().obtainStyledAttributes(
new int[]{android.R.attr.colorControlActivated});
int color = array.getColor(0, 0);
@@ -55,12 +52,12 @@ public class PageIndicator extends ViewGroup {
setNumPages(numPages, color);
}
- /** Oveload of setNumPages that allows the indicator color to be specified.*/
+ /** Overload of setNumPages that allows the indicator color to be specified.*/
public void setNumPages(int numPages, int color) {
+ setVisibility(numPages > 1 ? View.VISIBLE : View.GONE);
if (numPages == getChildCount()) {
return;
}
- setVisibility(numPages > 1 ? View.VISIBLE : View.GONE);
if (mAnimating) {
Log.w(TAG, "setNumPages during animation");
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index 6b0775f6c2d7..1c3b6850afc1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -50,6 +50,8 @@ public class QSContainerImpl extends FrameLayout {
private int mSideMargins;
private boolean mQsDisabled;
+ private int mContentPaddingStart = -1;
+ private int mContentPaddingEnd = -1;
public QSContainerImpl(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -66,10 +68,9 @@ public class QSContainerImpl extends FrameLayout {
mBackground = findViewById(R.id.quick_settings_background);
mStatusBarBackground = findViewById(R.id.quick_settings_status_bar_background);
mBackgroundGradient = findViewById(R.id.quick_settings_gradient_view);
- mSideMargins = getResources().getDimensionPixelSize(R.dimen.notification_side_paddings);
+ updateResources();
setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
- setMargins();
}
@Override
@@ -103,10 +104,15 @@ public class QSContainerImpl extends FrameLayout {
if (navBelow) {
maxQs -= getResources().getDimensionPixelSize(R.dimen.navigation_bar_height);
}
+
+ int padding = mPaddingLeft + mPaddingRight + layoutParams.leftMargin
+ + layoutParams.rightMargin;
+ final int qsPanelWidthSpec = getChildMeasureSpec(widthMeasureSpec, padding,
+ layoutParams.width);
// Measure with EXACTLY. That way, PagedTileLayout will only use excess height and will be
// measured last, after other views and padding is accounted for.
- mQSPanel.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(maxQs, MeasureSpec.EXACTLY));
- int width = mQSPanel.getMeasuredWidth();
+ mQSPanel.measure(qsPanelWidthSpec, MeasureSpec.makeMeasureSpec(maxQs, MeasureSpec.EXACTLY));
+ int width = mQSPanel.getMeasuredWidth() + padding;
int height = layoutParams.topMargin + layoutParams.bottomMargin
+ mQSPanel.getMeasuredHeight() + getPaddingBottom();
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
@@ -148,8 +154,18 @@ public class QSContainerImpl extends FrameLayout {
LayoutParams layoutParams = (LayoutParams) mQSPanel.getLayoutParams();
layoutParams.topMargin = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.quick_qs_offset_height);
-
mQSPanel.setLayoutParams(layoutParams);
+
+ mSideMargins = getResources().getDimensionPixelSize(R.dimen.notification_side_paddings);
+ mContentPaddingStart = getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_content_margin_start);
+ int newPaddingEnd = getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_content_margin_end);
+ boolean marginsChanged = newPaddingEnd != mContentPaddingEnd;
+ mContentPaddingEnd = newPaddingEnd;
+ if (marginsChanged) {
+ updatePaddingsAndMargins();
+ }
}
/**
@@ -196,17 +212,32 @@ public class QSContainerImpl extends FrameLayout {
updateExpansion();
}
- private void setMargins() {
- setMargins(mQSDetail);
- setMargins(mBackground);
- mQSPanel.setMargins(mSideMargins);
- mHeader.setMargins(mSideMargins);
- }
-
- private void setMargins(View view) {
- FrameLayout.LayoutParams lp = (LayoutParams) view.getLayoutParams();
- lp.rightMargin = mSideMargins;
- lp.leftMargin = mSideMargins;
+ private void updatePaddingsAndMargins() {
+ for (int i = 0; i < getChildCount(); i++) {
+ View view = getChildAt(i);
+ if (view == mStatusBarBackground || view == mBackgroundGradient
+ || view == mQSCustomizer) {
+ // Some views are always full width
+ continue;
+ }
+ LayoutParams lp = (LayoutParams) view.getLayoutParams();
+ lp.rightMargin = mSideMargins;
+ lp.leftMargin = mSideMargins;
+ if (view == mQSPanel) {
+ // QS panel lays out some of its content full width
+ mQSPanel.setContentMargins(mContentPaddingStart, mContentPaddingEnd);
+ } else if (view == mHeader) {
+ // The header contains the QQS panel which needs to have special padding, to
+ // visually align them.
+ mHeader.setContentMargins(mContentPaddingStart, mContentPaddingEnd);
+ } else {
+ view.setPaddingRelative(
+ mContentPaddingStart,
+ view.getPaddingTop(),
+ mContentPaddingEnd,
+ view.getPaddingBottom());
+ }
+ }
}
private int getDisplayHeight() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 48ba1b99d714..78448785fe2f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -88,6 +88,8 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
private final H mHandler = new H();
private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
private final QSTileRevealController mQsTileRevealController;
+ /** Whether or not the QS media player feature is enabled. */
+ protected boolean mUsingMediaPlayer;
protected boolean mExpanded;
protected boolean mListening;
@@ -102,6 +104,9 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
protected QSSecurityFooter mFooter;
private PageIndicator mFooterPageIndicator;
private boolean mGridContentVisible = true;
+ private int mContentMarginStart;
+ private int mContentMarginEnd;
+ private int mVisualTilePadding;
protected QSTileLayout mTileLayout;
@@ -122,6 +127,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
UiEventLogger uiEventLogger
) {
super(context, attrs);
+ mUsingMediaPlayer = useQsMediaPlayer(context);
mMediaHost = mediaHost;
mContext = context;
mQSLogger = qsLogger;
@@ -170,8 +176,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
mMediaHost.init(MediaHierarchyManager.LOCATION_QS);
ViewGroup hostView = mMediaHost.getHostView();
addView(hostView);
- int sidePaddings = getResources().getDimensionPixelSize(
- R.dimen.quick_settings_side_margins);
int bottomPadding = getResources().getDimensionPixelSize(
R.dimen.quick_settings_expanded_bottom_margin);
MarginLayoutParams layoutParams = (MarginLayoutParams) hostView.getLayoutParams();
@@ -179,8 +183,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
layoutParams.bottomMargin = bottomPadding;
hostView.setLayoutParams(layoutParams);
- hostView.setPadding(sidePaddings, hostView.getPaddingTop(), sidePaddings,
- hostView.getPaddingBottom());
+ updateMediaHostContentMargins();
}
protected void addDivider() {
@@ -359,8 +362,10 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
}
public void updateResources() {
- final Resources res = mContext.getResources();
- setPadding(0, res.getDimensionPixelSize(R.dimen.qs_panel_padding_top), 0, res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom));
+ int tileSize = getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
+ int tileBg = getResources().getDimensionPixelSize(R.dimen.qs_tile_background_size);
+ mVisualTilePadding = (int) ((tileSize - tileBg) / 2.0f);
+ updatePadding();
updatePageIndicator();
@@ -372,6 +377,14 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
}
}
+ protected void updatePadding() {
+ final Resources res = mContext.getResources();
+ setPaddingRelative(getPaddingStart(),
+ res.getDimensionPixelSize(R.dimen.qs_panel_padding_top),
+ getPaddingEnd(),
+ res.getDimensionPixelSize(R.dimen.qs_panel_padding_bottom));
+ }
+
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
@@ -723,17 +736,51 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne
mFooter.showDeviceMonitoringDialog();
}
- public void setMargins(int sideMargins) {
- for (int i = 0; i < getChildCount(); i++) {
- View view = getChildAt(i);
- if (view != mTileLayout) {
- LayoutParams lp = (LayoutParams) view.getLayoutParams();
- lp.leftMargin = sideMargins;
- lp.rightMargin = sideMargins;
- }
+ public void setContentMargins(int startMargin, int endMargin) {
+ // Only some views actually want this content padding, others want to go all the way
+ // to the edge like the brightness slider
+ mContentMarginStart = startMargin;
+ mContentMarginEnd = endMargin;
+ updateTileLayoutMargins(mContentMarginStart - mVisualTilePadding,
+ mContentMarginEnd - mVisualTilePadding);
+ updateMediaHostContentMargins();
+ }
+
+ /**
+ * Update the margins of all tile Layouts.
+ *
+ * @param visualMarginStart the visual start margin of the tile, adjusted for local insets
+ * to the tile. This can be set on a tileLayout
+ * @param visualMarginEnd the visual end margin of the tile, adjusted for local insets
+ * to the tile. This can be set on a tileLayout
+ */
+ protected void updateTileLayoutMargins(int visualMarginStart, int visualMarginEnd) {
+ updateMargins((View) mTileLayout, visualMarginStart, visualMarginEnd);
+ }
+
+ /**
+ * Update the margins of the media hosts
+ */
+ protected void updateMediaHostContentMargins() {
+ if (mUsingMediaPlayer && mMediaHost != null) {
+ updateMargins(mMediaHost.getHostView(), mContentMarginStart, mContentMarginEnd);
}
}
+ /**
+ * Update the margins of a view.
+ *
+ * @param view the view to adjust
+ * @param start the start margin to set
+ * @param end the end margin to set
+ */
+ protected void updateMargins(View view, int start, int end) {
+ LayoutParams lp = (LayoutParams) view.getLayoutParams();
+ lp.setMarginStart(start);
+ lp.setMarginEnd(end);
+ view.setLayoutParams(lp);
+ }
+
public MediaHost getMediaHost() {
return mMediaHost;
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 4008918e267c..65d3572d04a3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -355,10 +355,23 @@ public class QSTileHost implements QSHost, Tunable, PluginListener<QSFactory>, D
}
public void addTile(ComponentName tile) {
+ addTile(tile, /* end */ false);
+ }
+
+ /**
+ * Adds a custom tile to the set of current tiles.
+ * @param tile the component name of the {@link android.service.quicksettings.TileService}
+ * @param end if true, the tile will be added at the end. If false, at the beginning.
+ */
+ public void addTile(ComponentName tile, boolean end) {
String spec = CustomTile.toSpec(tile);
if (!mTileSpecs.contains(spec)) {
List<String> newSpecs = new ArrayList<>(mTileSpecs);
- newSpecs.add(0, spec);
+ if (end) {
+ newSpecs.add(spec);
+ } else {
+ newSpecs.add(0, spec);
+ }
changeTiles(mTileSpecs, newSpecs);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 75507beba7ae..94b4cee92965 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -41,7 +41,6 @@ import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
-import com.android.systemui.util.Utils;
import java.util.ArrayList;
import java.util.Collection;
@@ -62,8 +61,6 @@ public class QuickQSPanel extends QSPanel {
private boolean mDisabledByPolicy;
private int mMaxTiles;
protected QSPanel mFullPanel;
- /** Whether or not the QS media player feature is enabled. */
- private boolean mUsingMediaPlayer;
/** Whether or not the QuickQSPanel currently contains a media player. */
private boolean mShowHorizontalTileLayout;
private LinearLayout mHorizontalLinearLayout;
@@ -84,8 +81,7 @@ public class QuickQSPanel extends QSPanel {
MediaHost mediaHost,
UiEventLogger uiEventLogger
) {
- super(context, attrs, dumpManager, broadcastDispatcher, qsLogger, mediaHost,
- uiEventLogger);
+ super(context, attrs, dumpManager, broadcastDispatcher, qsLogger, mediaHost, uiEventLogger);
if (mFooter != null) {
removeView(mFooter.getView());
}
@@ -97,8 +93,6 @@ public class QuickQSPanel extends QSPanel {
}
mMediaBottomMargin = getResources().getDimensionPixelSize(
R.dimen.quick_settings_media_extra_bottom_margin);
-
- mUsingMediaPlayer = Utils.useQsMediaPlayer(context);
if (mUsingMediaPlayer) {
mHorizontalLinearLayout = new LinearLayout(mContext);
mHorizontalLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
@@ -132,7 +126,6 @@ public class QuickQSPanel extends QSPanel {
mHorizontalLinearLayout.setVisibility(useHorizontal ? View.VISIBLE : View.GONE);
addView((View) mRegularTileLayout, 0);
super.setPadding(0, 0, 0, 0);
- applySideMargins(mHorizontalLinearLayout);
applyBottomMargin((View) mRegularTileLayout);
} else {
sDefaultMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_columns);
@@ -151,14 +144,6 @@ public class QuickQSPanel extends QSPanel {
view.setLayoutParams(layoutParams);
}
- private void applySideMargins(View view) {
- int margin = getResources().getDimensionPixelSize(R.dimen.qs_header_tile_margin_horizontal);
- MarginLayoutParams layoutParams = (MarginLayoutParams) view.getLayoutParams();
- layoutParams.setMarginStart(margin);
- layoutParams.setMarginEnd(margin);
- view.setLayoutParams(layoutParams);
- }
-
private void reAttachMediaHost() {
if (mMediaHost == null) {
return;
@@ -177,10 +162,6 @@ public class QuickQSPanel extends QSPanel {
layoutParams.width = horizontal ? 0 : ViewGroup.LayoutParams.MATCH_PARENT;
layoutParams.weight = horizontal ? 1.5f : 0;
layoutParams.bottomMargin = mMediaBottomMargin;
- int marginStart = horizontal
- ? getResources().getDimensionPixelSize(R.dimen.qs_header_tile_margin_horizontal)
- : 0;
- layoutParams.setMarginStart(marginStart);
}
}
@@ -194,11 +175,22 @@ public class QuickQSPanel extends QSPanel {
mMediaHost.setShowsOnlyActiveMedia(true);
mMediaHost.init(MediaHierarchyManager.LOCATION_QQS);
reAttachMediaHost();
+ updateMediaHostContentMargins();
+ }
+
+ @Override
+ protected void updateTileLayoutMargins(int visualMarginStart, int visualMarginEnd) {
+ if (mUsingMediaPlayer) {
+ updateMargins((View) mRegularTileLayout, visualMarginStart, visualMarginEnd);
+ updateMargins((View) mHorizontalTileLayout, visualMarginStart, 0);
+ } else {
+ updateMargins((View) mTileLayout, visualMarginStart, visualMarginEnd);
+ }
}
@Override
- public void setPadding(int left, int top, int right, int bottom) {
- // Always have no padding.
+ protected void updatePadding() {
+ // QS Panel is setting a top padding by default, which we don't need.
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 29b3436c0b72..20e47b2f2fa9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -42,6 +42,7 @@ import android.view.DisplayCutout;
import android.view.View;
import android.view.WindowInsets;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
@@ -143,6 +144,11 @@ public class QuickStatusBarHeader extends RelativeLayout implements
private boolean mHasTopCutout = false;
private int mRoundedCornerPadding = 0;
+ private int mContentMarginStart;
+ private int mContentMarginEnd;
+ private int mWaterfallTopInset;
+ private int mCutOutPaddingLeft;
+ private int mCutOutPaddingRight;
@Inject
public QuickStatusBarHeader(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
@@ -422,33 +428,42 @@ public class QuickStatusBarHeader extends RelativeLayout implements
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- // Handle padding of QuickStatusBarHeader
- setPadding(mRoundedCornerPadding, getPaddingTop(), mRoundedCornerPadding,
- getPaddingBottom());
-
- // Handle padding of SystemIconsView
+ // Handle padding of the clock
DisplayCutout cutout = insets.getDisplayCutout();
Pair<Integer, Integer> cornerCutoutPadding = StatusBarWindowView.cornerCutoutMargins(
cutout, getDisplay());
Pair<Integer, Integer> padding =
StatusBarWindowView.paddingNeededForCutoutAndRoundedCorner(
- cutout, cornerCutoutPadding, mRoundedCornerPadding);
- final int waterfallTopInset = cutout == null ? 0 : cutout.getWaterfallInsets().top;
- int statusBarPaddingLeft = isLayoutRtl()
- ? getResources().getDimensionPixelSize(R.dimen.status_bar_padding_end)
- : getResources().getDimensionPixelSize(R.dimen.status_bar_padding_start);
- int statusBarPaddingRight = isLayoutRtl()
- ? getResources().getDimensionPixelSize(R.dimen.status_bar_padding_start)
- : getResources().getDimensionPixelSize(R.dimen.status_bar_padding_end);
- mSystemIconsView.setPadding(
- Math.max(padding.first + statusBarPaddingLeft - mRoundedCornerPadding, 0),
- waterfallTopInset,
- Math.max(padding.second + statusBarPaddingRight - mRoundedCornerPadding, 0),
- 0);
-
+ cutout, cornerCutoutPadding, -1);
+ mCutOutPaddingLeft = padding.first;
+ mCutOutPaddingRight = padding.second;
+ mWaterfallTopInset = cutout == null ? 0 : cutout.getWaterfallInsets().top;
+ updateClockPadding();
return super.onApplyWindowInsets(insets);
}
+ private void updateClockPadding() {
+ int clockPaddingLeft = 0;
+ int clockPaddingRight = 0;
+ // The clock might collide with cutouts, let's shift it out of the way.
+ // We only do that if the inset is bigger than our own padding, since it's nicer to
+ // align with
+ if (mCutOutPaddingLeft > 0) {
+ // if there's a cutout, let's use at least the rounded corner inset
+ int cutoutPadding = Math.max(mCutOutPaddingLeft, mRoundedCornerPadding);
+ int contentMarginLeft = isLayoutRtl() ? mContentMarginEnd : mContentMarginStart;
+ clockPaddingLeft = Math.max(cutoutPadding - contentMarginLeft, 0);
+ }
+ if (mCutOutPaddingRight > 0) {
+ // if there's a cutout, let's use at least the rounded corner inset
+ int cutoutPadding = Math.max(mCutOutPaddingRight, mRoundedCornerPadding);
+ int contentMarginRight = isLayoutRtl() ? mContentMarginStart : mContentMarginEnd;
+ clockPaddingRight = Math.max(cutoutPadding - contentMarginRight, 0);
+ }
+
+ mSystemIconsView.setPadding(clockPaddingLeft, mWaterfallTopInset, clockPaddingRight, 0);
+ }
+
@Override
@VisibleForTesting
public void onDetachedFromWindow() {
@@ -558,24 +573,27 @@ public class QuickStatusBarHeader extends RelativeLayout implements
return color == Color.WHITE ? 0 : 1;
}
- public void setMargins(int sideMargins) {
- for (int i = 0; i < getChildCount(); i++) {
- View v = getChildAt(i);
- // Prevents these views from getting set a margin.
- // The Icon views all have the same padding set in XML to be aligned.
- if (v == mSystemIconsView || v == mQuickQsStatusIcons || v == mHeaderQsPanel
- || v == mHeaderTextContainerView) {
- continue;
- }
- RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) v.getLayoutParams();
- lp.leftMargin = sideMargins;
- lp.rightMargin = sideMargins;
- }
- }
-
@NonNull
@Override
public Lifecycle getLifecycle() {
return mLifecycle;
}
+
+ public void setContentMargins(int marginStart, int marginEnd) {
+ mContentMarginStart = marginStart;
+ mContentMarginEnd = marginEnd;
+ for (int i = 0; i < getChildCount(); i++) {
+ View view = getChildAt(i);
+ if (view == mHeaderQsPanel) {
+ // QS panel doesn't lays out some of its content full width
+ mHeaderQsPanel.setContentMargins(marginStart, marginEnd);
+ } else {
+ MarginLayoutParams lp = (MarginLayoutParams) view.getLayoutParams();
+ lp.setMarginStart(marginStart);
+ lp.setMarginEnd(marginEnd);
+ view.setLayoutParams(lp);
+ }
+ }
+ updateClockPadding();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 098431658e6a..383c29d90a22 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -96,7 +96,6 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
mCellMarginHorizontal = res.getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal);
mCellMarginVertical= res.getDimensionPixelSize(R.dimen.qs_tile_margin_vertical);
mCellMarginTop = res.getDimensionPixelSize(R.dimen.qs_tile_margin_top);
- mSidePadding = res.getDimensionPixelOffset(R.dimen.qs_tile_layout_margin_side);
mMaxAllowedRows = Math.max(1, getResources().getInteger(R.integer.quick_settings_max_rows));
if (mLessRows) mMaxAllowedRows = Math.max(1, mMaxAllowedRows - 1);
if (mColumns != columns) {
@@ -120,7 +119,7 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
mRows = (numTiles + mColumns - 1) / mColumns;
}
mCellWidth =
- (availableWidth - mSidePadding * 2 - (mCellMarginHorizontal * mColumns)) / mColumns;
+ (availableWidth - (mCellMarginHorizontal * mColumns)) / mColumns;
// Measure each QS tile.
View previousView = this;
@@ -204,7 +203,7 @@ public class TileLayout extends ViewGroup implements QSTileLayout {
}
protected int getColumnStart(int column) {
- return getPaddingStart() + mSidePadding + mCellMarginHorizontal / 2 +
+ return getPaddingStart() + mCellMarginHorizontal / 2 +
column * (mCellWidth + mCellMarginHorizontal);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
index db7c6ad69d23..2863d08a75dc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -69,10 +69,14 @@ public class TileServices extends IQSService.Stub {
mHost = host;
mContext = mHost.getContext();
mBroadcastDispatcher = broadcastDispatcher;
- mBroadcastDispatcher.registerReceiver(mRequestListeningReceiver,
- new IntentFilter(TileService.ACTION_REQUEST_LISTENING));
mHandler = new Handler(looper);
mMainHandler = new Handler(Looper.getMainLooper());
+ mBroadcastDispatcher.registerReceiver(
+ mRequestListeningReceiver,
+ new IntentFilter(TileService.ACTION_REQUEST_LISTENING),
+ null, // Use the default Executor
+ UserHandle.ALL
+ );
}
public Context getContext() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index b272b60f3593..baa2dfdcebf3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -64,13 +64,16 @@ import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActiv
import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.internal.util.ScreenshotHelper;
import com.android.systemui.Dumpable;
+import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.model.SysUiState;
import com.android.systemui.pip.PipAnimationController;
import com.android.systemui.pip.PipUI;
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
+import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.shared.recents.ISystemUiProxy;
+import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.stackdivider.Divider;
@@ -83,8 +86,6 @@ import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
import com.android.systemui.statusbar.policy.CallbackController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -101,8 +102,9 @@ import dagger.Lazy;
* Class to send information from overview to launcher with a binder.
*/
@Singleton
-public class OverviewProxyService implements CallbackController<OverviewProxyListener>,
- NavigationModeController.ModeChangedListener, Dumpable {
+public class OverviewProxyService extends CurrentUserTracker implements
+ CallbackController<OverviewProxyListener>, NavigationModeController.ModeChangedListener,
+ Dumpable {
private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
@@ -123,7 +125,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
private final NotificationShadeWindowController mStatusBarWinController;
private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser;
private final ComponentName mRecentsComponentName;
- private final DeviceProvisionedController mDeviceProvisionedController;
private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
private final Intent mQuickStepIntent;
private final ScreenshotHelper mScreenshotHelper;
@@ -383,8 +384,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
@Override
public void handleImageAsScreenshot(Bitmap screenImage, Rect locationInScreen,
Insets visibleInsets, int taskId) {
- mScreenshotHelper.provideScreenshot(screenImage, locationInScreen, visibleInsets,
- taskId, SCREENSHOT_OVERVIEW, mHandler, null);
+ // Deprecated
}
@Override
@@ -434,6 +434,21 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
}
}
+ @Override
+ public void handleImageBundleAsScreenshot(Bundle screenImageBundle, Rect locationInScreen,
+ Insets visibleInsets, Task.TaskKey task) {
+ mScreenshotHelper.provideScreenshot(
+ screenImageBundle,
+ locationInScreen,
+ visibleInsets,
+ task.id,
+ task.userId,
+ task.sourceComponent,
+ SCREENSHOT_OVERVIEW,
+ mHandler,
+ null);
+ }
+
private boolean verifyCaller(String reason) {
final int callerId = Binder.getCallingUserHandle().getIdentifier();
if (callerId != mCurrentBoundedUserId) {
@@ -480,7 +495,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
return;
}
- mCurrentBoundedUserId = mDeviceProvisionedController.getCurrentUser();
+ mCurrentBoundedUserId = getCurrentUserId();
mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
Bundle params = new Bundle();
@@ -523,22 +538,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
}
};
- private final DeviceProvisionedListener mDeviceProvisionedCallback =
- new DeviceProvisionedListener() {
- @Override
- public void onUserSetupChanged() {
- if (mDeviceProvisionedController.isCurrentUserSetup()) {
- internalConnectToCurrentUser();
- }
- }
-
- @Override
- public void onUserSwitched() {
- mConnectionBackoffAttempts = 0;
- internalConnectToCurrentUser();
- }
- };
-
private final StatusBarWindowCallback mStatusBarWindowCallback = this::onStatusBarStateChanged;
// This is the death handler for the binder from the launcher service
@@ -548,18 +547,18 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@Inject
public OverviewProxyService(Context context, CommandQueue commandQueue,
- DeviceProvisionedController provisionController,
NavigationBarController navBarController, NavigationModeController navModeController,
NotificationShadeWindowController statusBarWinController, SysUiState sysUiState,
PipUI pipUI, Optional<Divider> dividerOptional,
- Optional<Lazy<StatusBar>> statusBarOptionalLazy) {
+ Optional<Lazy<StatusBar>> statusBarOptionalLazy,
+ BroadcastDispatcher broadcastDispatcher) {
+ super(broadcastDispatcher);
mContext = context;
mPipUI = pipUI;
mStatusBarOptionalLazy = statusBarOptionalLazy;
mHandler = new Handler();
mNavBarController = navBarController;
mStatusBarWinController = statusBarWinController;
- mDeviceProvisionedController = provisionController;
mConnectionBackoffAttempts = 0;
mDividerOptional = dividerOptional;
mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
@@ -580,7 +579,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
// Listen for device provisioned/user setup
updateEnabledState();
- mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);
+ startTracking();
// Listen for launcher package changes
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
@@ -604,6 +603,12 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
});
}
+ @Override
+ public void onUserSwitched(int newUserId) {
+ mConnectionBackoffAttempts = 0;
+ internalConnectToCurrentUser();
+ }
+
public void notifyBackAction(boolean completed, int downX, int downY, boolean isButton,
boolean gestureSwipeLeft) {
try {
@@ -709,10 +714,8 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
disconnectFromLauncherService();
// If user has not setup yet or already connected, do not try to connect
- if (!mDeviceProvisionedController.isCurrentUserSetup() || !isEnabled()) {
- Log.v(TAG_OPS, "Cannot attempt connection, is setup "
- + mDeviceProvisionedController.isCurrentUserSetup() + ", is enabled "
- + isEnabled());
+ if (!isEnabled()) {
+ Log.v(TAG_OPS, "Cannot attempt connection, is enabled " + isEnabled());
return;
}
mHandler.removeCallbacks(mConnectionRunnable);
@@ -722,7 +725,7 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
mBound = mContext.bindServiceAsUser(launcherServiceIntent,
mOverviewServiceConnection,
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
- UserHandle.of(mDeviceProvisionedController.getCurrentUser()));
+ UserHandle.of(getCurrentUserId()));
} catch (SecurityException e) {
Log.e(TAG_OPS, "Unable to bind because of security error", e);
}
@@ -881,8 +884,6 @@ public class OverviewProxyService implements CallbackController<OverviewProxyLis
pw.println(TAG_OPS + " state:");
pw.print(" recentsComponentName="); pw.println(mRecentsComponentName);
pw.print(" isConnected="); pw.println(mOverviewProxy != null);
- pw.print(" isCurrentUserSetup="); pw.println(mDeviceProvisionedController
- .isCurrentUserSetup());
pw.print(" connectionBackoffAttempts="); pw.println(mConnectionBackoffAttempts);
pw.print(" quickStepIntent="); pw.println(mQuickStepIntent);
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 960c50129a56..2ddd6aaf4c40 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -33,9 +33,7 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.Settings;
-import android.util.DisplayMetrics;
import android.util.Log;
-import android.util.Size;
import android.widget.Toast;
import com.android.systemui.R;
@@ -225,8 +223,8 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
res.getString(R.string.screenrecord_name));
String notificationTitle = mAudioSource == ScreenRecordingAudioSource.NONE
- ? res.getString(R.string.screenrecord_ongoing_screen_and_audio)
- : res.getString(R.string.screenrecord_ongoing_screen_only);
+ ? res.getString(R.string.screenrecord_ongoing_screen_only)
+ : res.getString(R.string.screenrecord_ongoing_screen_and_audio);
mRecordingNotificationBuilder = new Notification.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_screenrecord)
@@ -247,7 +245,8 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
startForeground(NOTIFICATION_RECORDING_ID, notification);
}
- private Notification createSaveNotification(Uri uri) {
+ private Notification createSaveNotification(ScreenMediaRecorder.SavedRecording recording) {
+ Uri uri = recording.getUri();
Intent viewIntent = new Intent(Intent.ACTION_VIEW)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION)
.setDataAndType(uri, "video/mp4");
@@ -290,16 +289,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis
.addExtras(extras);
// Add thumbnail if available
- Bitmap thumbnailBitmap = null;
- try {
- ContentResolver resolver = getContentResolver();
- DisplayMetrics metrics = getResources().getDisplayMetrics();
- Size size = new Size(metrics.widthPixels, metrics.heightPixels / 2);
- thumbnailBitmap = resolver.loadThumbnail(uri, size, null);
- } catch (IOException e) {
- Log.e(TAG, "Error creating thumbnail: " + e.getMessage());
- e.printStackTrace();
- }
+ Bitmap thumbnailBitmap = recording.getThumbnail();
if (thumbnailBitmap != null) {
Notification.BigPictureStyle pictureStyle = new Notification.BigPictureStyle()
.bigPicture(thumbnailBitmap)
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
index 752f4fddf24b..edbc3cfdece5 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenInternalAudioRecorder.java
@@ -38,6 +38,7 @@ import java.nio.ByteBuffer;
public class ScreenInternalAudioRecorder {
private static String TAG = "ScreenAudioRecorder";
private static final int TIMEOUT = 500;
+ private static final float MIC_VOLUME_SCALE = 1.4f;
private final Context mContext;
private AudioRecord mAudioRecord;
private AudioRecord mAudioRecordMic;
@@ -148,6 +149,10 @@ public class ScreenInternalAudioRecorder {
readShortsInternal = mAudioRecord.read(bufferInternal, 0,
bufferInternal.length);
readShortsMic = mAudioRecordMic.read(bufferMic, 0, bufferMic.length);
+
+ // modify the volume
+ bufferMic = scaleValues(bufferMic,
+ readShortsMic, MIC_VOLUME_SCALE);
readBytes = Math.min(readShortsInternal, readShortsMic) * 2;
buffer = addAndConvertBuffers(bufferInternal, readShortsInternal, bufferMic,
readShortsMic);
@@ -168,6 +173,19 @@ public class ScreenInternalAudioRecorder {
});
}
+ private short[] scaleValues(short[] buff, int len, float scale) {
+ for (int i = 0; i < len; i++) {
+ int oldValue = buff[i];
+ int newValue = (int) (buff[i] * scale);
+ if (newValue > Short.MAX_VALUE) {
+ newValue = Short.MAX_VALUE;
+ } else if (newValue < Short.MIN_VALUE) {
+ newValue = Short.MIN_VALUE;
+ }
+ buff[i] = (short) (newValue);
+ }
+ return buff;
+ }
private byte[] addAndConvertBuffers(short[] a1, int a1Limit, short[] a2, int a2Limit) {
int size = Math.max(a1Limit, a2Limit);
if (size < 0) return new byte[0];
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
index c967648c544e..1c7d987afff2 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
@@ -22,13 +22,17 @@ import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.INTER
import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.MIC;
import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.MIC_AND_INTERNAL;
+import android.annotation.Nullable;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
+import android.graphics.Bitmap;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
+import android.media.MediaCodecInfo;
import android.media.MediaMuxer;
import android.media.MediaRecorder;
+import android.media.ThumbnailUtils;
import android.media.projection.IMediaProjection;
import android.media.projection.IMediaProjectionManager;
import android.media.projection.MediaProjection;
@@ -40,6 +44,7 @@ import android.os.ServiceManager;
import android.provider.MediaStore;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.Size;
import android.view.Surface;
import android.view.WindowManager;
@@ -55,9 +60,9 @@ import java.util.Date;
*/
public class ScreenMediaRecorder {
private static final int TOTAL_NUM_TRACKS = 1;
- private static final int VIDEO_BIT_RATE = 10000000;
private static final int VIDEO_FRAME_RATE = 30;
- private static final int AUDIO_BIT_RATE = 16;
+ private static final int VIDEO_FRAME_RATE_TO_RESOLUTION_RATIO = 6;
+ private static final int AUDIO_BIT_RATE = 196000;
private static final int AUDIO_SAMPLE_RATE = 44100;
private static final int MAX_DURATION_MS = 60 * 60 * 1000;
private static final long MAX_FILESIZE_BYTES = 5000000000L;
@@ -108,7 +113,7 @@ public class ScreenMediaRecorder {
// Set up audio source
if (mAudioSource == MIC) {
- mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
}
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
@@ -121,10 +126,16 @@ public class ScreenMediaRecorder {
wm.getDefaultDisplay().getRealMetrics(metrics);
int screenWidth = metrics.widthPixels;
int screenHeight = metrics.heightPixels;
+ int refereshRate = (int) wm.getDefaultDisplay().getRefreshRate();
+ int vidBitRate = screenHeight * screenWidth * refereshRate / VIDEO_FRAME_RATE
+ * VIDEO_FRAME_RATE_TO_RESOLUTION_RATIO;
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
+ mMediaRecorder.setVideoEncodingProfileLevel(
+ MediaCodecInfo.CodecProfileLevel.AVCProfileHigh,
+ MediaCodecInfo.CodecProfileLevel.AVCLevel42);
mMediaRecorder.setVideoSize(screenWidth, screenHeight);
- mMediaRecorder.setVideoFrameRate(VIDEO_FRAME_RATE);
- mMediaRecorder.setVideoEncodingBitRate(VIDEO_BIT_RATE);
+ mMediaRecorder.setVideoFrameRate(refereshRate);
+ mMediaRecorder.setVideoEncodingBitRate(vidBitRate);
mMediaRecorder.setMaxDuration(MAX_DURATION_MS);
mMediaRecorder.setMaxFileSize(MAX_FILESIZE_BYTES);
@@ -203,7 +214,7 @@ public class ScreenMediaRecorder {
/**
* Store recorded video
*/
- Uri save() throws IOException {
+ protected SavedRecording save() throws IOException {
String fileName = new SimpleDateFormat("'screen-'yyyyMMdd-HHmmss'.mp4'")
.format(new Date());
@@ -241,8 +252,38 @@ public class ScreenMediaRecorder {
OutputStream os = resolver.openOutputStream(itemUri, "w");
Files.copy(mTempVideoFile.toPath(), os);
os.close();
- mTempVideoFile.delete();
if (mTempAudioFile != null) mTempAudioFile.delete();
- return itemUri;
+ DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
+ Size size = new Size(metrics.widthPixels, metrics.heightPixels);
+ SavedRecording recording = new SavedRecording(itemUri, mTempVideoFile, size);
+ mTempVideoFile.delete();
+ return recording;
+ }
+
+ /**
+ * Object representing the recording
+ */
+ public class SavedRecording {
+
+ private Uri mUri;
+ private Bitmap mThumbnailBitmap;
+
+ protected SavedRecording(Uri uri, File file, Size thumbnailSize) {
+ mUri = uri;
+ try {
+ mThumbnailBitmap = ThumbnailUtils.createVideoThumbnail(
+ file, thumbnailSize, null);
+ } catch (IOException e) {
+ Log.e(TAG, "Error creating thumbnail", e);
+ }
+ }
+
+ public Uri getUri() {
+ return mUri;
+ }
+
+ public @Nullable Bitmap getThumbnail() {
+ return mThumbnailBitmap;
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
index abd7e7159260..d057a8a43c43 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordDialog.java
@@ -24,12 +24,9 @@ import static com.android.systemui.screenrecord.ScreenRecordingAudioSource.NONE;
import android.app.Activity;
import android.app.PendingIntent;
import android.os.Bundle;
-import android.util.Log;
import android.view.Gravity;
-import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
-import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
@@ -88,8 +85,8 @@ public class ScreenRecordDialog extends Activity {
});
mModes = new ArrayList<>();
- mModes.add(INTERNAL);
mModes.add(MIC);
+ mModes.add(INTERNAL);
mModes.add(MIC_AND_INTERNAL);
mAudioSwitch = findViewById(R.id.screenrecord_audio_switch);
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java
index 2e0e746594b4..3e78489e5707 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingAdapter.java
@@ -88,12 +88,6 @@ public class ScreenRecordingAdapter extends ArrayAdapter<ScreenRecordingAudioSou
return layout;
}
- private void setDescription(LinearLayout layout, int description) {
- if (description != Resources.ID_NULL) {
- ((TextView) layout.getChildAt(1)).setText(description);
- }
- }
-
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
switch (getItem(position)) {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index a9d3772a0fdb..a624479fa63c 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -35,6 +35,7 @@ import android.app.ActivityOptions;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
@@ -494,8 +495,10 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
}
void handleImageAsScreenshot(Bitmap screenshot, Rect screenshotScreenBounds,
- Insets visibleInsets, int taskId, Consumer<Uri> finisher, Runnable onComplete) {
- // TODO use taskId and visibleInsets
+ Insets visibleInsets, int taskId, int userId, ComponentName topComponent,
+ Consumer<Uri> finisher, Runnable onComplete) {
+ // TODO: use task Id, userId, topComponent for smart handler
+ // TODO: use visibleInsets for animation
mOnCompleteRunnable = onComplete;
takeScreenshot(screenshot, finisher, screenshotScreenBounds);
}
@@ -640,6 +643,18 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
*/
private void showUiOnActionsReady(SavedImageData imageData) {
logSuccessOnActionsReady(imageData);
+
+ AccessibilityManager accessibilityManager = (AccessibilityManager)
+ mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
+ long timeoutMs = accessibilityManager.getRecommendedTimeoutMillis(
+ SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS,
+ AccessibilityManager.FLAG_CONTENT_CONTROLS);
+
+ mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
+ mScreenshotHandler.sendMessageDelayed(
+ mScreenshotHandler.obtainMessage(MESSAGE_CORNER_TIMEOUT),
+ timeoutMs);
+
if (imageData.uri != null) {
mScreenshotHandler.post(() -> {
if (mScreenshotAnimation != null && mScreenshotAnimation.isRunning()) {
@@ -653,17 +668,6 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset
} else {
createScreenshotActionsShadeAnimation(imageData).start();
}
-
- AccessibilityManager accessibilityManager = (AccessibilityManager)
- mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
- long timeoutMs = accessibilityManager.getRecommendedTimeoutMillis(
- SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS,
- AccessibilityManager.FLAG_CONTENT_CONTROLS);
-
- mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT);
- mScreenshotHandler.sendMessageDelayed(
- mScreenshotHandler.obtainMessage(MESSAGE_CORNER_TIMEOUT),
- timeoutMs);
});
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java
index 095c32f4a2ce..0017b1f79b74 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotLegacy.java
@@ -24,6 +24,7 @@ import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.Nullable;
+import android.content.ComponentName;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -234,8 +235,10 @@ public class GlobalScreenshotLegacy {
}
void handleImageAsScreenshot(Bitmap screenshot, Rect screenshotScreenBounds,
- Insets visibleInsets, int taskId, Consumer<Uri> finisher) {
- // TODO use taskId and visibleInsets
+ Insets visibleInsets, int taskId, int userId, ComponentName topComponent,
+ Consumer<Uri> finisher) {
+ // TODO: use task Id, userId, topComponent for smart handler
+ // TODO: use visibleInsets for animation
takeScreenshot(screenshot, finisher, false, false, screenshotScreenBounds);
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
index a5bab212e6b7..221174f70d66 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -123,6 +123,7 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
if (isCancelled()) {
return null;
}
+ Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
ContentResolver resolver = mContext.getContentResolver();
Bitmap image = mParams.image;
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 98030d45b05e..8322fe08d3c2 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -20,6 +20,7 @@ import static com.android.internal.util.ScreenshotHelper.SCREENSHOT_MSG_PROCESS_
import static com.android.internal.util.ScreenshotHelper.SCREENSHOT_MSG_URI;
import android.app.Service;
+import android.content.ComponentName;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Insets;
@@ -37,6 +38,7 @@ import android.view.WindowManager;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.util.ScreenshotHelper;
+import com.android.systemui.shared.recents.utilities.BitmapUtil;
import java.util.function.Consumer;
@@ -107,16 +109,19 @@ public class TakeScreenshotService extends Service {
}
break;
case WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE:
- Bitmap screenshot = screenshotRequest.getBitmap();
+ Bitmap screenshot = BitmapUtil.bundleToHardwareBitmap(
+ screenshotRequest.getBitmapBundle());
Rect screenBounds = screenshotRequest.getBoundsInScreen();
Insets insets = screenshotRequest.getInsets();
int taskId = screenshotRequest.getTaskId();
+ int userId = screenshotRequest.getUserId();
+ ComponentName topComponent = screenshotRequest.getTopComponent();
if (useCornerFlow) {
- mScreenshot.handleImageAsScreenshot(
- screenshot, screenBounds, insets, taskId, uriConsumer, onComplete);
+ mScreenshot.handleImageAsScreenshot(screenshot, screenBounds, insets,
+ taskId, userId, topComponent, uriConsumer, onComplete);
} else {
- mScreenshotLegacy.handleImageAsScreenshot(
- screenshot, screenBounds, insets, taskId, uriConsumer);
+ mScreenshotLegacy.handleImageAsScreenshot(screenshot, screenBounds, insets,
+ taskId, userId, topComponent, uriConsumer);
}
break;
default:
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 95aceed1126b..21810c0e7cf5 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -99,16 +99,19 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
private Handler mHandler;
private KeyguardStateController mKeyguardStateController;
+ private WindowManagerProxy mWindowManagerProxy;
+
private final ArrayList<WeakReference<Consumer<Boolean>>> mDockedStackExistsListeners =
new ArrayList<>();
private SplitScreenTaskOrganizer mSplits = new SplitScreenTaskOrganizer(this);
private DisplayChangeController.OnDisplayChangingListener mRotationController =
- (display, fromRotation, toRotation, t) -> {
- if (!mSplits.isSplitScreenSupported()) {
+ (display, fromRotation, toRotation, wct) -> {
+ if (!mSplits.isSplitScreenSupported() || mWindowManagerProxy == null) {
return;
}
+ WindowContainerTransaction t = new WindowContainerTransaction();
DisplayLayout displayLayout =
new DisplayLayout(mDisplayController.getDisplayLayout(display));
SplitDisplayLayout sdl = new SplitDisplayLayout(mContext, displayLayout, mSplits);
@@ -127,6 +130,17 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
if (isSplitActive()) {
WindowManagerProxy.applyHomeTasksMinimized(sdl, mSplits.mSecondary.token, t);
}
+ if (mWindowManagerProxy.queueSyncTransactionIfWaiting(t)) {
+ // Because sync transactions are serialized, its possible for an "older"
+ // bounds-change to get applied after a screen rotation. In that case, we
+ // want to actually defer on that rather than apply immediately. Of course,
+ // this means that the bounds may not change until after the rotation so
+ // the user might see some artifacts. This should be rare.
+ Slog.w(TAG, "Screen rotated while other operations were pending, this may"
+ + " result in some graphical artifacts.");
+ } else {
+ wct.merge(t, true /* transfer */);
+ }
};
private final DividerImeController mImePositionProcessor;
@@ -159,6 +173,7 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
mRecentsOptionalLazy = recentsOptionalLazy;
mForcedResizableController = new ForcedResizableInfoActivityController(context, this);
mTransactionPool = transactionPool;
+ mWindowManagerProxy = new WindowManagerProxy(mTransactionPool, mHandler);
mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mHandler);
}
@@ -278,9 +293,9 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
LayoutInflater.from(dctx).inflate(R.layout.docked_stack_divider, null);
DisplayLayout displayLayout = mDisplayController.getDisplayLayout(mContext.getDisplayId());
mView.injectDependencies(mWindowManager, mDividerState, this, mSplits, mSplitLayout,
- mImePositionProcessor);
+ mImePositionProcessor, mWindowManagerProxy);
mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE);
- mView.setMinimizedDockStack(mMinimized, mHomeStackResizable);
+ mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, null /* transaction */);
final int size = dctx.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.docked_stack_divider_thickness);
final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE;
@@ -303,7 +318,7 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
addDivider(configuration);
if (mMinimized) {
- mView.setMinimizedDockStack(true, mHomeStackResizable);
+ mView.setMinimizedDockStack(true, mHomeStackResizable, null /* transaction */);
updateTouchable();
}
mView.setHidden(isDividerHidden);
@@ -327,11 +342,13 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
if (visible) {
mView.enterSplitMode(mHomeStackResizable);
// Update state because animations won't finish.
- mView.setMinimizedDockStack(mMinimized, mHomeStackResizable);
+ mWindowManagerProxy.runInSync(
+ t -> mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, t));
+
} else {
mView.exitSplitMode();
- // un-minimize so that next entry triggers minimize anim.
- mView.setMinimizedDockStack(false /* minimized */, mHomeStackResizable);
+ mWindowManagerProxy.runInSync(
+ t -> mView.setMinimizedDockStack(false, mHomeStackResizable, t));
}
// Notify existence listeners
synchronized (mDockedStackExistsListeners) {
@@ -344,12 +361,6 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
}
}
- void onSplitDismissed() {
- updateVisibility(false /* visible */);
- mMinimized = false;
- removeDivider();
- }
-
/** Switch to minimized state if appropriate */
public void setMinimized(final boolean minimized) {
if (DEBUG) Slog.d(TAG, "posting ext setMinimized " + minimized + " vis:" + mVisible);
@@ -405,7 +416,7 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
}
}
updateTouchable();
- WindowOrganizer.applyTransaction(wct);
+ mWindowManagerProxy.applySyncTransaction(wct);
}
void setAdjustedForIme(boolean adjustedForIme) {
@@ -501,7 +512,14 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
update(mDisplayController.getDisplayContext(
mContext.getDisplayId()).getResources().getConfiguration());
// Set resizable directly here because applyEnterSplit already resizes home stack.
- mHomeStackResizable = WindowManagerProxy.applyEnterSplit(mSplits, mSplitLayout);
+ mHomeStackResizable = mWindowManagerProxy.applyEnterSplit(mSplits, mSplitLayout);
+ }
+
+ void startDismissSplit() {
+ mWindowManagerProxy.applyDismissSplit(mSplits, mSplitLayout, true /* dismissOrMaximize */);
+ updateVisibility(false /* visible */);
+ mMinimized = false;
+ removeDivider();
}
void ensureMinimizedSplit() {
@@ -530,6 +548,10 @@ public class Divider extends SystemUI implements DividerView.DividerCallbacks,
return mSplitLayout;
}
+ WindowManagerProxy getWmProxy() {
+ return mWindowManagerProxy;
+ }
+
/** @return the container token for the secondary split root task. */
public WindowContainerToken getSecondaryRoot() {
if (mSplits == null || mSplits.mSecondary == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
index 1e0c07b1cd4c..aea87f2d1971 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerImeController.java
@@ -29,7 +29,6 @@ import android.view.SurfaceControl;
import android.window.TaskOrganizer;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
-import android.window.WindowOrganizer;
import androidx.annotation.Nullable;
@@ -213,7 +212,7 @@ class DividerImeController implements DisplayImeController.ImePositionProcessor
SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
}
- WindowOrganizer.applyTransaction(wct);
+ mSplits.mDivider.getWmProxy().applySyncTransaction(wct);
// Update all the adjusted-for-ime states
if (!mPaused) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index e349b5af5b2d..2271f6de194f 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -46,6 +46,7 @@ import android.view.VelocityTracker;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewConfiguration;
+import android.view.ViewRootImpl;
import android.view.ViewTreeObserver.InternalInsetsInfo;
import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
import android.view.WindowManager;
@@ -138,7 +139,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
private final Rect mOtherInsetRect = new Rect();
private final Rect mLastResizeRect = new Rect();
private final Rect mTmpRect = new Rect();
- private final WindowManagerProxy mWindowManagerProxy = WindowManagerProxy.getInstance();
+ private WindowManagerProxy mWindowManagerProxy;
private DividerWindowManager mWindowManager;
private VelocityTracker mVelocityTracker;
private FlingAnimationUtils mFlingAnimationUtils;
@@ -360,13 +361,14 @@ public class DividerView extends FrameLayout implements OnTouchListener,
public void injectDependencies(DividerWindowManager windowManager, DividerState dividerState,
DividerCallbacks callback, SplitScreenTaskOrganizer tiles, SplitDisplayLayout sdl,
- DividerImeController imeController) {
+ DividerImeController imeController, WindowManagerProxy wmProxy) {
mWindowManager = windowManager;
mState = dividerState;
mCallback = callback;
mTiles = tiles;
mSplitLayout = sdl;
mImeController = imeController;
+ mWindowManagerProxy = wmProxy;
if (mState.mRatioPositionBeforeMinimized == 0) {
// Set the middle target as the initial state
@@ -376,10 +378,6 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
}
- public WindowManagerProxy getWindowManagerProxy() {
- return mWindowManagerProxy;
- }
-
public Rect getNonMinimizedSplitScreenSecondaryBounds() {
mOtherTaskRect.set(mSplitLayout.mSecondary);
return mOtherTaskRect;
@@ -519,7 +517,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) {
SnapTarget snapTarget = getSnapAlgorithm().calculateSnapTarget(
mStartPosition, 0 /* velocity */, false /* hardDismiss */);
- resizeStackSurfaces(calculatePosition(x, y), mStartPosition, snapTarget);
+ resizeStackSurfaces(calculatePosition(x, y), mStartPosition, snapTarget,
+ null /* transaction */);
}
break;
case MotionEvent.ACTION_UP:
@@ -608,7 +607,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
taskPositionSameAtEnd && animation.getAnimatedFraction() == 1f
? TASK_POSITION_SAME
: snapTarget.taskPosition,
- snapTarget));
+ snapTarget, null /* transaction */));
Consumer<Boolean> endAction = cancelled -> {
if (DEBUG) Slog.d(TAG, "End Fling " + cancelled + " min:" + mIsInMinimizeInteraction);
final boolean wasMinimizeInteraction = mIsInMinimizeInteraction;
@@ -716,7 +715,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
dismissOrMaximize = mDockSide == WindowManager.DOCKED_RIGHT
|| mDockSide == WindowManager.DOCKED_BOTTOM;
}
- mWindowManagerProxy.dismissOrMaximizeDocked(mTiles, dismissOrMaximize);
+ mWindowManagerProxy.dismissOrMaximizeDocked(mTiles, mSplitLayout, dismissOrMaximize);
Transaction t = mTiles.getTransaction();
setResizeDimLayer(t, true /* primary */, 0f);
setResizeDimLayer(t, false /* primary */, 0f);
@@ -806,7 +805,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mWindowManager.setTouchRegion(touchRegion);
}
- public void setMinimizedDockStack(boolean minimized, boolean isHomeStackResizable) {
+ void setMinimizedDockStack(boolean minimized, boolean isHomeStackResizable,
+ Transaction t) {
mHomeStackResizable = isHomeStackResizable;
updateDockSide();
if (!minimized) {
@@ -840,9 +840,10 @@ public class DividerView extends FrameLayout implements OnTouchListener,
// Relayout to recalculate the divider shadow when minimizing
requestLayout();
mIsInMinimizeInteraction = true;
- resizeStackSurfaces(mSplitLayout.getMinimizedSnapAlgorithm().getMiddleTarget());
+ resizeStackSurfaces(
+ mSplitLayout.getMinimizedSnapAlgorithm().getMiddleTarget(), t);
} else {
- resizeStackSurfaces(mSnapTargetBeforeMinimized);
+ resizeStackSurfaces(mSnapTargetBeforeMinimized, t);
mIsInMinimizeInteraction = false;
}
}
@@ -873,10 +874,11 @@ public class DividerView extends FrameLayout implements OnTouchListener,
* assigned to it.
*/
private SurfaceControl getWindowSurfaceControl() {
- if (getViewRootImpl() == null) {
+ final ViewRootImpl root = getViewRootImpl();
+ if (root == null) {
return null;
}
- SurfaceControl out = getViewRootImpl().getSurfaceControl();
+ SurfaceControl out = root.getSurfaceControl();
if (out != null && out.isValid()) {
return out;
}
@@ -885,15 +887,13 @@ public class DividerView extends FrameLayout implements OnTouchListener,
void exitSplitMode() {
// Reset tile bounds
- post(() -> {
- final SurfaceControl sc = getWindowSurfaceControl();
- if (sc == null) {
- return;
- }
- Transaction t = mTiles.getTransaction();
- t.hide(sc).apply();
- mTiles.releaseTransaction(t);
- });
+ final SurfaceControl sc = getWindowSurfaceControl();
+ if (sc == null) {
+ return;
+ }
+ Transaction t = mTiles.getTransaction();
+ t.hide(sc).apply();
+ mTiles.releaseTransaction(t);
int midPos = mSplitLayout.getSnapAlgorithm().getMiddleTarget().position;
WindowManagerProxy.applyResizeSplits(midPos, mSplitLayout);
}
@@ -1049,8 +1049,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mDividerSize);
}
- private void resizeStackSurfaces(SnapTarget taskSnapTarget) {
- resizeStackSurfaces(taskSnapTarget.position, taskSnapTarget.position, taskSnapTarget);
+ private void resizeStackSurfaces(SnapTarget taskSnapTarget, Transaction t) {
+ resizeStackSurfaces(taskSnapTarget.position, taskSnapTarget.position, taskSnapTarget, t);
}
void resizeSplitSurfaces(Transaction t, Rect dockedRect, Rect otherRect) {
@@ -1105,7 +1105,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
}
- void resizeStackSurfaces(int position, int taskPosition, SnapTarget taskSnapTarget) {
+ void resizeStackSurfaces(int position, int taskPosition, SnapTarget taskSnapTarget,
+ Transaction transaction) {
if (mRemoved) {
// This divider view has been removed so shouldn't have any additional influence.
return;
@@ -1123,7 +1124,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
mBackground.invalidate();
}
- Transaction t = mTiles.getTransaction();
+ final boolean ownTransaction = transaction == null;
+ final Transaction t = ownTransaction ? mTiles.getTransaction() : transaction;
mLastResizeRect.set(mDockedRect);
if (mHomeStackResizable && mIsInMinimizeInteraction) {
calculateBoundsForPosition(mSnapTargetBeforeMinimized.position, mDockSide,
@@ -1138,8 +1140,10 @@ public class DividerView extends FrameLayout implements OnTouchListener,
}
resizeSplitSurfaces(t, mDockedRect, mDockedTaskRect, mOtherRect,
mOtherTaskRect);
- t.apply();
- mTiles.releaseTransaction(t);
+ if (ownTransaction) {
+ t.apply();
+ mTiles.releaseTransaction(t);
+ }
return;
}
@@ -1201,8 +1205,10 @@ public class DividerView extends FrameLayout implements OnTouchListener,
SnapTarget closestDismissTarget = getSnapAlgorithm().getClosestDismissTarget(position);
float dimFraction = getDimFraction(position, closestDismissTarget);
setResizeDimLayer(t, isDismissTargetPrimary(closestDismissTarget), dimFraction);
- t.apply();
- mTiles.releaseTransaction(t);
+ if (ownTransaction) {
+ t.apply();
+ mTiles.releaseTransaction(t);
+ }
}
private void applyExitAnimationParallax(Rect taskRect, int position) {
@@ -1383,7 +1389,8 @@ public class DividerView extends FrameLayout implements OnTouchListener,
resizeStackSurfaces(calculatePositionForInsetBounds(),
mSplitLayout.getSnapAlgorithm().getMiddleTarget().position,
- mSplitLayout.getSnapAlgorithm().getMiddleTarget());
+ mSplitLayout.getSnapAlgorithm().getMiddleTarget(),
+ null /* transaction */);
}
void onRecentsDrawn() {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
index c496d2280222..db324822994b 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
@@ -200,8 +200,7 @@ class SplitScreenTaskOrganizer extends TaskOrganizer {
Log.d(TAG, " was in split, so this means leave it "
+ mPrimary.topActivityType + " " + mSecondary.topActivityType);
}
- WindowManagerProxy.applyDismissSplit(this, true /* dismissOrMaximize */);
- mDivider.onSplitDismissed();
+ mDivider.startDismissSplit();
} else if (!primaryIsEmpty && primaryWasEmpty && secondaryWasEmpty) {
// Wasn't in split-mode (both were empty), but now that the primary split is
// populated, we should fully enter split by moving everything else into secondary.
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java
new file mode 100644
index 000000000000..1ff404677ea6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SyncTransactionQueue.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.stackdivider;
+
+import android.os.Handler;
+import android.util.Slog;
+import android.view.SurfaceControl;
+import android.window.WindowContainerTransaction;
+import android.window.WindowContainerTransactionCallback;
+import android.window.WindowOrganizer;
+
+import androidx.annotation.NonNull;
+
+import com.android.systemui.TransactionPool;
+
+import java.util.ArrayList;
+
+/**
+ * Helper for serializing sync-transactions and corresponding callbacks.
+ */
+class SyncTransactionQueue {
+ private static final boolean DEBUG = Divider.DEBUG;
+ private static final String TAG = "SyncTransactionQueue";
+
+ // Just a little longer than the sync-engine timeout of 5s
+ private static final int REPLY_TIMEOUT = 5300;
+
+ private final TransactionPool mTransactionPool;
+ private final Handler mHandler;
+
+ // Sync Transactions currently don't support nesting or interleaving properly, so
+ // queue up transactions to run them serially.
+ private final ArrayList<SyncCallback> mQueue = new ArrayList<>();
+
+ private SyncCallback mInFlight = null;
+ private final ArrayList<TransactionRunnable> mRunnables = new ArrayList<>();
+
+ private final Runnable mOnReplyTimeout = () -> {
+ synchronized (mQueue) {
+ if (mInFlight != null && mQueue.contains(mInFlight)) {
+ Slog.w(TAG, "Sync Transaction timed-out: " + mInFlight.mWCT);
+ mInFlight.onTransactionReady(mInFlight.mId, new SurfaceControl.Transaction());
+ }
+ }
+ };
+
+ SyncTransactionQueue(TransactionPool pool, Handler handler) {
+ mTransactionPool = pool;
+ mHandler = handler;
+ }
+
+ /**
+ * Queues a sync transaction to be sent serially to WM.
+ */
+ void queue(WindowContainerTransaction wct) {
+ SyncCallback cb = new SyncCallback(wct);
+ synchronized (mQueue) {
+ if (DEBUG) Slog.d(TAG, "Queueing up " + wct);
+ mQueue.add(cb);
+ if (mQueue.size() == 1) {
+ cb.send();
+ }
+ }
+ }
+
+ /**
+ * Queues a sync transaction only if there are already sync transaction(s) queued or in flight.
+ * Otherwise just returns without queueing.
+ * @return {@code true} if queued, {@code false} if not.
+ */
+ boolean queueIfWaiting(WindowContainerTransaction wct) {
+ synchronized (mQueue) {
+ if (mQueue.isEmpty()) {
+ if (DEBUG) Slog.d(TAG, "Nothing in queue, so skip queueing up " + wct);
+ return false;
+ }
+ if (DEBUG) Slog.d(TAG, "Queue is non-empty, so queueing up " + wct);
+ SyncCallback cb = new SyncCallback(wct);
+ mQueue.add(cb);
+ if (mQueue.size() == 1) {
+ cb.send();
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Runs a runnable in sync with sync transactions (ie. when the current in-flight transaction
+ * returns. If there are no transactions in-flight, runnable executes immediately.
+ */
+ void runInSync(TransactionRunnable runnable) {
+ synchronized (mQueue) {
+ if (DEBUG) Slog.d(TAG, "Run in sync. mInFlight=" + mInFlight);
+ if (mInFlight != null) {
+ mRunnables.add(runnable);
+ return;
+ }
+ }
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
+ runnable.runWithTransaction(t);
+ t.apply();
+ mTransactionPool.release(t);
+ }
+
+ // Synchronized on mQueue
+ private void onTransactionReceived(@NonNull SurfaceControl.Transaction t) {
+ if (DEBUG) Slog.d(TAG, " Running " + mRunnables.size() + " sync runnables");
+ for (int i = 0, n = mRunnables.size(); i < n; ++i) {
+ mRunnables.get(i).runWithTransaction(t);
+ }
+ mRunnables.clear();
+ t.apply();
+ t.close();
+ }
+
+ interface TransactionRunnable {
+ void runWithTransaction(SurfaceControl.Transaction t);
+ }
+
+ private class SyncCallback extends WindowContainerTransactionCallback {
+ int mId = -1;
+ final WindowContainerTransaction mWCT;
+
+ SyncCallback(WindowContainerTransaction wct) {
+ mWCT = wct;
+ }
+
+ // Must be sychronized on mQueue
+ void send() {
+ if (mInFlight != null) {
+ throw new IllegalStateException("Sync Transactions must be serialized. In Flight: "
+ + mInFlight.mId + " - " + mInFlight.mWCT);
+ }
+ mInFlight = this;
+ if (DEBUG) Slog.d(TAG, "Sending sync transaction: " + mWCT);
+ mId = new WindowOrganizer().applySyncTransaction(mWCT, this);
+ if (DEBUG) Slog.d(TAG, " Sent sync transaction. Got id=" + mId);
+ mHandler.postDelayed(mOnReplyTimeout, REPLY_TIMEOUT);
+ }
+
+ @Override
+ public void onTransactionReady(int id,
+ @androidx.annotation.NonNull SurfaceControl.Transaction t) {
+ mHandler.post(() -> {
+ synchronized (mQueue) {
+ if (mId != id) {
+ Slog.e(TAG, "Got an unexpected onTransactionReady. Expected "
+ + mId + " but got " + id);
+ return;
+ }
+ mInFlight = null;
+ mHandler.removeCallbacks(mOnReplyTimeout);
+ if (DEBUG) Slog.d(TAG, "onTransactionReady id=" + mId);
+ mQueue.remove(this);
+ onTransactionReceived(t);
+ if (!mQueue.isEmpty()) {
+ mQueue.get(0).send();
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index 3027bd225216..c8361c63e960 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -25,9 +25,11 @@ import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.graphics.Rect;
+import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
import android.view.Display;
+import android.view.SurfaceControl;
import android.view.WindowManagerGlobal;
import android.window.TaskOrganizer;
import android.window.WindowContainerToken;
@@ -35,6 +37,7 @@ import android.window.WindowContainerTransaction;
import android.window.WindowOrganizer;
import com.android.internal.annotations.GuardedBy;
+import com.android.systemui.TransactionPool;
import java.util.ArrayList;
import java.util.List;
@@ -49,8 +52,6 @@ public class WindowManagerProxy {
private static final String TAG = "WindowManagerProxy";
private static final int[] HOME_AND_RECENTS = {ACTIVITY_TYPE_HOME, ACTIVITY_TYPE_RECENTS};
- private static final WindowManagerProxy sInstance = new WindowManagerProxy();
-
@GuardedBy("mDockedRect")
private final Rect mDockedRect = new Rect();
@@ -61,6 +62,8 @@ public class WindowManagerProxy {
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
+ private final SyncTransactionQueue mSyncTransactionQueue;
+
private final Runnable mSetTouchableRegionRunnable = new Runnable() {
@Override
public void run() {
@@ -76,16 +79,13 @@ public class WindowManagerProxy {
}
};
- private WindowManagerProxy() {
+ WindowManagerProxy(TransactionPool transactionPool, Handler handler) {
+ mSyncTransactionQueue = new SyncTransactionQueue(transactionPool, handler);
}
- public static WindowManagerProxy getInstance() {
- return sInstance;
- }
-
- void dismissOrMaximizeDocked(
- final SplitScreenTaskOrganizer tiles, final boolean dismissOrMaximize) {
- mExecutor.execute(() -> applyDismissSplit(tiles, dismissOrMaximize));
+ void dismissOrMaximizeDocked(final SplitScreenTaskOrganizer tiles, SplitDisplayLayout layout,
+ final boolean dismissOrMaximize) {
+ mExecutor.execute(() -> applyDismissSplit(tiles, layout, dismissOrMaximize));
}
public void setResizing(final boolean resizing) {
@@ -163,7 +163,7 @@ public class WindowManagerProxy {
*
* @return whether the home stack is resizable
*/
- static boolean applyEnterSplit(SplitScreenTaskOrganizer tiles, SplitDisplayLayout layout) {
+ boolean applyEnterSplit(SplitScreenTaskOrganizer tiles, SplitDisplayLayout layout) {
// Set launchtile first so that any stack created after
// getAllStackInfos and before reparent (even if unlikely) are placed
// correctly.
@@ -174,6 +174,8 @@ public class WindowManagerProxy {
if (rootTasks.isEmpty()) {
return false;
}
+ ActivityManager.RunningTaskInfo topHomeTask = null;
+ boolean homeIsTop = false;
for (int i = rootTasks.size() - 1; i >= 0; --i) {
final ActivityManager.RunningTaskInfo rootTask = rootTasks.get(i);
// Only move resizeable task to split secondary. WM will just ignore this anyways...
@@ -183,16 +185,25 @@ public class WindowManagerProxy {
!= WINDOWING_MODE_FULLSCREEN) {
continue;
}
+ // Since this iterates from bottom to top, update topHomeTask for every fullscreen task
+ // so it will be left with the status of the top one.
+ topHomeTask = isHomeOrRecentTask(rootTask) ? rootTask : null;
wct.reparent(rootTask.token, tiles.mSecondary.token, true /* onTop */);
}
// Move the secondary split-forward.
wct.reorder(tiles.mSecondary.token, true /* onTop */);
boolean isHomeResizable = applyHomeTasksMinimized(layout, null /* parent */, wct);
- WindowOrganizer.applyTransaction(wct);
+ if (isHomeResizable && topHomeTask != null) {
+ // Translate/update-crop of secondary out-of-band with sync transaction -- Until BALST
+ // is enabled, this temporarily syncs the home surface position with offset until
+ // sync transaction finishes.
+ wct.setBoundsChangeTransaction(topHomeTask.token, tiles.mHomeBounds);
+ }
+ applySyncTransaction(wct);
return isHomeResizable;
}
- private static boolean isHomeOrRecentTask(ActivityManager.RunningTaskInfo ti) {
+ static boolean isHomeOrRecentTask(ActivityManager.RunningTaskInfo ti) {
final int atype = ti.configuration.windowConfiguration.getActivityType();
return atype == ACTIVITY_TYPE_HOME || atype == ACTIVITY_TYPE_RECENTS;
}
@@ -203,7 +214,8 @@ public class WindowManagerProxy {
* split (thus resulting in the top of the secondary split becoming
* fullscreen. {@code false} resolves the other way.
*/
- static void applyDismissSplit(SplitScreenTaskOrganizer tiles, boolean dismissOrMaximize) {
+ void applyDismissSplit(SplitScreenTaskOrganizer tiles, SplitDisplayLayout layout,
+ boolean dismissOrMaximize) {
// Set launch root first so that any task created after getChildContainers and
// before reparent (pretty unlikely) are put into fullscreen.
TaskOrganizer.setLaunchRoot(Display.DEFAULT_DISPLAY, null);
@@ -229,6 +241,7 @@ public class WindowManagerProxy {
wct.reparent(primaryChildren.get(i).token, null /* parent */,
true /* onTop */);
}
+ boolean homeOnTop = false;
// Don't need to worry about home tasks because they are already in the "proper"
// order within the secondary split.
for (int i = secondaryChildren.size() - 1; i >= 0; --i) {
@@ -236,8 +249,31 @@ public class WindowManagerProxy {
wct.reparent(ti.token, null /* parent */, true /* onTop */);
if (isHomeOrRecentTask(ti)) {
wct.setBounds(ti.token, null);
+ if (i == 0) {
+ homeOnTop = true;
+ }
}
}
+ if (homeOnTop) {
+ // Translate/update-crop of secondary out-of-band with sync transaction -- instead
+ // play this in sync with new home-app frame because until BALST is enabled this
+ // shows up on screen before the syncTransaction returns.
+ // We only have access to the secondary root surface, though, so in order to
+ // position things properly, we have to take into account the existing negative
+ // offset/crop of the minimized-home task.
+ final boolean landscape = layout.mDisplayLayout.isLandscape();
+ final int posX = landscape ? layout.mSecondary.left - tiles.mHomeBounds.left
+ : layout.mSecondary.left;
+ final int posY = landscape ? layout.mSecondary.top
+ : layout.mSecondary.top - tiles.mHomeBounds.top;
+ final SurfaceControl.Transaction sft = new SurfaceControl.Transaction();
+ sft.setPosition(tiles.mSecondarySurface, posX, posY);
+ final Rect crop = new Rect(0, 0, layout.mDisplayLayout.width(),
+ layout.mDisplayLayout.height());
+ crop.offset(-posX, -posY);
+ sft.setWindowCrop(tiles.mSecondarySurface, crop);
+ wct.setBoundsChangeTransaction(tiles.mSecondary.token, sft);
+ }
} else {
// Maximize, so move non-home secondary split first
for (int i = secondaryChildren.size() - 1; i >= 0; --i) {
@@ -267,6 +303,29 @@ public class WindowManagerProxy {
}
// Reset focusable to true
wct.setFocusable(tiles.mPrimary.token, true /* focusable */);
- WindowOrganizer.applyTransaction(wct);
+ applySyncTransaction(wct);
+ }
+
+ /**
+ * Utility to apply a sync transaction serially with other sync transactions.
+ *
+ * @see SyncTransactionQueue#queue
+ */
+ void applySyncTransaction(WindowContainerTransaction wct) {
+ mSyncTransactionQueue.queue(wct);
+ }
+
+ /**
+ * @see SyncTransactionQueue#queueIfWaiting
+ */
+ boolean queueSyncTransactionIfWaiting(WindowContainerTransaction wct) {
+ return mSyncTransactionQueue.queueIfWaiting(wct);
+ }
+
+ /**
+ * @see SyncTransactionQueue#runInSync
+ */
+ void runInSync(SyncTransactionQueue.TransactionRunnable runnable) {
+ mSyncTransactionQueue.runInSync(runnable);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 217148df60e2..5628a24f40ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -52,7 +52,6 @@ import com.android.systemui.Interpolators;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.media.MediaDataManager;
-import com.android.systemui.media.MediaDeviceManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.dagger.StatusBarModule;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
@@ -102,6 +101,12 @@ public class NotificationMediaManager implements Dumpable {
PAUSED_MEDIA_STATES.add(PlaybackState.STATE_PAUSED);
PAUSED_MEDIA_STATES.add(PlaybackState.STATE_ERROR);
}
+ private static final HashSet<Integer> INACTIVE_MEDIA_STATES = new HashSet<>();
+ static {
+ INACTIVE_MEDIA_STATES.add(PlaybackState.STATE_NONE);
+ INACTIVE_MEDIA_STATES.add(PlaybackState.STATE_STOPPED);
+ INACTIVE_MEDIA_STATES.add(PlaybackState.STATE_ERROR);
+ }
private final NotificationEntryManager mEntryManager;
private final MediaDataManager mMediaDataManager;
@@ -190,8 +195,7 @@ public class NotificationMediaManager implements Dumpable {
KeyguardBypassController keyguardBypassController,
@Main DelayableExecutor mainExecutor,
DeviceConfigProxy deviceConfig,
- MediaDataManager mediaDataManager,
- MediaDeviceManager mediaDeviceManager) {
+ MediaDataManager mediaDataManager) {
mContext = context;
mMediaArtworkProcessor = mediaArtworkProcessor;
mKeyguardBypassController = keyguardBypassController;
@@ -212,13 +216,11 @@ public class NotificationMediaManager implements Dumpable {
@Override
public void onPendingEntryAdded(NotificationEntry entry) {
mediaDataManager.onNotificationAdded(entry.getKey(), entry.getSbn());
- mediaDeviceManager.onNotificationAdded(entry.getKey(), entry.getSbn());
}
@Override
public void onPreEntryUpdated(NotificationEntry entry) {
mediaDataManager.onNotificationAdded(entry.getKey(), entry.getSbn());
- mediaDeviceManager.onNotificationAdded(entry.getKey(), entry.getSbn());
}
@Override
@@ -239,7 +241,6 @@ public class NotificationMediaManager implements Dumpable {
int reason) {
onNotificationRemoved(entry.getKey());
mediaDataManager.onNotificationRemoved(entry.getKey());
- mediaDeviceManager.onNotificationRemoved(entry.getKey());
}
});
@@ -252,10 +253,24 @@ public class NotificationMediaManager implements Dumpable {
mPropertiesChangedListener);
}
+ /**
+ * Check if a state should be considered actively playing
+ * @param state a PlaybackState
+ * @return true if playing
+ */
public static boolean isPlayingState(int state) {
return !PAUSED_MEDIA_STATES.contains(state);
}
+ /**
+ * Check if a state should be considered active (playing or paused)
+ * @param state a PlaybackState
+ * @return true if active
+ */
+ public static boolean isActiveState(int state) {
+ return !INACTIVE_MEDIA_STATES.contains(state);
+ }
+
public void setUpWithPresenter(NotificationPresenter presenter) {
mPresenter = presenter;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 3dda15b5ce39..a8c03243c117 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -42,7 +42,6 @@ import com.android.systemui.statusbar.notification.stack.NotificationListContain
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.util.Assert;
-import com.android.systemui.util.Utils;
import java.util.ArrayList;
import java.util.HashMap;
@@ -150,9 +149,7 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle
final int N = activeNotifications.size();
for (int i = 0; i < N; i++) {
NotificationEntry ent = activeNotifications.get(i);
- boolean hideMedia = Utils.useQsMediaPlayer(mContext);
if (ent.isRowDismissed() || ent.isRowRemoved()
- || (ent.isMediaNotification() && hideMedia)
|| mBubbleController.isBubbleNotificationSuppressedFromShade(ent)
|| mFgsSectionController.hasEntry(ent)) {
// we don't want to update removed notifications because they could
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
index c988e1251d3f..84c8db3218e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/StatusBarDependenciesModule.java
@@ -24,7 +24,6 @@ import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.media.MediaDataManager;
-import com.android.systemui.media.MediaDeviceManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.ActionClickLogger;
import com.android.systemui.statusbar.CommandQueue;
@@ -51,8 +50,6 @@ import com.android.systemui.tracing.ProtoTracer;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.concurrency.DelayableExecutor;
-import java.util.concurrent.Executor;
-
import javax.inject.Singleton;
import dagger.Lazy;
@@ -105,8 +102,7 @@ public interface StatusBarDependenciesModule {
KeyguardBypassController keyguardBypassController,
@Main DelayableExecutor mainExecutor,
DeviceConfigProxy deviceConfigProxy,
- MediaDataManager mediaDataManager,
- MediaDeviceManager mediaDeviceManager) {
+ MediaDataManager mediaDataManager) {
return new NotificationMediaManager(
context,
statusBarLazy,
@@ -116,8 +112,7 @@ public interface StatusBarDependenciesModule {
keyguardBypassController,
mainExecutor,
deviceConfigProxy,
- mediaDataManager,
- mediaDeviceManager);
+ mediaDataManager);
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
index 3afd6235b287..6335a09cde2b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.notification;
+import static com.android.systemui.media.MediaDataManagerKt.isMediaNotification;
+
import android.Manifest;
import android.app.AppGlobals;
import android.app.Notification;
@@ -27,6 +29,7 @@ import android.service.notification.StatusBarNotification;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.ForegroundServiceController;
+import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -46,6 +49,7 @@ public class NotificationFilter {
private final NotificationGroupManager mGroupManager = Dependency.get(
NotificationGroupManager.class);
private final StatusBarStateController mStatusBarStateController;
+ private final Boolean mIsMediaFlagEnabled;
private NotificationEntryManager.KeyguardEnvironment mEnvironment;
private ShadeController mShadeController;
@@ -53,8 +57,11 @@ public class NotificationFilter {
private NotificationLockscreenUserManager mUserManager;
@Inject
- public NotificationFilter(StatusBarStateController statusBarStateController) {
+ public NotificationFilter(
+ StatusBarStateController statusBarStateController,
+ MediaFeatureFlag mediaFeatureFlag) {
mStatusBarStateController = statusBarStateController;
+ mIsMediaFlagEnabled = mediaFeatureFlag.getEnabled();
}
private NotificationEntryManager.KeyguardEnvironment getEnvironment() {
@@ -133,6 +140,10 @@ public class NotificationFilter {
}
}
}
+
+ if (mIsMediaFlagEnabled && isMediaNotification(sbn)) {
+ return true;
+ }
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java
new file mode 100644
index 000000000000..026a3ffb73cd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinator.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator;
+
+import static com.android.systemui.media.MediaDataManagerKt.isMediaNotification;
+
+import com.android.systemui.media.MediaFeatureFlag;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+
+import javax.inject.Inject;
+
+/**
+ * Coordinates hiding (filtering) of media notifications.
+ */
+public class MediaCoordinator implements Coordinator {
+ private static final String TAG = "MediaCoordinator";
+
+ private final Boolean mIsMediaFeatureEnabled;
+
+ private final NotifFilter mMediaFilter = new NotifFilter(TAG) {
+ @Override
+ public boolean shouldFilterOut(NotificationEntry entry, long now) {
+ return mIsMediaFeatureEnabled && isMediaNotification(entry.getSbn());
+ }
+ };
+
+ @Inject
+ public MediaCoordinator(MediaFeatureFlag featureFlag) {
+ mIsMediaFeatureEnabled = featureFlag.getEnabled();
+ }
+
+ @Override
+ public void attach(NotifPipeline pipeline) {
+ pipeline.addFinalizeFilter(mMediaFilter);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
index 2b279bbd553a..ac4296439507 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java
@@ -57,7 +57,8 @@ public class NotifCoordinators implements Dumpable {
BubbleCoordinator bubbleCoordinator,
HeadsUpCoordinator headsUpCoordinator,
ConversationCoordinator conversationCoordinator,
- PreparationCoordinator preparationCoordinator) {
+ PreparationCoordinator preparationCoordinator,
+ MediaCoordinator mediaCoordinator) {
dumpManager.registerDumpable(TAG, this);
mCoordinators.add(new HideLocallyDismissedNotifsCoordinator());
mCoordinators.add(hideNotifsForOtherUsersCoordinator);
@@ -72,6 +73,7 @@ public class NotifCoordinators implements Dumpable {
mCoordinators.add(preparationCoordinator);
}
// TODO: add new Coordinators here! (b/112656837)
+ mCoordinators.add(mediaCoordinator);
// TODO: add the sections in a particular ORDER (HeadsUp < People < Alerting)
for (Coordinator c : mCoordinators) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java
index 9dcc187cb0ef..87612f15ed3d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java
@@ -52,7 +52,7 @@ public class AppOpsInfo extends LinearLayout implements NotificationGuts.GutsCon
private NotificationGuts mGutsContainer;
private OnClickListener mOnOk = v -> {
- closeControls(v);
+ mGutsContainer.closeControls(v, false);
};
public AppOpsInfo(Context context, AttributeSet attrs) {
@@ -117,6 +117,7 @@ public class AppOpsInfo extends LinearLayout implements NotificationGuts.GutsCon
});
TextView ok = findViewById(R.id.ok);
ok.setOnClickListener(mOnOk);
+ ok.setAccessibilityDelegate(mGutsContainer.getAccessibilityDelegate());
}
private String getPrompt() {
@@ -160,19 +161,6 @@ public class AppOpsInfo extends LinearLayout implements NotificationGuts.GutsCon
}
}
- private void closeControls(View v) {
- mMetricsLogger.visibility(MetricsEvent.APP_OPS_GUTS, false);
- int[] parentLoc = new int[2];
- int[] targetLoc = new int[2];
- mGutsContainer.getLocationOnScreen(parentLoc);
- v.getLocationOnScreen(targetLoc);
- final int centerX = v.getWidth() / 2;
- final int centerY = v.getHeight() / 2;
- final int x = targetLoc[0] - parentLoc[0] + centerX;
- final int y = targetLoc[1] - parentLoc[1] + centerY;
- mGutsContainer.closeControls(x, y, false, false);
- }
-
@Override
public void setGutsParent(NotificationGuts guts) {
mGutsContainer = guts;
@@ -200,6 +188,7 @@ public class AppOpsInfo extends LinearLayout implements NotificationGuts.GutsCon
@Override
public boolean handleCloseControls(boolean save, boolean force) {
+ mMetricsLogger.visibility(MetricsEvent.APP_OPS_GUTS, false);
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
index b163818f68a8..93db9cdf85ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
@@ -341,7 +341,6 @@ class ChannelEditorDialogController @Inject constructor(
}
private val wmFlags = (WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
- or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED)
}
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 f7ad50edb2f6..94e12e82f850 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
@@ -1122,9 +1122,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
public void setGutsView(MenuItem item) {
- if (mGuts != null && item.getGutsView() instanceof NotificationGuts.GutsContent) {
- ((NotificationGuts.GutsContent) item.getGutsView()).setGutsParent(mGuts);
- mGuts.setGutsContent((NotificationGuts.GutsContent) item.getGutsView());
+ if (getGuts() != null && item.getGutsView() instanceof NotificationGuts.GutsContent) {
+ getGuts().setGutsContent((NotificationGuts.GutsContent) item.getGutsView());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 9925909c3e16..b0861bfbd643 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -557,9 +557,9 @@ public class NotificationContentView extends FrameLayout {
private void focusExpandButtonIfNecessary() {
if (mFocusOnVisibilityChange) {
- NotificationHeaderView header = getVisibleNotificationHeader();
- if (header != null) {
- ImageView expandButton = header.getExpandButton();
+ NotificationViewWrapper wrapper = getVisibleWrapper(mVisibleType);
+ if (wrapper != null) {
+ View expandButton = wrapper.getExpandButton();
if (expandButton != null) {
expandButton.requestAccessibilityFocus();
}
@@ -1348,7 +1348,9 @@ public class NotificationContentView extends FrameLayout {
}
ImageView bubbleButton = layout.findViewById(com.android.internal.R.id.bubble_button);
View actionContainer = layout.findViewById(com.android.internal.R.id.actions_container);
- if (bubbleButton == null || actionContainer == null) {
+ LinearLayout actionContainerLayout =
+ layout.findViewById(com.android.internal.R.id.actions_container_layout);
+ if (bubbleButton == null || actionContainer == null || actionContainerLayout == null) {
return;
}
boolean isPersonWithShortcut =
@@ -1374,8 +1376,16 @@ public class NotificationContentView extends FrameLayout {
bubbleButton.setOnClickListener(mContainingNotification.getBubbleClickListener());
bubbleButton.setVisibility(VISIBLE);
actionContainer.setVisibility(VISIBLE);
+
+ int paddingEnd = getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.bubble_visible_padding_end);
+ actionContainerLayout.setPaddingRelative(0, 0, paddingEnd, 0);
} else {
bubbleButton.setVisibility(GONE);
+
+ int paddingEnd = getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.bubble_gone_padding_end);
+ actionContainerLayout.setPaddingRelative(0, 0, paddingEnd, 0);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index 9befa313edd8..e9d89589172e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -53,6 +53,7 @@ import android.transition.TransitionManager;
import android.transition.TransitionSet;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Slog;
import android.view.LayoutInflater;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
@@ -115,6 +116,7 @@ public class NotificationConversationInfo extends LinearLayout implements
private OnSnoozeClickListener mOnSnoozeClickListener;
private OnSettingsClickListener mOnSettingsClickListener;
private NotificationGuts mGutsContainer;
+ private OnConversationSettingsClickListener mOnConversationSettingsClickListener;
@VisibleForTesting
boolean mSkipPost = false;
@@ -137,13 +139,13 @@ public class NotificationConversationInfo extends LinearLayout implements
mSelectedAction = ACTION_HOME;
mShortcutManager.requestPinShortcut(mShortcutInfo, null);
mShadeController.animateCollapsePanels();
- closeControls(v, true);
+ mGutsContainer.closeControls(v, true);
};
private OnClickListener mOnSnoozeClick = v -> {
mSelectedAction = ACTION_SNOOZE;
mOnSnoozeClickListener.onClick(v, 1);
- closeControls(v, true);
+ mGutsContainer.closeControls(v, true);
};
*/
@@ -164,7 +166,11 @@ public class NotificationConversationInfo extends LinearLayout implements
private OnClickListener mOnDone = v -> {
mPressedApply = true;
- closeControls(v, true);
+ // If the user selected Priority, maybe show the priority onboarding
+ if (mSelectedAction == ACTION_FAVORITE && shouldShowPriorityOnboarding()) {
+ showPriorityOnboarding();
+ }
+ mGutsContainer.closeControls(v, true);
};
public NotificationConversationInfo(Context context, AttributeSet attrs) {
@@ -175,6 +181,10 @@ public class NotificationConversationInfo extends LinearLayout implements
void onClick(View v, NotificationChannel channel, int appUid);
}
+ public interface OnConversationSettingsClickListener {
+ void onClick();
+ }
+
public interface OnAppSettingsClickListener {
void onClick(View v, Intent intent);
}
@@ -190,14 +200,6 @@ public class NotificationConversationInfo extends LinearLayout implements
}
mSelectedAction = selectedAction;
- onSelectedActionChanged();
- }
-
- private void onSelectedActionChanged() {
- // If the user selected Priority, maybe show the priority onboarding
- if (mSelectedAction == ACTION_FAVORITE && shouldShowPriorityOnboarding()) {
- showPriorityOnboarding();
- }
}
public void bindNotification(
@@ -216,7 +218,8 @@ public class NotificationConversationInfo extends LinearLayout implements
Provider<PriorityOnboardingDialogController.Builder> builderProvider,
boolean isDeviceProvisioned,
@Main Handler mainHandler,
- @Background Handler bgHandler) {
+ @Background Handler bgHandler,
+ OnConversationSettingsClickListener onConversationSettingsClickListener) {
mSelectedAction = -1;
mINotificationManager = iNotificationManager;
mVisualStabilityManager = visualStabilityManager;
@@ -231,6 +234,7 @@ public class NotificationConversationInfo extends LinearLayout implements
mDelegatePkg = mSbn.getOpPkg();
mIsDeviceProvisioned = isDeviceProvisioned;
mOnSnoozeClickListener = onSnoozeClickListener;
+ mOnConversationSettingsClickListener = onConversationSettingsClickListener;
mIconFactory = conversationIconFactory;
mUserContext = userContext;
mBubbleMetadata = bubbleMetadata;
@@ -258,6 +262,7 @@ public class NotificationConversationInfo extends LinearLayout implements
View done = findViewById(R.id.done);
done.setOnClickListener(mOnDone);
+ done.setAccessibilityDelegate(mGutsContainer.getAccessibilityDelegate());
}
private void bindActions() {
@@ -322,7 +327,6 @@ public class NotificationConversationInfo extends LinearLayout implements
ImageView image = findViewById(R.id.conversation_icon);
image.setImageDrawable(mIconFactory.getConversationDrawable(
mShortcutInfo, mPackageName, mAppUid, important));
-
}
private void bindPackage() {
@@ -368,14 +372,11 @@ public class NotificationConversationInfo extends LinearLayout implements
}
}
TextView groupNameView = findViewById(R.id.group_name);
- View groupDivider = findViewById(R.id.group_divider);
if (groupName != null) {
groupNameView.setText(groupName);
groupNameView.setVisibility(VISIBLE);
- groupDivider.setVisibility(VISIBLE);
} else {
groupNameView.setVisibility(GONE);
- groupDivider.setVisibility(GONE);
}
}
@@ -523,9 +524,9 @@ public class NotificationConversationInfo extends LinearLayout implements
boolean ignoreDnd = false;
try {
- ignoreDnd = (mINotificationManager
- .getConsolidatedNotificationPolicy().priorityConversationSenders
- & NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT) != 0;
+ ignoreDnd = mINotificationManager
+ .getConsolidatedNotificationPolicy().priorityConversationSenders ==
+ NotificationManager.Policy.CONVERSATION_SENDERS_IMPORTANT;
} catch (RemoteException e) {
Log.e(TAG, "Could not check conversation senders", e);
}
@@ -540,31 +541,14 @@ public class NotificationConversationInfo extends LinearLayout implements
.setView(onboardingView)
.setIgnoresDnd(ignoreDnd)
.setShowsAsBubble(showAsBubble)
+ .setIcon(((ImageView) findViewById(R.id.conversation_icon)).getDrawable())
+ .setOnSettingsClick(mOnConversationSettingsClickListener)
.build();
controller.init();
controller.show();
}
- /**
- * Closes the controls and commits the updated importance values (indirectly).
- *
- * <p><b>Note,</b> this will only get called once the view is dismissing. This means that the
- * user does not have the ability to undo the action anymore.
- */
- @VisibleForTesting
- void closeControls(View v, boolean save) {
- int[] parentLoc = new int[2];
- int[] targetLoc = new int[2];
- mGutsContainer.getLocationOnScreen(parentLoc);
- v.getLocationOnScreen(targetLoc);
- final int centerX = v.getWidth() / 2;
- final int centerY = v.getHeight() / 2;
- final int x = targetLoc[0] - parentLoc[0] + centerX;
- final int y = targetLoc[1] - parentLoc[1] + centerY;
- mGutsContainer.closeControls(x, y, save, false /* force */);
- }
-
@Override
public void setGutsParent(NotificationGuts guts) {
mGutsContainer = guts;
@@ -634,8 +618,7 @@ public class NotificationConversationInfo extends LinearLayout implements
try {
switch (mAction) {
case ACTION_FAVORITE:
- mChannelToUpdate.setImportantConversation(
- !mChannelToUpdate.isImportantConversation());
+ mChannelToUpdate.setImportantConversation(true);
if (mChannelToUpdate.isImportantConversation()) {
mChannelToUpdate.setAllowBubbles(true);
if (mAppBubble == BUBBLE_PREFERENCE_NONE) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
index c762b73a1648..eeac46a60ac8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
@@ -22,12 +22,14 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
import androidx.annotation.Nullable;
@@ -59,6 +61,31 @@ public class NotificationGuts extends FrameLayout {
private GutsContent mGutsContent;
+ private View.AccessibilityDelegate mGutsContentAccessibilityDelegate =
+ new View.AccessibilityDelegate() {
+ @Override
+ public void onInitializeAccessibilityNodeInfo(
+ View host, AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(host, info);
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
+ }
+
+ @Override
+ public boolean performAccessibilityAction(View host, int action, Bundle args) {
+ if (super.performAccessibilityAction(host, action, args)) {
+ return true;
+ }
+
+ switch (action) {
+ case AccessibilityNodeInfo.ACTION_LONG_CLICK:
+ closeControls(host, false);
+ return true;
+ }
+
+ return false;
+ }
+ };
+
public interface GutsContent {
public void setGutsParent(NotificationGuts listener);
@@ -110,6 +137,11 @@ public class NotificationGuts extends FrameLayout {
* view on the lockscreen
*/
boolean needsFalsingProtection();
+
+ /**
+ * Equivalent to {@link View#setAccessibilityDelegate(AccessibilityDelegate)}
+ */
+ void setAccessibilityDelegate(AccessibilityDelegate gutsContentAccessibilityDelegate);
}
public interface OnGutsClosedListener {
@@ -146,6 +178,8 @@ public class NotificationGuts extends FrameLayout {
}
public void setGutsContent(GutsContent content) {
+ content.setGutsParent(this);
+ content.setAccessibilityDelegate(mGutsContentAccessibilityDelegate);
mGutsContent = content;
removeAllViews();
addView(mGutsContent.getContentView());
@@ -237,13 +271,29 @@ public class NotificationGuts extends FrameLayout {
/**
* Closes any exposed guts/views.
+ */
+ public void closeControls(View eventSource, boolean save) {
+ int[] parentLoc = new int[2];
+ int[] targetLoc = new int[2];
+ getLocationOnScreen(parentLoc);
+ eventSource.getLocationOnScreen(targetLoc);
+ final int centerX = eventSource.getWidth() / 2;
+ final int centerY = eventSource.getHeight() / 2;
+ final int x = targetLoc[0] - parentLoc[0] + centerX;
+ final int y = targetLoc[1] - parentLoc[1] + centerY;
+
+ closeControls(x, y, save, false);
+ }
+
+ /**
+ * Closes any exposed guts/views.
*
* @param x x coordinate to animate the close circular reveal with
* @param y y coordinate to animate the close circular reveal with
* @param save whether the state should be saved
* @param force whether the guts should be force-closed regardless of state.
*/
- public void closeControls(int x, int y, boolean save, boolean force) {
+ private void closeControls(int x, int y, boolean save, boolean force) {
// First try to dismiss any blocking helper.
boolean wasBlockingHelperDismissed =
Dependency.get(NotificationBlockingHelperManager.class)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index a64dcdffff1e..1074adc3383d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -216,6 +216,11 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
}
}
+ private void startConversationSettingsActivity(int uid, ExpandableNotificationRow row) {
+ final Intent intent = new Intent(Settings.ACTION_CONVERSATION_SETTINGS);
+ mNotificationActivityStarter.startNotificationGutsIntent(intent, uid, row);
+ }
+
private boolean bindGuts(final ExpandableNotificationRow row) {
row.ensureGutsInflated();
return bindGuts(row, mGutsMenuItem);
@@ -438,6 +443,12 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
mListContainer.getSwipeActionHelper().snooze(sbn, hours);
};
+ final NotificationConversationInfo.OnConversationSettingsClickListener
+ onConversationSettingsListener =
+ () -> {
+ startConversationSettingsActivity(sbn.getUid(), row);
+ };
+
if (!userHandle.equals(UserHandle.ALL)
|| mLockscreenUserManager.getCurrentUserId() == UserHandle.USER_SYSTEM) {
onSettingsClick = (View v, NotificationChannel channel, int appUid) -> {
@@ -468,7 +479,8 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
mBuilderProvider,
mDeviceProvisionedController.isDeviceProvisioned(),
mMainHandler,
- mBgHandler);
+ mBgHandler,
+ onConversationSettingsListener);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 334599930b63..a131ebef77db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -141,7 +141,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
// used by standard ui
private OnClickListener mOnDismissSettings = v -> {
mPressedApply = true;
- closeControls(v, true);
+ mGutsContainer.closeControls(v, true);
};
public NotificationInfo(Context context, AttributeSet attrs) {
@@ -250,7 +250,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
View done = findViewById(R.id.done);
done.setOnClickListener(mOnDismissSettings);
-
+ done.setAccessibilityDelegate(mGutsContainer.getAccessibilityDelegate());
View silent = findViewById(R.id.silence);
View alert = findViewById(R.id.alert);
@@ -330,7 +330,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
mUniqueChannelsInRow, mPkgIcon, mOnSettingsClickListener);
mChannelEditorDialogController.setOnFinishListener(() -> {
mPresentingChannelEditorDialog = false;
- closeControls(this, false);
+ mGutsContainer.closeControls(this, false);
});
mChannelEditorDialogController.show();
}
@@ -375,14 +375,11 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
}
TextView groupNameView = findViewById(R.id.group_name);
- View divider = findViewById(R.id.group_divider);
if (groupName != null) {
groupNameView.setText(groupName);
groupNameView.setVisibility(VISIBLE);
- divider.setVisibility(VISIBLE);
} else {
groupNameView.setVisibility(GONE);
- divider.setVisibility(GONE);
}
}
@@ -531,25 +528,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
return intent;
}
- /**
- * Closes the controls and commits the updated importance values (indirectly).
- *
- * <p><b>Note,</b> this will only get called once the view is dismissing. This means that the
- * user does not have the ability to undo the action anymore.
- */
- @VisibleForTesting
- void closeControls(View v, boolean save) {
- int[] parentLoc = new int[2];
- int[] targetLoc = new int[2];
- mGutsContainer.getLocationOnScreen(parentLoc);
- v.getLocationOnScreen(targetLoc);
- final int centerX = v.getWidth() / 2;
- final int centerY = v.getHeight() / 2;
- final int x = targetLoc[0] - parentLoc[0] + centerX;
- final int y = targetLoc[1] - parentLoc[1] + centerY;
- mGutsContainer.closeControls(x, y, save, false /* force */);
- }
-
@Override
public void setGutsParent(NotificationGuts guts) {
mGutsContainer = guts;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
index cde3dfd66aaf..1ffb244b51c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
@@ -380,16 +380,8 @@ public class NotificationSnooze extends LinearLayout
private void undoSnooze(View v) {
mSelectedOption = null;
- int[] parentLoc = new int[2];
- int[] targetLoc = new int[2];
- mGutsContainer.getLocationOnScreen(parentLoc);
- v.getLocationOnScreen(targetLoc);
- final int centerX = v.getWidth() / 2;
- final int centerY = v.getHeight() / 2;
- final int x = targetLoc[0] - parentLoc[0] + centerX;
- final int y = targetLoc[1] - parentLoc[1] + centerY;
showSnoozeOptions(false);
- mGutsContainer.closeControls(x, y, false /* save */, false /* force */);
+ mGutsContainer.closeControls(v, false);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
index ea059cbcf3e1..f1fe54ad4024 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
@@ -89,7 +89,7 @@ public class PartialConversationInfo extends LinearLayout implements
private OnClickListener mOnDone = v -> {
mPressedApply = true;
- closeControls(v, true);
+ mGutsContainer.closeControls(v, true);
};
public PartialConversationInfo(Context context, AttributeSet attrs) {
@@ -132,6 +132,7 @@ public class PartialConversationInfo extends LinearLayout implements
View done = findViewById(R.id.done);
done.setOnClickListener(mOnDone);
+ done.setAccessibilityDelegate(mGutsContainer.getAccessibilityDelegate());
}
private void bindActions() {
@@ -172,7 +173,7 @@ public class PartialConversationInfo extends LinearLayout implements
mUniqueChannelsInRow, mPkgIcon, mOnSettingsClickListener);
mChannelEditorDialogController.setOnFinishListener(() -> {
mPresentingChannelEditorDialog = false;
- closeControls(this, false);
+ mGutsContainer.closeControls(this, false);
});
mChannelEditorDialogController.show();
}
@@ -240,7 +241,6 @@ public class PartialConversationInfo extends LinearLayout implements
} catch (PackageManager.NameNotFoundException e) {
mPkgIcon = mPm.getDefaultActivityIcon();
}
- ((TextView) findViewById(R.id.pkg_name)).setText(mAppName);
}
private void bindDelegate() {
@@ -269,14 +269,11 @@ public class PartialConversationInfo extends LinearLayout implements
}
}
TextView groupNameView = findViewById(R.id.group_name);
- View groupDivider = findViewById(R.id.group_divider);
if (groupName != null) {
groupNameView.setText(groupName);
groupNameView.setVisibility(VISIBLE);
- groupDivider.setVisibility(VISIBLE);
} else {
groupNameView.setVisibility(GONE);
- groupDivider.setVisibility(GONE);
}
}
@@ -320,25 +317,6 @@ public class PartialConversationInfo extends LinearLayout implements
}
}
- /**
- * Closes the controls and commits the updated importance values (indirectly).
- *
- * <p><b>Note,</b> this will only get called once the view is dismissing. This means that the
- * user does not have the ability to undo the action anymore.
- */
- @VisibleForTesting
- void closeControls(View v, boolean save) {
- int[] parentLoc = new int[2];
- int[] targetLoc = new int[2];
- mGutsContainer.getLocationOnScreen(parentLoc);
- v.getLocationOnScreen(targetLoc);
- final int centerX = v.getWidth() / 2;
- final int centerY = v.getHeight() / 2;
- final int x = targetLoc[0] - parentLoc[0] + centerX;
- final int y = targetLoc[1] - parentLoc[1] + centerY;
- mGutsContainer.closeControls(x, y, save, false /* force */);
- }
-
@Override
public void setGutsParent(NotificationGuts guts) {
mGutsContainer = guts;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt
index d1b405256f39..c88f0bdc2acb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PriorityOnboardingDialogController.kt
@@ -21,19 +21,21 @@ import android.content.Context
import android.graphics.Color
import android.graphics.PixelFormat
import android.graphics.drawable.ColorDrawable
+import android.graphics.drawable.Drawable
+import android.text.SpannableStringBuilder
+import android.text.style.BulletSpan
import android.view.Gravity
import android.view.View
-import android.view.View.GONE
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import android.view.Window
import android.view.WindowInsets.Type.statusBars
import android.view.WindowManager
-import android.widget.LinearLayout
+import android.widget.ImageView
import android.widget.TextView
import com.android.systemui.Prefs
import com.android.systemui.R
-import java.lang.IllegalStateException
+import com.android.systemui.statusbar.notification.row.NotificationConversationInfo.OnConversationSettingsClickListener
import javax.inject.Inject
/**
@@ -43,7 +45,9 @@ class PriorityOnboardingDialogController @Inject constructor(
val view: View,
val context: Context,
val ignoresDnd: Boolean,
- val showsAsBubble: Boolean
+ val showsAsBubble: Boolean,
+ val icon : Drawable,
+ val onConversationSettingsClickListener : OnConversationSettingsClickListener
) {
private lateinit var dialog: Dialog
@@ -62,11 +66,21 @@ class PriorityOnboardingDialogController @Inject constructor(
dialog.dismiss()
}
+ private fun settings() {
+ // Log that the user has seen the onboarding
+ Prefs.putBoolean(context, Prefs.Key.HAS_SEEN_PRIORITY_ONBOARDING, true)
+ dialog.dismiss()
+ onConversationSettingsClickListener?.onClick()
+ }
+
class Builder @Inject constructor() {
private lateinit var view: View
private lateinit var context: Context
private var ignoresDnd = false
private var showAsBubble = false
+ private lateinit var icon: Drawable
+ private lateinit var onConversationSettingsClickListener
+ : OnConversationSettingsClickListener
fun setView(v: View): Builder {
view = v
@@ -88,9 +102,20 @@ class PriorityOnboardingDialogController @Inject constructor(
return this
}
+ fun setIcon(draw : Drawable) : Builder {
+ icon = draw
+ return this
+ }
+
+ fun setOnSettingsClick(onClick : OnConversationSettingsClickListener) : Builder {
+ onConversationSettingsClickListener = onClick
+ return this
+ }
+
fun build(): PriorityOnboardingDialogController {
val controller = PriorityOnboardingDialogController(
- view, context, ignoresDnd, showAsBubble)
+ view, context, ignoresDnd, showAsBubble, icon,
+ onConversationSettingsClickListener)
return controller
}
}
@@ -113,13 +138,32 @@ class PriorityOnboardingDialogController @Inject constructor(
done()
}
- if (!ignoresDnd) {
- findViewById<LinearLayout>(R.id.ignore_dnd_tip).visibility = GONE
+ findViewById<TextView>(R.id.settings_button)?.setOnClickListener {
+ settings()
}
- if (!showsAsBubble) {
- findViewById<LinearLayout>(R.id.floating_bubble_tip).visibility = GONE
+ findViewById<ImageView>(R.id.conversation_icon)?.setImageDrawable(icon)
+
+ val gapWidth = dialog.context.getResources().getDimensionPixelSize(
+ R.dimen.conversation_onboarding_bullet_gap_width)
+ val description = SpannableStringBuilder()
+ description.append(context.getText(R.string.priority_onboarding_show_at_top_text),
+ BulletSpan(gapWidth), /* flags */0)
+ description.append(System.lineSeparator())
+ description.append(context.getText(R.string.priority_onboarding_show_avatar_text),
+ BulletSpan(gapWidth), /* flags */0)
+ if (showsAsBubble) {
+ description.append(System.lineSeparator())
+ description.append(context.getText(
+ R.string.priority_onboarding_appear_as_bubble_text),
+ BulletSpan(gapWidth), /* flags */0)
+ }
+ if (ignoresDnd) {
+ description.append(System.lineSeparator())
+ description.append(context.getText(R.string.priority_onboarding_ignores_dnd_text),
+ BulletSpan(gapWidth), /* flags */0)
}
+ findViewById<TextView>(R.id.behaviors).setText(description)
window?.apply {
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
@@ -129,7 +173,7 @@ class PriorityOnboardingDialogController @Inject constructor(
attributes = attributes.apply {
format = PixelFormat.TRANSLUCENT
- title = ChannelEditorDialogController::class.java.simpleName
+ title = PriorityOnboardingDialogController::class.java.simpleName
gravity = Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL
fitInsetsTypes = attributes.fitInsetsTypes and statusBars().inv()
width = MATCH_PARENT
@@ -140,7 +184,6 @@ class PriorityOnboardingDialogController @Inject constructor(
}
private val wmFlags = (WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS
- or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
index 15499b87d56d..fe70c818216e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt
@@ -50,6 +50,7 @@ class NotificationConversationTemplateViewWrapper constructor(
private lateinit var conversationBadgeBg: View
private lateinit var expandButton: View
private lateinit var expandButtonContainer: View
+ private lateinit var expandButtonInnerContainer: View
private lateinit var imageMessageContainer: ViewGroup
private lateinit var messagingLinearLayout: MessagingLinearLayout
private lateinit var conversationTitleView: View
@@ -69,6 +70,8 @@ class NotificationConversationTemplateViewWrapper constructor(
expandButton = requireViewById(com.android.internal.R.id.expand_button)
expandButtonContainer =
requireViewById(com.android.internal.R.id.expand_button_container)
+ expandButtonInnerContainer =
+ requireViewById(com.android.internal.R.id.expand_button_inner_container)
importanceRing = requireViewById(com.android.internal.R.id.conversation_icon_badge_ring)
appName = requireViewById(com.android.internal.R.id.app_name_text)
conversationTitleView = requireViewById(com.android.internal.R.id.conversation_text)
@@ -134,6 +137,8 @@ class NotificationConversationTemplateViewWrapper constructor(
)
}
+ override fun getExpandButton() = expandButtonInnerContainer
+
override fun setShelfIconVisible(visible: Boolean) {
if (conversationLayout.isImportantConversation) {
if (conversationIconView.visibility != GONE) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
index f8b783113ccb..4c9cb209424a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java
@@ -317,6 +317,11 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper {
}
@Override
+ public View getExpandButton() {
+ return mExpandButton;
+ }
+
+ @Override
public int getOriginalIconColor() {
return mIcon.getOriginalIconColor();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index 02e537d2879f..30080e3d8cc2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -240,6 +240,13 @@ public abstract class NotificationViewWrapper implements TransformableView {
return null;
}
+ /**
+ * @return the expand button if it exists
+ */
+ public @Nullable View getExpandButton() {
+ return null;
+ }
+
public int getOriginalIconColor() {
return Notification.COLOR_INVALID;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
index ba7675f27cf4..0bdac39f35e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.kt
@@ -287,21 +287,17 @@ class NotificationSectionsManager @Inject internal constructor(
// Is there a section discontinuity? This usually occurs due to HUNs
if (prev?.entry?.bucket?.let { it > child.entry.bucket } == true) {
// Remove existing headers, and move the Incoming header if necessary
- if (alertingHeaderTarget != -1) {
- if (showHeaders && incomingHeaderTarget != -1) {
- incomingHeaderTarget = alertingHeaderTarget
- }
- alertingHeaderTarget = -1
- }
- if (peopleHeaderTarget != -1) {
- if (showHeaders && incomingHeaderTarget != -1) {
- incomingHeaderTarget = peopleHeaderTarget
- }
- peopleHeaderTarget = -1
- }
- if (showHeaders && incomingHeaderTarget == -1) {
- incomingHeaderTarget = 0
+ incomingHeaderTarget = when {
+ !showHeaders -> -1
+ incomingHeaderTarget != -1 -> incomingHeaderTarget
+ peopleHeaderTarget != -1 -> peopleHeaderTarget
+ alertingHeaderTarget != -1 -> alertingHeaderTarget
+ gentleHeaderTarget != -1 -> gentleHeaderTarget
+ else -> 0
}
+ peopleHeaderTarget = -1
+ alertingHeaderTarget = -1
+ gentleHeaderTarget = -1
// Walk backwards changing all previous notifications to the Incoming
// section
for (j in i - 1 downTo lastIncomingIndex + 1) {
@@ -323,6 +319,9 @@ class NotificationSectionsManager @Inject internal constructor(
peopleHeaderTarget = i
// Offset the target if there are other headers before this that
// will be moved.
+ if (currentIncomingHeaderIdx != -1 && incomingHeaderTarget == -1) {
+ peopleHeaderTarget--
+ }
if (currentPeopleHeaderIdx != -1) {
peopleHeaderTarget--
}
@@ -340,6 +339,13 @@ class NotificationSectionsManager @Inject internal constructor(
alertingHeaderTarget = i
// Offset the target if there are other headers before this that
// will be moved.
+ if (currentIncomingHeaderIdx != -1 && incomingHeaderTarget == -1) {
+ alertingHeaderTarget--
+ }
+ if (currentPeopleHeaderIdx != -1 && peopleHeaderTarget == -1) {
+ // People header will be removed
+ alertingHeaderTarget--
+ }
if (currentAlertingHeaderIdx != -1) {
alertingHeaderTarget--
}
@@ -354,6 +360,17 @@ class NotificationSectionsManager @Inject internal constructor(
gentleHeaderTarget = i
// Offset the target if there are other headers before this that
// will be moved.
+ if (currentIncomingHeaderIdx != -1 && incomingHeaderTarget == -1) {
+ gentleHeaderTarget--
+ }
+ if (currentPeopleHeaderIdx != -1 && peopleHeaderTarget == -1) {
+ // People header will be removed
+ gentleHeaderTarget--
+ }
+ if (currentAlertingHeaderIdx != -1 && alertingHeaderTarget == -1) {
+ // Alerting header will be removed
+ gentleHeaderTarget--
+ }
if (currentGentleHeaderIdx != -1) {
gentleHeaderTarget--
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index 79515415f1c3..fc8c8dbba7fd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -274,7 +274,7 @@ public class AutoTileManager {
}
if (value != 0) {
if (mSpec.startsWith(CustomTile.PREFIX)) {
- mHost.addTile(CustomTile.getComponentFromSpec(mSpec));
+ mHost.addTile(CustomTile.getComponentFromSpec(mSpec), /* end */ true);
} else {
mHost.addTile(mSpec);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index 46c873db8a08..4337e20c0a39 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -40,6 +40,7 @@ import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.phone.ReverseLinearLayout.ReverseRelativeLayout;
import com.android.systemui.statusbar.policy.KeyButtonView;
+import java.io.PrintWriter;
import java.util.Objects;
public class NavigationBarInflaterView extends FrameLayout
@@ -469,4 +470,10 @@ public class NavigationBarInflaterView extends FrameLayout
private static float convertDpToPx(Context context, float dp) {
return dp * context.getResources().getDisplayMetrics().density;
}
+
+ public void dump(PrintWriter pw) {
+ pw.println("NavigationBarInflaterView {");
+ pw.println(" mCurrentLayout: " + mCurrentLayout);
+ pw.println(" }");
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 2978772cac5e..6b37ac317cdd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -1198,6 +1198,9 @@ public class NavigationBarView extends FrameLayout implements
pw.println(" }");
+ if (mNavigationInflaterView != null) {
+ mNavigationInflaterView.dump(pw);
+ }
mContextualButtonGroup.dump(pw);
mRecentsOnboarding.dump(pw);
mRegionSamplingHelper.dump(pw);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index f58cce58af74..76c51d61459a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -572,6 +572,9 @@ public class NotificationIconAreaController implements DarkReceiver,
.setInterpolator(Interpolators.LINEAR)
.setDuration(AOD_ICONS_APPEAR_DURATION)
.start();
+ } else {
+ mAodIcons.setAlpha(1.0f);
+ mAodIcons.setTranslationY(0);
}
}
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 e0e52001e740..1bc42d1a169d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -2253,6 +2253,8 @@ public class StatusBar extends SystemUI implements DemoMode,
updateHideIconsForBouncer(false /* animate */);
}
}
+
+ updateBubblesVisibility();
}
@Override
@@ -2268,6 +2270,8 @@ public class StatusBar extends SystemUI implements DemoMode,
}
mLightBarController.onStatusBarAppearanceChanged(appearanceRegions, barModeChanged,
mStatusBarMode, navbarColorManagedByIme);
+
+ updateBubblesVisibility();
}
@Override
@@ -2311,6 +2315,7 @@ public class StatusBar extends SystemUI implements DemoMode,
final int barMode = barMode(mTransientShown, mAppearance);
if (updateBarMode(barMode)) {
mLightBarController.onStatusBarModeChanged(barMode);
+ updateBubblesVisibility();
}
}
@@ -2395,6 +2400,14 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationPanelViewController.setQsScrimEnabled(scrimEnabled);
}
+ /** Temporarily hides Bubbles if the status bar is hidden. */
+ private void updateBubblesVisibility() {
+ mBubbleController.onStatusBarVisibilityChanged(
+ mStatusBarMode != MODE_LIGHTS_OUT
+ && mStatusBarMode != MODE_LIGHTS_OUT_TRANSPARENT
+ && !mStatusBarWindowHidden);
+ }
+
void checkBarMode(@TransitionMode int mode, @WindowVisibleState int windowState,
BarTransitions transitions) {
final boolean anim = !mNoAnimationOnNextBarModeChange && mDeviceInteractive
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 b4de3cd5d43b..18a7adda3f7d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -640,8 +640,7 @@ public class MobileSignalController extends SignalController<
+ " dataState=" + state.getDataRegistrationState());
}
mServiceState = state;
- // onDisplayInfoChanged is invoked directly after onServiceStateChanged, so not calling
- // updateTelephony() to prevent icon flickering in case of overrides.
+ updateTelephony();
}
@Override
@@ -651,12 +650,6 @@ public class MobileSignalController extends SignalController<
+ " type=" + networkType);
}
mDataState = state;
- if (networkType != mTelephonyDisplayInfo.getNetworkType()) {
- Log.d(mTag, "onDataConnectionStateChanged:"
- + " network type change and reset displayInfo. type=" + networkType);
- mTelephonyDisplayInfo = new TelephonyDisplayInfo(networkType,
- TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE);
- }
updateTelephony();
}
diff --git a/packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java b/packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java
index 6c3538cb6142..a31ea7c3ab17 100644
--- a/packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java
+++ b/packages/SystemUI/src/com/android/systemui/util/DismissCircleView.java
@@ -40,7 +40,7 @@ public class DismissCircleView extends FrameLayout {
setBackground(res.getDrawable(R.drawable.dismiss_circle_background));
- mIconView.setImageDrawable(res.getDrawable(R.drawable.dismiss_target_x));
+ mIconView.setImageDrawable(res.getDrawable(R.drawable.ic_close_white));
addView(mIconView);
setViewSizes();
diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java
index b1792d003290..5c9db54a0f00 100644
--- a/packages/SystemUI/src/com/android/systemui/util/Utils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java
@@ -133,4 +133,13 @@ public class Utils {
Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS, 1);
return flag > 0;
}
+
+ /**
+ * Allow media resumption controls. Requires {@link #useQsMediaPlayer(Context)} to be enabled.
+ * Off by default, but can be enabled by setting to 1
+ */
+ public static boolean useMediaResumption(Context context) {
+ int flag = Settings.System.getInt(context.getContentResolver(), "qs_media_resumption", 0);
+ return useQsMediaPlayer(context) && flag > 0;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index ce032e2ceaec..3455ff47de8d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -212,7 +212,6 @@ public class VolumeDialogImpl implements VolumeDialog,
mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt
index f46819252fac..2aed75e6519f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt
@@ -29,9 +29,9 @@ import org.junit.runner.RunWith
class BubblePersistentRepositoryTest : SysuiTestCase() {
private val bubbles = listOf(
- BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1"),
- BubbleEntity(10, "com.example.chat", "alice and bob", "key-2"),
- BubbleEntity(0, "com.example.messenger", "shortcut-2", "key-3")
+ BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1", 120, 0),
+ BubbleEntity(10, "com.example.chat", "alice and bob", "key-2", 0, 16537428),
+ BubbleEntity(0, "com.example.messenger", "shortcut-2", "key-3", 120, 0)
)
private lateinit var repository: BubblePersistentRepository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt
index 2bb6bb8ebe14..f9d611c2bb33 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt
@@ -37,9 +37,9 @@ class BubbleVolatileRepositoryTest : SysuiTestCase() {
private val user0 = UserHandle.of(0)
private val user10 = UserHandle.of(10)
- private val bubble1 = BubbleEntity(0, PKG_MESSENGER, "shortcut-1", "k1")
- private val bubble2 = BubbleEntity(10, PKG_CHAT, "alice and bob", "k2")
- private val bubble3 = BubbleEntity(0, PKG_MESSENGER, "shortcut-2", "k3")
+ private val bubble1 = BubbleEntity(0, PKG_MESSENGER, "shortcut-1", "k1", 120, 0)
+ private val bubble2 = BubbleEntity(10, PKG_CHAT, "alice and bob", "k2", 0, 16537428)
+ private val bubble3 = BubbleEntity(0, PKG_MESSENGER, "shortcut-2", "k3", 120, 0)
private val bubbles = listOf(bubble1, bubble2, bubble3)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt
index 79701ecf70f8..49467874dd8b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt
@@ -31,17 +31,17 @@ import java.io.ByteArrayOutputStream
class BubbleXmlHelperTest : SysuiTestCase() {
private val bubbles = listOf(
- BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1"),
- BubbleEntity(10, "com.example.chat", "alice and bob", "k2"),
- BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3")
+ BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1", 120, 0),
+ BubbleEntity(10, "com.example.chat", "alice and bob", "k2", 0, 16537428),
+ BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3", 120, 0)
)
@Test
fun testWriteXml() {
val expectedEntries = """
- <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" />
- <bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" />
- <bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" />
+ <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" />
+ <bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" />
+ <bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" />
""".trimIndent()
ByteArrayOutputStream().use {
writeXml(it, bubbles)
@@ -56,9 +56,9 @@ class BubbleXmlHelperTest : SysuiTestCase() {
val src = """
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<bs>
- <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" />
- <bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" />
- <bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" />
+ <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" h="120" hid="0" />
+ <bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" h="0" hid="16537428" />
+ <bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" h="120" hid="0" />
</bs>
""".trimIndent()
val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8)))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferFreezerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferFreezerTest.kt
new file mode 100644
index 000000000000..eb38073a85f7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/dump/LogBufferFreezerTest.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.dump
+
+import android.content.BroadcastReceiver
+import android.content.IntentFilter
+import android.os.UserHandle
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.capture
+import com.android.systemui.util.mockito.eq
+import com.android.systemui.util.time.FakeSystemClock
+import org.junit.Before
+import org.junit.Test
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class LogBufferFreezerTest : SysuiTestCase() {
+
+ lateinit var freezer: LogBufferFreezer
+ lateinit var receiver: BroadcastReceiver
+
+ @Mock
+ lateinit var dumpManager: DumpManager
+ @Mock
+ lateinit var broadcastDispatcher: BroadcastDispatcher
+ @Captor
+ lateinit var receiverCaptor: ArgumentCaptor<BroadcastReceiver>
+
+ val clock = FakeSystemClock()
+ val executor = FakeExecutor(clock)
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ freezer = LogBufferFreezer(dumpManager, executor, 500)
+
+ freezer.attach(broadcastDispatcher)
+
+ verify(broadcastDispatcher)
+ .registerReceiver(
+ capture(receiverCaptor),
+ any(IntentFilter::class.java),
+ eq(executor),
+ any(UserHandle::class.java))
+ receiver = receiverCaptor.value
+ }
+
+ @Test
+ fun testBuffersAreFrozenInResponseToBroadcast() {
+ // WHEN the bugreport intent is fired
+ receiver.onReceive(null, null)
+
+ // THEN the buffers are frozen
+ verify(dumpManager).freezeBuffers()
+ }
+
+ @Test
+ fun testBuffersAreUnfrozenAfterTimeout() {
+ // GIVEN that we've already frozen the buffers in response to a broadcast
+ receiver.onReceive(null, null)
+ verify(dumpManager).freezeBuffers()
+
+ // WHEN the timeout expires
+ clock.advanceTime(501)
+
+ // THEN the buffers are unfrozen
+ verify(dumpManager).unfreezeBuffers()
+ }
+
+ @Test
+ fun testBuffersAreNotPrematurelyUnfrozen() {
+ // GIVEN that we received a broadcast 499ms ago (shortly before the timeout would expire)
+ receiver.onReceive(null, null)
+ verify(dumpManager).freezeBuffers()
+ clock.advanceTime(499)
+
+ // WHEN we receive a second broadcast
+ receiver.onReceive(null, null)
+
+ // THEN the buffers are frozen a second time
+ verify(dumpManager, times(2)).freezeBuffers()
+
+ // THEN when we advance beyond the first timeout, nothing happens
+ clock.advanceTime(101)
+ verify(dumpManager, never()).unfreezeBuffers()
+
+ // THEN only when we advance past the reset timeout window are the buffers unfrozen
+ clock.advanceTime(401)
+ verify(dumpManager).unfreezeBuffers()
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
index 32546333aac3..329af2b7f62b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java
@@ -19,6 +19,7 @@ package com.android.systemui.globalactions;
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -244,7 +245,7 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
}
@Test
- public void testCreateActionItems_maxThree() {
+ public void testCreateActionItems_maxThree_noOverflow() {
mGlobalActionsDialog = spy(mGlobalActionsDialog);
// allow 3 items to be shown
doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems();
@@ -254,13 +255,129 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+ };
+ doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
+ mGlobalActionsDialog.createActionItems();
+
+ assertEquals(3, mGlobalActionsDialog.mItems.size());
+ assertEquals(0, mGlobalActionsDialog.mOverflowItems.size());
+ assertEquals(0, mGlobalActionsDialog.mPowerItems.size());
+ }
+
+ @Test
+ public void testCreateActionItems_maxThree_condensePower() {
+ mGlobalActionsDialog = spy(mGlobalActionsDialog);
+ // allow 3 items to be shown
+ doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems();
+ // ensure items are not blocked by keyguard or device provisioning
+ doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any());
+ // make sure lockdown action will be shown
+ doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
+ String[] actions = {
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
+ };
+ doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
+ mGlobalActionsDialog.createActionItems();
+
+ assertEquals(3, mGlobalActionsDialog.mItems.size());
+ assertEquals(0, mGlobalActionsDialog.mOverflowItems.size());
+ assertEquals(2, mGlobalActionsDialog.mPowerItems.size());
+
+ // PowerOptionsAction should appear immediately after the Emergency action
+
+ GlobalActionsDialog.Action firstItem = mGlobalActionsDialog.mItems.get(0);
+ GlobalActionsDialog.Action secondItem = mGlobalActionsDialog.mItems.get(1);
+
+ assertTrue(firstItem instanceof GlobalActionsDialog.EmergencyAction);
+ assertTrue(secondItem instanceof GlobalActionsDialog.PowerOptionsAction);
+ }
+
+ @Test
+ public void testCreateActionItems_maxThree_condensePower_noEmergency() {
+ mGlobalActionsDialog = spy(mGlobalActionsDialog);
+ // allow 3 items to be shown
+ doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems();
+ // make sure lockdown action will be shown
+ doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
+ // ensure items are not blocked by keyguard or device provisioning
+ doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any());
+ String[] actions = {
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_SCREENSHOT,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
+ };
+ doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
+ mGlobalActionsDialog.createActionItems();
+
+ assertEquals(3, mGlobalActionsDialog.mItems.size());
+ assertEquals(0, mGlobalActionsDialog.mOverflowItems.size());
+ assertEquals(2, mGlobalActionsDialog.mPowerItems.size());
+
+ // When Emergency isn't used, PowerOptionsAction should be first
+
+ GlobalActionsDialog.Action firstItem = mGlobalActionsDialog.mItems.get(0);
+ GlobalActionsDialog.Action secondItem = mGlobalActionsDialog.mItems.get(1);
+
+ assertTrue(firstItem instanceof GlobalActionsDialog.PowerOptionsAction);
+ assertTrue(secondItem instanceof GlobalActionsDialog.ScreenshotAction);
+ }
+
+ @Test
+ public void testCreateActionItems_maxFour_condensePower() {
+ mGlobalActionsDialog = spy(mGlobalActionsDialog);
+ // allow 3 items to be shown
+ doReturn(4).when(mGlobalActionsDialog).getMaxShownPowerItems();
+ // make sure lockdown action will be shown
+ doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
+ // ensure items are not blocked by keyguard or device provisioning
+ doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any());
+ String[] actions = {
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_SCREENSHOT
+ };
+ doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
+ mGlobalActionsDialog.createActionItems();
+
+ assertEquals(4, mGlobalActionsDialog.mItems.size());
+ assertEquals(0, mGlobalActionsDialog.mOverflowItems.size());
+ assertEquals(2, mGlobalActionsDialog.mPowerItems.size());
+
+ // with four items, make sure power still shows up immediately after Emergency
+ GlobalActionsDialog.Action firstItem = mGlobalActionsDialog.mItems.get(0);
+ GlobalActionsDialog.Action secondItem = mGlobalActionsDialog.mItems.get(1);
+
+ assertTrue(firstItem instanceof GlobalActionsDialog.EmergencyAction);
+ assertTrue(secondItem instanceof GlobalActionsDialog.PowerOptionsAction);
+ }
+
+ @Test
+ public void testCreateActionItems_maxThree_doNotCondensePower() {
+ mGlobalActionsDialog = spy(mGlobalActionsDialog);
+ // allow 3 items to be shown
+ doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems();
+ // make sure lockdown action will be shown
+ doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
+ // ensure items are not blocked by keyguard or device provisioning
+ doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any());
+ String[] actions = {
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
GlobalActionsDialog.GLOBAL_ACTION_KEY_SCREENSHOT,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
};
doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
mGlobalActionsDialog.createActionItems();
assertEquals(3, mGlobalActionsDialog.mItems.size());
assertEquals(1, mGlobalActionsDialog.mOverflowItems.size());
+ assertEquals(0, mGlobalActionsDialog.mPowerItems.size());
}
@Test
@@ -270,11 +387,13 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
doReturn(Integer.MAX_VALUE).when(mGlobalActionsDialog).getMaxShownPowerItems();
// ensure items are not blocked by keyguard or device provisioning
doReturn(true).when(mGlobalActionsDialog).shouldShowAction(any());
+ // make sure lockdown action will be shown
+ doReturn(true).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
String[] actions = {
GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
- GlobalActionsDialog.GLOBAL_ACTION_KEY_SCREENSHOT,
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
};
doReturn(actions).when(mGlobalActionsDialog).getDefaultActions();
mGlobalActionsDialog.createActionItems();
@@ -288,10 +407,12 @@ public class GlobalActionsDialogTest extends SysuiTestCase {
mGlobalActionsDialog = spy(mGlobalActionsDialog);
// allow only 3 items to be shown
doReturn(3).when(mGlobalActionsDialog).getMaxShownPowerItems();
+ // make sure lockdown action will NOT be shown
+ doReturn(false).when(mGlobalActionsDialog).shouldDisplayLockdown(any());
String[] actions = {
GlobalActionsDialog.GLOBAL_ACTION_KEY_EMERGENCY,
- // screenshot blocked because device not provisioned
- GlobalActionsDialog.GLOBAL_ACTION_KEY_SCREENSHOT,
+ // lockdown action not allowed
+ GlobalActionsDialog.GLOBAL_ACTION_KEY_LOCKDOWN,
GlobalActionsDialog.GLOBAL_ACTION_KEY_POWER,
GlobalActionsDialog.GLOBAL_ACTION_KEY_RESTART,
};
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index 9d2b6f4deb14..737ced63eed0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -31,6 +31,7 @@ import android.widget.ImageButton
import android.widget.ImageView
import android.widget.SeekBar
import android.widget.TextView
+import androidx.lifecycle.LiveData
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
@@ -41,6 +42,7 @@ import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
@@ -48,6 +50,7 @@ import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
private const val KEY = "TEST_KEY"
private const val APP = "APP"
@@ -67,13 +70,14 @@ public class MediaControlPanelTest : SysuiTestCase() {
private lateinit var player: MediaControlPanel
- private lateinit var fgExecutor: FakeExecutor
private lateinit var bgExecutor: FakeExecutor
@Mock private lateinit var activityStarter: ActivityStarter
@Mock private lateinit var holder: PlayerViewHolder
@Mock private lateinit var view: TransitionLayout
@Mock private lateinit var mediaHostStatesManager: MediaHostStatesManager
+ @Mock private lateinit var seekBarViewModel: SeekBarViewModel
+ @Mock private lateinit var seekBarData: LiveData<SeekBarViewModel.Progress>
private lateinit var appIcon: ImageView
private lateinit var appName: TextView
private lateinit var albumView: ImageView
@@ -95,20 +99,17 @@ public class MediaControlPanelTest : SysuiTestCase() {
private val device = MediaDeviceData(true, null, DEVICE_NAME)
private val disabledDevice = MediaDeviceData(false, null, null)
+ @JvmField @Rule val mockito = MockitoJUnit.rule()
+
@Before
fun setUp() {
- fgExecutor = FakeExecutor(FakeSystemClock())
bgExecutor = FakeExecutor(FakeSystemClock())
- activityStarter = mock(ActivityStarter::class.java)
- mediaHostStatesManager = mock(MediaHostStatesManager::class.java)
-
- player = MediaControlPanel(context, fgExecutor, bgExecutor, activityStarter,
- mediaHostStatesManager)
+ player = MediaControlPanel(context, bgExecutor, activityStarter, mediaHostStatesManager,
+ seekBarViewModel)
+ whenever(seekBarViewModel.progress).thenReturn(seekBarData)
// Mock out a view holder for the player to attach to.
- holder = mock(PlayerViewHolder::class.java)
- view = mock(TransitionLayout::class.java)
whenever(holder.player).thenReturn(view)
appIcon = ImageView(context)
whenever(holder.appIcon).thenReturn(appIcon)
@@ -171,7 +172,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun bindWhenUnattached() {
val state = MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
- emptyList(), PACKAGE, null, null, device)
+ emptyList(), PACKAGE, null, null, device, null)
player.bind(state)
assertThat(player.isPlaying()).isFalse()
}
@@ -180,7 +181,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
fun bindText() {
player.attach(holder)
val state = MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
- emptyList(), PACKAGE, session.getSessionToken(), null, device)
+ emptyList(), PACKAGE, session.getSessionToken(), null, device, null)
player.bind(state)
assertThat(appName.getText()).isEqualTo(APP)
assertThat(titleText.getText()).isEqualTo(TITLE)
@@ -191,7 +192,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
fun bindBackgroundColor() {
player.attach(holder)
val state = MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
- emptyList(), PACKAGE, session.getSessionToken(), null, device)
+ emptyList(), PACKAGE, session.getSessionToken(), null, device, null)
player.bind(state)
val list = ArgumentCaptor.forClass(ColorStateList::class.java)
verify(view).setBackgroundTintList(list.capture())
@@ -202,7 +203,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
fun bindDevice() {
player.attach(holder)
val state = MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
- emptyList(), PACKAGE, session.getSessionToken(), null, device)
+ emptyList(), PACKAGE, session.getSessionToken(), null, device, null)
player.bind(state)
assertThat(seamlessText.getText()).isEqualTo(DEVICE_NAME)
assertThat(seamless.isEnabled()).isTrue()
@@ -212,7 +213,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
fun bindDisabledDevice() {
player.attach(holder)
val state = MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
- emptyList(), PACKAGE, session.getSessionToken(), null, disabledDevice)
+ emptyList(), PACKAGE, session.getSessionToken(), null, disabledDevice, null)
player.bind(state)
assertThat(seamless.isEnabled()).isFalse()
assertThat(seamlessText.getText()).isEqualTo(context.getResources().getString(
@@ -223,7 +224,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
fun bindNullDevice() {
player.attach(holder)
val state = MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
- emptyList(), PACKAGE, session.getSessionToken(), null, null)
+ emptyList(), PACKAGE, session.getSessionToken(), null, null, null)
player.bind(state)
assertThat(seamless.isEnabled()).isTrue()
assertThat(seamlessText.getText()).isEqualTo(context.getResources().getString(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
index 48e3b0a9d993..bed5c9eb6df5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataCombineLatestTest.java
@@ -79,16 +79,16 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
mManager.addListener(mListener);
mMediaData = new MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null,
- new ArrayList<>(), new ArrayList<>(), PACKAGE, null, null, null, KEY);
+ new ArrayList<>(), new ArrayList<>(), PACKAGE, null, null, null, null, KEY, false);
mDeviceData = new MediaDeviceData(true, null, DEVICE_NAME);
}
@Test
public void eventNotEmittedWithoutDevice() {
// WHEN data source emits an event without device data
- mDataListener.onMediaDataLoaded(KEY, mMediaData);
+ mDataListener.onMediaDataLoaded(KEY, null, mMediaData);
// THEN an event isn't emitted
- verify(mListener, never()).onMediaDataLoaded(eq(KEY), any());
+ verify(mListener, never()).onMediaDataLoaded(eq(KEY), any(), any());
}
@Test
@@ -96,7 +96,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
// WHEN device source emits an event without media data
mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData);
// THEN an event isn't emitted
- verify(mListener, never()).onMediaDataLoaded(eq(KEY), any());
+ verify(mListener, never()).onMediaDataLoaded(eq(KEY), any(), any());
}
@Test
@@ -104,22 +104,22 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
// GIVEN that a device event has already been received
mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData);
// WHEN media event is received
- mDataListener.onMediaDataLoaded(KEY, mMediaData);
+ mDataListener.onMediaDataLoaded(KEY, null, mMediaData);
// THEN the listener receives a combined event
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
- verify(mListener).onMediaDataLoaded(eq(KEY), captor.capture());
+ verify(mListener).onMediaDataLoaded(eq(KEY), any(), captor.capture());
assertThat(captor.getValue().getDevice()).isNotNull();
}
@Test
public void emitEventAfterMediaFirst() {
// GIVEN that media event has already been received
- mDataListener.onMediaDataLoaded(KEY, mMediaData);
+ mDataListener.onMediaDataLoaded(KEY, null, mMediaData);
// WHEN device event is received
mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData);
// THEN the listener receives a combined event
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
- verify(mListener).onMediaDataLoaded(eq(KEY), captor.capture());
+ verify(mListener).onMediaDataLoaded(eq(KEY), any(), captor.capture());
assertThat(captor.getValue().getDevice()).isNotNull();
}
@@ -133,7 +133,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
@Test
public void mediaDataRemovedAfterMediaEvent() {
- mDataListener.onMediaDataLoaded(KEY, mMediaData);
+ mDataListener.onMediaDataLoaded(KEY, null, mMediaData);
mDataListener.onMediaDataRemoved(KEY);
verify(mListener).onMediaDataRemoved(eq(KEY));
}
@@ -145,6 +145,18 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
verify(mListener).onMediaDataRemoved(eq(KEY));
}
+ @Test
+ public void mediaDataKeyUpdated() {
+ // GIVEN that device and media events have already been received
+ mDataListener.onMediaDataLoaded(KEY, null, mMediaData);
+ mDeviceListener.onMediaDeviceChanged(KEY, mDeviceData);
+ // WHEN the key is changed
+ mDataListener.onMediaDataLoaded("NEW_KEY", KEY, mMediaData);
+ // THEN the listener gets a load event with the correct keys
+ ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
+ verify(mListener).onMediaDataLoaded(eq("NEW_KEY"), any(), captor.capture());
+ }
+
private MediaDataManager.Listener captureDataListener() {
ArgumentCaptor<MediaDataManager.Listener> captor = ArgumentCaptor.forClass(
MediaDataManager.Listener.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
index c0aef8adc4af..3a3140f2ff53 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
@@ -23,8 +23,6 @@ import android.media.MediaRouter2Manager
import android.media.RoutingSessionInfo
import android.media.session.MediaSession
import android.media.session.PlaybackState
-import android.os.Process
-import android.service.notification.StatusBarNotification
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
@@ -67,6 +65,7 @@ private fun <T> eq(value: T): T = Mockito.eq(value) ?: value
public class MediaDeviceManagerTest : SysuiTestCase() {
private lateinit var manager: MediaDeviceManager
+ @Mock private lateinit var mediaDataManager: MediaDataManager
@Mock private lateinit var lmmFactory: LocalMediaManagerFactory
@Mock private lateinit var lmm: LocalMediaManager
@Mock private lateinit var mr2: MediaRouter2Manager
@@ -80,13 +79,14 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
private lateinit var metadataBuilder: MediaMetadata.Builder
private lateinit var playbackBuilder: PlaybackState.Builder
private lateinit var notifBuilder: Notification.Builder
- private lateinit var sbn: StatusBarNotification
+ private lateinit var mediaData: MediaData
@JvmField @Rule val mockito = MockitoJUnit.rule()
@Before
fun setUp() {
fakeExecutor = FakeExecutor(FakeSystemClock())
- manager = MediaDeviceManager(context, lmmFactory, mr2, featureFlag, fakeExecutor)
+ manager = MediaDeviceManager(context, lmmFactory, mr2, featureFlag, fakeExecutor,
+ mediaDataManager)
manager.addListener(listener)
// Configure mocks.
@@ -117,8 +117,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
setSmallIcon(android.R.drawable.ic_media_pause)
setStyle(Notification.MediaStyle().setMediaSession(session.getSessionToken()))
}
- sbn = StatusBarNotification(PACKAGE, PACKAGE, 0, "TAG", Process.myUid(), 0, 0,
- notifBuilder.build(), Process.myUserHandle(), 0)
+ mediaData = MediaData(true, 0, PACKAGE, null, null, SESSION_TITLE, null,
+ emptyList(), emptyList(), PACKAGE, session.sessionToken, null, null, null)
}
@After
@@ -128,33 +128,33 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
@Test
fun removeUnknown() {
- manager.onNotificationRemoved("unknown")
+ manager.onMediaDataRemoved("unknown")
}
@Test
fun addNotification() {
- manager.onNotificationAdded(KEY, sbn)
+ manager.onMediaDataLoaded(KEY, null, mediaData)
verify(lmmFactory).create(PACKAGE)
}
@Test
fun featureDisabled() {
whenever(featureFlag.enabled).thenReturn(false)
- manager.onNotificationAdded(KEY, sbn)
+ manager.onMediaDataLoaded(KEY, null, mediaData)
verify(lmmFactory, never()).create(PACKAGE)
}
@Test
fun addAndRemoveNotification() {
- manager.onNotificationAdded(KEY, sbn)
- manager.onNotificationRemoved(KEY)
+ manager.onMediaDataLoaded(KEY, null, mediaData)
+ manager.onMediaDataRemoved(KEY)
verify(lmm).unregisterCallback(any())
}
@Test
fun deviceEventOnAddNotification() {
// WHEN a notification is added
- manager.onNotificationAdded(KEY, sbn)
+ manager.onMediaDataLoaded(KEY, null, mediaData)
val deviceCallback = captureCallback()
// THEN the update is dispatched to the listener
val data = captureDeviceData(KEY)
@@ -165,7 +165,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
@Test
fun deviceListUpdate() {
- manager.onNotificationAdded(KEY, sbn)
+ manager.onMediaDataLoaded(KEY, null, mediaData)
val deviceCallback = captureCallback()
// WHEN the device list changes
deviceCallback.onDeviceListUpdate(mutableListOf(device))
@@ -179,7 +179,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
@Test
fun selectedDeviceStateChanged() {
- manager.onNotificationAdded(KEY, sbn)
+ manager.onMediaDataLoaded(KEY, null, mediaData)
val deviceCallback = captureCallback()
// WHEN the selected device changes state
deviceCallback.onSelectedDeviceStateChanged(device, 1)
@@ -193,9 +193,9 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
@Test
fun listenerReceivesKeyRemoved() {
- manager.onNotificationAdded(KEY, sbn)
+ manager.onMediaDataLoaded(KEY, null, mediaData)
// WHEN the notification is removed
- manager.onNotificationRemoved(KEY)
+ manager.onMediaDataRemoved(KEY)
// THEN the listener receives key removed event
verify(listener).onKeyRemoved(eq(KEY))
}
@@ -205,7 +205,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
// GIVEN that MR2Manager returns null for routing session
whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null)
// WHEN a notification is added
- manager.onNotificationAdded(KEY, sbn)
+ manager.onMediaDataLoaded(KEY, null, mediaData)
// THEN the device is disabled
val data = captureDeviceData(KEY)
assertThat(data.enabled).isFalse()
@@ -216,7 +216,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
@Test
fun deviceDisabledWhenMR2ReturnsNullRouteInfoOnDeviceChanged() {
// GIVEN a notif is added
- manager.onNotificationAdded(KEY, sbn)
+ manager.onMediaDataLoaded(KEY, null, mediaData)
reset(listener)
// AND MR2Manager returns null for routing session
whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null)
@@ -234,7 +234,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
@Test
fun deviceDisabledWhenMR2ReturnsNullRouteInfoOnDeviceListUpdate() {
// GIVEN a notif is added
- manager.onNotificationAdded(KEY, sbn)
+ manager.onMediaDataLoaded(KEY, null, mediaData)
reset(listener)
// GIVEN that MR2Manager returns null for routing session
whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(null)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
index c21343cb5423..7d44327b0d38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
@@ -16,7 +16,9 @@
package com.android.systemui.media
+import android.media.MediaMetadata
import android.media.session.MediaController
+import android.media.session.MediaSession
import android.media.session.PlaybackState
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
@@ -41,6 +43,10 @@ import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
private const val KEY = "KEY"
+private const val PACKAGE = "PKG"
+private const val SESSION_KEY = "SESSION_KEY"
+private const val SESSION_ARTIST = "SESSION_ARTIST"
+private const val SESSION_TITLE = "SESSION_TITLE"
private fun <T> eq(value: T): T = Mockito.eq(value) ?: value
private fun <T> anyObject(): T {
@@ -54,12 +60,15 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
@Mock private lateinit var mediaControllerFactory: MediaControllerFactory
@Mock private lateinit var mediaController: MediaController
@Mock private lateinit var executor: DelayableExecutor
- @Mock private lateinit var mediaData: MediaData
@Mock private lateinit var timeoutCallback: (String, Boolean) -> Unit
@Mock private lateinit var cancellationRunnable: Runnable
@Captor private lateinit var timeoutCaptor: ArgumentCaptor<Runnable>
@Captor private lateinit var mediaCallbackCaptor: ArgumentCaptor<MediaController.Callback>
@JvmField @Rule val mockito = MockitoJUnit.rule()
+ private lateinit var metadataBuilder: MediaMetadata.Builder
+ private lateinit var playbackBuilder: PlaybackState.Builder
+ private lateinit var session: MediaSession
+ private lateinit var mediaData: MediaData
private lateinit var mediaTimeoutListener: MediaTimeoutListener
@Before
@@ -68,22 +77,39 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
`when`(executor.executeDelayed(any(), anyLong())).thenReturn(cancellationRunnable)
mediaTimeoutListener = MediaTimeoutListener(mediaControllerFactory, executor)
mediaTimeoutListener.timeoutCallback = timeoutCallback
+
+ // Create a media session and notification for testing.
+ metadataBuilder = MediaMetadata.Builder().apply {
+ putString(MediaMetadata.METADATA_KEY_ARTIST, SESSION_ARTIST)
+ putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_TITLE)
+ }
+ playbackBuilder = PlaybackState.Builder().apply {
+ setState(PlaybackState.STATE_PAUSED, 6000L, 1f)
+ setActions(PlaybackState.ACTION_PLAY)
+ }
+ session = MediaSession(context, SESSION_KEY).apply {
+ setMetadata(metadataBuilder.build())
+ setPlaybackState(playbackBuilder.build())
+ }
+ session.setActive(true)
+ mediaData = MediaData(true, 0, PACKAGE, null, null, SESSION_TITLE, null,
+ emptyList(), emptyList(), PACKAGE, session.sessionToken, null, null, null)
}
@Test
fun testOnMediaDataLoaded_registersPlaybackListener() {
- mediaTimeoutListener.onMediaDataLoaded(KEY, mediaData)
+ mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData)
verify(mediaController).registerCallback(capture(mediaCallbackCaptor))
// Ignores is same key
clearInvocations(mediaController)
- mediaTimeoutListener.onMediaDataLoaded(KEY, mediaData)
+ mediaTimeoutListener.onMediaDataLoaded(KEY, KEY, mediaData)
verify(mediaController, never()).registerCallback(anyObject())
}
@Test
fun testOnMediaDataRemoved_unregistersPlaybackListener() {
- mediaTimeoutListener.onMediaDataLoaded(KEY, mediaData)
+ mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData)
mediaTimeoutListener.onMediaDataRemoved(KEY)
verify(mediaController).unregisterCallback(anyObject())
@@ -105,7 +131,7 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
@Test
fun testOnPlaybackStateChanged_cancelsTimeout_whenResumed() {
- // Assuming we're have a pending timeout
+ // Assuming we have a pending timeout
testOnPlaybackStateChanged_schedulesTimeout_whenPaused()
mediaCallbackCaptor.value.onPlaybackStateChanged(PlaybackState.Builder()
@@ -114,6 +140,17 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
}
@Test
+ fun testOnPlaybackStateChanged_reusesTimeout_whenNotPlaying() {
+ // Assuming we have a pending timeout
+ testOnPlaybackStateChanged_schedulesTimeout_whenPaused()
+
+ clearInvocations(cancellationRunnable)
+ mediaCallbackCaptor.value.onPlaybackStateChanged(PlaybackState.Builder()
+ .setState(PlaybackState.STATE_STOPPED, 0L, 0f).build())
+ verify(cancellationRunnable, never()).run()
+ }
+
+ @Test
fun testTimeoutCallback_invokedIfTimeout() {
// Assuming we're have a pending timeout
testOnPlaybackStateChanged_schedulesTimeout_whenPaused()
@@ -124,7 +161,7 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
@Test
fun testIsTimedOut() {
- mediaTimeoutListener.onMediaDataLoaded(KEY, mediaData)
+ mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData)
assertThat(mediaTimeoutListener.isTimedOut(KEY)).isFalse()
}
} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
index 19e15b3c4307..24e9bd837d5d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
@@ -29,6 +29,7 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.concurrency.FakeRepeatableExecutor
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -71,7 +72,7 @@ public class SeekBarViewModelTest : SysuiTestCase() {
@Before
fun setUp() {
fakeExecutor = FakeExecutor(FakeSystemClock())
- viewModel = SeekBarViewModel(fakeExecutor)
+ viewModel = SeekBarViewModel(FakeRepeatableExecutor(fakeExecutor))
mockController = mock(MediaController::class.java)
whenever(mockController.sessionToken).thenReturn(token1)
mockTransport = mock(MediaController.TransportControls::class.java)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
index b7a2633d0d36..536cae4380c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
@@ -82,7 +82,7 @@ public class PipAnimationControllerTest extends SysuiTestCase {
@Test
public void getAnimator_withBounds_returnBoundsAnimator() {
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
- .getAnimator(mLeash, new Rect(), new Rect());
+ .getAnimator(mLeash, new Rect(), new Rect(), null);
assertEquals("Expect ANIM_TYPE_BOUNDS animation",
animator.getAnimationType(), PipAnimationController.ANIM_TYPE_BOUNDS);
@@ -94,12 +94,12 @@ public class PipAnimationControllerTest extends SysuiTestCase {
final Rect endValue1 = new Rect(100, 100, 200, 200);
final Rect endValue2 = new Rect(200, 200, 300, 300);
final PipAnimationController.PipTransitionAnimator oldAnimator = mPipAnimationController
- .getAnimator(mLeash, startValue, endValue1);
+ .getAnimator(mLeash, startValue, endValue1, null);
oldAnimator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new);
oldAnimator.start();
final PipAnimationController.PipTransitionAnimator newAnimator = mPipAnimationController
- .getAnimator(mLeash, startValue, endValue2);
+ .getAnimator(mLeash, startValue, endValue2, null);
assertEquals("getAnimator with same type returns same animator",
oldAnimator, newAnimator);
@@ -129,7 +129,7 @@ public class PipAnimationControllerTest extends SysuiTestCase {
final Rect endValue1 = new Rect(100, 100, 200, 200);
final Rect endValue2 = new Rect(200, 200, 300, 300);
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
- .getAnimator(mLeash, startValue, endValue1);
+ .getAnimator(mLeash, startValue, endValue1, null);
animator.updateEndValue(endValue2);
@@ -141,7 +141,7 @@ public class PipAnimationControllerTest extends SysuiTestCase {
final Rect startValue = new Rect(0, 0, 100, 100);
final Rect endValue = new Rect(100, 100, 200, 200);
final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController
- .getAnimator(mLeash, startValue, endValue);
+ .getAnimator(mLeash, startValue, endValue, null);
animator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new);
animator.setPipAnimationCallback(mPipAnimationCallback);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index 11477395a781..5d4ef550b36c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -219,13 +219,43 @@ public class QSTileHostTest extends SysuiTestCase {
public void testNoRepeatedSpecs_customTile() {
mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, CUSTOM_TILE_SPEC);
- mQSTileHost.addTile(CUSTOM_TILE);
+ mQSTileHost.addTile(CUSTOM_TILE, /* end */ false);
assertEquals(1, mQSTileHost.mTileSpecs.size());
assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(0));
}
@Test
+ public void testAddedAtBeginningOnDefault_customTile() {
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1"); // seed
+
+ mQSTileHost.addTile(CUSTOM_TILE);
+
+ assertEquals(2, mQSTileHost.mTileSpecs.size());
+ assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(0));
+ }
+
+ @Test
+ public void testAddedAtBeginning_customTile() {
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1"); // seed
+
+ mQSTileHost.addTile(CUSTOM_TILE, /* end */ false);
+
+ assertEquals(2, mQSTileHost.mTileSpecs.size());
+ assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(0));
+ }
+
+ @Test
+ public void testAddedAtEnd_customTile() {
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "spec1"); // seed
+
+ mQSTileHost.addTile(CUSTOM_TILE, /* end */ true);
+
+ assertEquals(2, mQSTileHost.mTileSpecs.size());
+ assertEquals(CUSTOM_TILE_SPEC, mQSTileHost.mTileSpecs.get(1));
+ }
+
+ @Test
public void testLoadTileSpec_repeated() {
List<String> specs = QSTileHost.loadTileSpecs(mContext, "spec1,spec1,spec2");
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 2fc3d72c2672..53ed4cf12b2f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -18,13 +18,22 @@ package com.android.systemui.qs.external;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
+import android.content.IntentFilter;
import android.os.Handler;
import android.os.Looper;
+import android.os.UserHandle;
import android.service.quicksettings.Tile;
+import android.service.quicksettings.TileService;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -50,7 +59,6 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
@@ -99,7 +107,7 @@ public class TileServicesTest extends SysuiTestCase {
mTunerService,
() -> mAutoTileManager,
mDumpManager,
- mBroadcastDispatcher,
+ mock(BroadcastDispatcher.class),
Optional.of(mStatusBar),
mQSLogger,
mUiEventLogger);
@@ -113,6 +121,14 @@ public class TileServicesTest extends SysuiTestCase {
}
@Test
+ public void testActiveTileListenerRegisteredOnAllUsers() {
+ ArgumentCaptor<IntentFilter> captor = ArgumentCaptor.forClass(IntentFilter.class);
+ verify(mBroadcastDispatcher).registerReceiver(any(), captor.capture(), any(), eq(
+ UserHandle.ALL));
+ assertTrue(captor.getValue().hasAction(TileService.ACTION_REQUEST_LISTENING));
+ }
+
+ @Test
public void testRecalculateBindAllowance() {
// Add some fake tiles.
for (int i = 0; i < NUM_FAKES; i++) {
@@ -125,10 +141,9 @@ public class TileServicesTest extends SysuiTestCase {
}
mTileService.recalculateBindAllowance();
for (int i = 0; i < NUM_FAKES; i++) {
- Mockito.verify(mManagers.get(i), Mockito.times(1)).calculateBindPriority(
- Mockito.anyLong());
+ verify(mManagers.get(i), times(1)).calculateBindPriority(anyLong());
ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
- Mockito.verify(mManagers.get(i), Mockito.times(1)).setBindAllowed(captor.capture());
+ verify(mManagers.get(i), times(1)).setBindAllowed(captor.capture());
assertEquals("" + i + "th service", i >= (NUM_FAKES - TileServices.DEFAULT_MAX_BOUND),
(boolean) captor.getValue());
@@ -142,7 +157,7 @@ public class TileServicesTest extends SysuiTestCase {
for (int i = 0; i < NUM_FAKES; i++) {
ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
- Mockito.verify(mManagers.get(i), Mockito.times(2)).setBindAllowed(captor.capture());
+ verify(mManagers.get(i), times(2)).setBindAllowed(captor.capture());
assertEquals("" + i + "th service", i >= (NUM_FAKES - TileServices.REDUCED_MAX_BOUND),
(boolean) captor.getValue());
@@ -158,12 +173,12 @@ public class TileServicesTest extends SysuiTestCase {
for (int i = 0; i < TileServices.DEFAULT_MAX_BOUND - 1; i++) {
// Shouldn't get bind prioirities calculated when there are less than the max services.
- Mockito.verify(mManagers.get(i), Mockito.never()).calculateBindPriority(
- Mockito.anyLong());
+ verify(mManagers.get(i), never()).calculateBindPriority(
+ anyLong());
// All should be bound since there are less than the max services.
ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
- Mockito.verify(mManagers.get(i), Mockito.times(1)).setBindAllowed(captor.capture());
+ verify(mManagers.get(i), times(1)).setBindAllowed(captor.capture());
assertTrue(captor.getValue());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
index 595ba89ca3b6..5a81d36ea744 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
@@ -27,8 +27,10 @@ import static org.mockito.Mockito.when;
import android.Manifest;
import android.app.Notification;
+import android.app.Notification.MediaStyle;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
+import android.media.session.MediaSession;
import android.os.Bundle;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
@@ -40,6 +42,7 @@ import androidx.test.filters.SmallTest;
import com.android.systemui.ForegroundServiceController;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.media.MediaFeatureFlag;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
@@ -51,6 +54,7 @@ import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ShadeController;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -73,10 +77,16 @@ public class NotificationFilterTest extends SysuiTestCase {
ForegroundServiceController mFsc;
@Mock
KeyguardEnvironment mEnvironment;
+ @Mock
+ MediaFeatureFlag mMediaFeatureFlag;
+ @Mock
+ StatusBarStateController mStatusBarStateController;
private final IPackageManager mMockPackageManager = mock(IPackageManager.class);
private NotificationFilter mNotificationFilter;
private ExpandableNotificationRow mRow;
+ private NotificationEntry mMediaEntry;
+ private MediaSession mMediaSession;
@Before
public void setUp() throws Exception {
@@ -84,6 +94,12 @@ public class NotificationFilterTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
when(mMockStatusBarNotification.getUid()).thenReturn(UID_NORMAL);
+ mMediaSession = new MediaSession(mContext, "TEST_MEDIA_SESSION");
+ NotificationEntryBuilder builder = new NotificationEntryBuilder();
+ builder.modifyNotification(mContext).setStyle(
+ new MediaStyle().setMediaSession(mMediaSession.getSessionToken()));
+ mMediaEntry = builder.build();
+
when(mMockPackageManager.checkUidPermission(
eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
eq(UID_NORMAL)))
@@ -107,7 +123,12 @@ public class NotificationFilterTest extends SysuiTestCase {
mDependency,
TestableLooper.get(this));
mRow = testHelper.createRow();
- mNotificationFilter = new NotificationFilter(mock(StatusBarStateController.class));
+ mNotificationFilter = new NotificationFilter(mStatusBarStateController, mMediaFeatureFlag);
+ }
+
+ @After
+ public void tearDown() {
+ mMediaSession.release();
}
@Test
@@ -218,6 +239,56 @@ public class NotificationFilterTest extends SysuiTestCase {
assertFalse(mNotificationFilter.shouldFilterOut(entry));
}
+ @Test
+ public void shouldFilterOtherNotificationWhenDisabled() {
+ // GIVEN that the media feature is disabled
+ when(mMediaFeatureFlag.getEnabled()).thenReturn(false);
+ NotificationFilter filter = new NotificationFilter(mStatusBarStateController,
+ mMediaFeatureFlag);
+ // WHEN the media filter is asked about an entry
+ NotificationEntry otherEntry = new NotificationEntryBuilder().build();
+ final boolean shouldFilter = filter.shouldFilterOut(otherEntry);
+ // THEN it shouldn't be filtered
+ assertFalse(shouldFilter);
+ }
+
+ @Test
+ public void shouldFilterOtherNotificationWhenEnabled() {
+ // GIVEN that the media feature is enabled
+ when(mMediaFeatureFlag.getEnabled()).thenReturn(true);
+ NotificationFilter filter = new NotificationFilter(mStatusBarStateController,
+ mMediaFeatureFlag);
+ // WHEN the media filter is asked about an entry
+ NotificationEntry otherEntry = new NotificationEntryBuilder().build();
+ final boolean shouldFilter = filter.shouldFilterOut(otherEntry);
+ // THEN it shouldn't be filtered
+ assertFalse(shouldFilter);
+ }
+
+ @Test
+ public void shouldFilterMediaNotificationWhenDisabled() {
+ // GIVEN that the media feature is disabled
+ when(mMediaFeatureFlag.getEnabled()).thenReturn(false);
+ NotificationFilter filter = new NotificationFilter(mStatusBarStateController,
+ mMediaFeatureFlag);
+ // WHEN the media filter is asked about a media entry
+ final boolean shouldFilter = filter.shouldFilterOut(mMediaEntry);
+ // THEN it shouldn't be filtered
+ assertFalse(shouldFilter);
+ }
+
+ @Test
+ public void shouldFilterMediaNotificationWhenEnabled() {
+ // GIVEN that the media feature is enabled
+ when(mMediaFeatureFlag.getEnabled()).thenReturn(true);
+ NotificationFilter filter = new NotificationFilter(mStatusBarStateController,
+ mMediaFeatureFlag);
+ // WHEN the media filter is asked about a media entry
+ final boolean shouldFilter = filter.shouldFilterOut(mMediaEntry);
+ // THEN it should be filtered
+ assertTrue(shouldFilter);
+ }
+
private void initStatusBarNotification(boolean allowDuringSetup) {
Bundle bundle = new Bundle();
bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
new file mode 100644
index 000000000000..c5dc2b4d4f03
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/MediaCoordinatorTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.coordinator;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification.MediaStyle;
+import android.media.session.MediaSession;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.media.MediaFeatureFlag;
+import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+
+import 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;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public final class MediaCoordinatorTest extends SysuiTestCase {
+
+ private MediaSession mMediaSession;
+ private NotificationEntry mOtherEntry;
+ private NotificationEntry mMediaEntry;
+
+ @Mock private NotifPipeline mNotifPipeline;
+ @Mock private MediaFeatureFlag mMediaFeatureFlag;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mOtherEntry = new NotificationEntryBuilder().build();
+ mMediaSession = new MediaSession(mContext, "TEST_MEDIA_SESSION");
+ NotificationEntryBuilder builder = new NotificationEntryBuilder();
+ builder.modifyNotification(mContext).setStyle(
+ new MediaStyle().setMediaSession(mMediaSession.getSessionToken()));
+ mMediaEntry = builder.build();
+ }
+
+ @After
+ public void tearDown() {
+ mMediaSession.release();
+ }
+
+ @Test
+ public void shouldFilterOtherNotificationWhenDisabled() {
+ // GIVEN that the media feature is disabled
+ when(mMediaFeatureFlag.getEnabled()).thenReturn(false);
+ MediaCoordinator coordinator = new MediaCoordinator(mMediaFeatureFlag);
+ // WHEN the media filter is asked about an entry
+ NotifFilter filter = captureFilter(coordinator);
+ final boolean shouldFilter = filter.shouldFilterOut(mOtherEntry, 0);
+ // THEN it shouldn't be filtered
+ assertThat(shouldFilter).isFalse();
+ }
+
+ @Test
+ public void shouldFilterOtherNotificationWhenEnabled() {
+ // GIVEN that the media feature is enabled
+ when(mMediaFeatureFlag.getEnabled()).thenReturn(true);
+ MediaCoordinator coordinator = new MediaCoordinator(mMediaFeatureFlag);
+ // WHEN the media filter is asked about an entry
+ NotifFilter filter = captureFilter(coordinator);
+ final boolean shouldFilter = filter.shouldFilterOut(mOtherEntry, 0);
+ // THEN it shouldn't be filtered
+ assertThat(shouldFilter).isFalse();
+ }
+
+ @Test
+ public void shouldFilterMediaNotificationWhenDisabled() {
+ // GIVEN that the media feature is disabled
+ when(mMediaFeatureFlag.getEnabled()).thenReturn(false);
+ MediaCoordinator coordinator = new MediaCoordinator(mMediaFeatureFlag);
+ // WHEN the media filter is asked about a media entry
+ NotifFilter filter = captureFilter(coordinator);
+ final boolean shouldFilter = filter.shouldFilterOut(mMediaEntry, 0);
+ // THEN it shouldn't be filtered
+ assertThat(shouldFilter).isFalse();
+ }
+
+ @Test
+ public void shouldFilterMediaNotificationWhenEnabled() {
+ // GIVEN that the media feature is enabled
+ when(mMediaFeatureFlag.getEnabled()).thenReturn(true);
+ MediaCoordinator coordinator = new MediaCoordinator(mMediaFeatureFlag);
+ // WHEN the media filter is asked about a media entry
+ NotifFilter filter = captureFilter(coordinator);
+ final boolean shouldFilter = filter.shouldFilterOut(mMediaEntry, 0);
+ // THEN it should be filtered
+ assertThat(shouldFilter).isTrue();
+ }
+
+ private NotifFilter captureFilter(MediaCoordinator coordinator) {
+ ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
+ coordinator.attach(mNotifPipeline);
+ verify(mNotifPipeline).addFinalizeFilter(filterCaptor.capture());
+ return filterCaptor.getValue();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/AppOpsInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/AppOpsInfoTest.java
index dd5cb585d0aa..ec73a7571969 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/AppOpsInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/AppOpsInfoTest.java
@@ -144,7 +144,7 @@ public class AppOpsInfoTest extends SysuiTestCase {
final View okButton = mAppOpsInfo.findViewById(R.id.ok);
okButton.performClick();
assertEquals(1, latch.getCount());
- verify(mGutsParent, times(1)).closeControls(anyInt(), anyInt(), anyBoolean(), anyBoolean());
+ verify(mGutsParent, times(1)).closeControls(eq(okButton), anyBoolean());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
index b018b59e4389..ed4f8b330e23 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentViewTest.java
@@ -16,7 +16,6 @@
package com.android.systemui.statusbar.notification.row;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
@@ -30,11 +29,13 @@ import android.app.AppOpsManager;
import android.util.ArraySet;
import android.view.NotificationHeaderView;
import android.view.View;
+import android.view.ViewPropertyAnimator;
import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.widget.NotificationExpandButton;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
@@ -98,4 +99,42 @@ public class NotificationContentViewTest extends SysuiTestCase {
verify(mockExpanded, times(1)).setVisibility(View.VISIBLE);
verify(mockHeadsUp, times(1)).setVisibility(View.VISIBLE);
}
+
+ @Test
+ @UiThreadTest
+ public void testExpandButtonFocusIsCalled() {
+ View mockContractedEB = mock(NotificationExpandButton.class);
+ View mockContracted = mock(NotificationHeaderView.class);
+ when(mockContracted.animate()).thenReturn(mock(ViewPropertyAnimator.class));
+ when(mockContracted.findViewById(com.android.internal.R.id.expand_button)).thenReturn(
+ mockContractedEB);
+
+ View mockExpandedEB = mock(NotificationExpandButton.class);
+ View mockExpanded = mock(NotificationHeaderView.class);
+ when(mockExpanded.animate()).thenReturn(mock(ViewPropertyAnimator.class));
+ when(mockExpanded.findViewById(com.android.internal.R.id.expand_button)).thenReturn(
+ mockExpandedEB);
+
+ View mockHeadsUpEB = mock(NotificationExpandButton.class);
+ View mockHeadsUp = mock(NotificationHeaderView.class);
+ when(mockHeadsUp.animate()).thenReturn(mock(ViewPropertyAnimator.class));
+ when(mockHeadsUp.findViewById(com.android.internal.R.id.expand_button)).thenReturn(
+ mockHeadsUpEB);
+
+ // Set up all 3 child forms
+ mView.setContractedChild(mockContracted);
+ mView.setExpandedChild(mockExpanded);
+ mView.setHeadsUpChild(mockHeadsUp);
+
+ // This is required to call requestAccessibilityFocus()
+ mView.setFocusOnVisibilityChange();
+
+ // The following will initialize the view and switch from not visible to expanded.
+ // (heads-up is actually an alternate form of contracted, hence this enters expanded state)
+ mView.setHeadsUp(true);
+
+ verify(mockContractedEB, times(0)).requestAccessibilityFocus();
+ verify(mockExpandedEB, times(1)).requestAccessibilityFocus();
+ verify(mockHeadsUpEB, times(0)).requestAccessibilityFocus();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index 0272028e62fc..4122cf5466e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -173,7 +173,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
doAnswer((Answer<Object>) invocation -> {
mNotificationInfo.handleCloseControls(true, false);
return null;
- }).when(mNotificationGuts).closeControls(anyInt(), anyInt(), eq(true), eq(false));
+ }).when(mNotificationGuts).closeControls(any(View.class), eq(true));
// Our view is never attached to a window so the View#post methods in NotificationInfo never
// get called. Setting this will skip the post and do the action immediately.
mNotificationInfo.mSkipPost = true;
@@ -256,7 +256,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final ImageView view = mNotificationInfo.findViewById(R.id.conversation_icon);
assertEquals(mIconDrawable, view.getDrawable());
}
@@ -280,7 +280,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final TextView textView = mNotificationInfo.findViewById(R.id.pkg_name);
assertTrue(textView.getText().toString().contains("App Name"));
assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
@@ -331,12 +331,11 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final TextView textView = mNotificationInfo.findViewById(R.id.group_name);
assertTrue(textView.getText().toString().contains(group.getName()));
assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
assertEquals(VISIBLE, textView.getVisibility());
- assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.group_divider).getVisibility());
}
@Test
@@ -357,11 +356,10 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final TextView textView = mNotificationInfo.findViewById(R.id.group_name);
assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility());
assertEquals(GONE, textView.getVisibility());
- assertEquals(GONE, mNotificationInfo.findViewById(R.id.group_divider).getVisibility());
}
@Test
@@ -382,7 +380,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
assertEquals(GONE, nameView.getVisibility());
}
@@ -417,7 +415,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
assertEquals(VISIBLE, nameView.getVisibility());
assertTrue(nameView.getText().toString().contains("Proxied"));
@@ -445,7 +443,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
settingsButton.performClick();
@@ -471,7 +469,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
assertTrue(settingsButton.getVisibility() != View.VISIBLE);
}
@@ -498,7 +496,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
false,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
final View settingsButton = mNotificationInfo.findViewById(R.id.info);
assertTrue(settingsButton.getVisibility() != View.VISIBLE);
}
@@ -523,7 +521,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View view = mNotificationInfo.findViewById(R.id.silence);
assertThat(view.isSelected()).isTrue();
}
@@ -551,7 +549,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View view = mNotificationInfo.findViewById(R.id.default_behavior);
assertThat(view.isSelected()).isTrue();
assertThat(((TextView) view.findViewById(R.id.default_summary)).getText()).isEqualTo(
@@ -582,7 +580,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View view = mNotificationInfo.findViewById(R.id.default_behavior);
assertThat(view.isSelected()).isTrue();
assertThat(((TextView) view.findViewById(R.id.default_summary)).getText()).isEqualTo(
@@ -612,7 +610,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View fave = mNotificationInfo.findViewById(R.id.priority);
fave.performClick();
@@ -656,7 +654,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
mNotificationInfo.findViewById(R.id.default_behavior).performClick();
mTestableLooper.processAllMessages();
@@ -699,7 +697,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View silence = mNotificationInfo.findViewById(R.id.silence);
@@ -743,7 +741,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View fave = mNotificationInfo.findViewById(R.id.priority);
fave.performClick();
@@ -780,7 +778,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View fave = mNotificationInfo.findViewById(R.id.priority);
fave.performClick();
@@ -795,6 +793,45 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
}
@Test
+ public void testFavorite_thenDefaultThenFavorite_andSave_nothingChanged() throws Exception {
+ mConversationChannel.setOriginalImportance(IMPORTANCE_HIGH);
+ mConversationChannel.setImportance(IMPORTANCE_HIGH);
+ mConversationChannel.setImportantConversation(true);
+
+ mNotificationInfo.bindNotification(
+ mShortcutManager,
+ mMockPackageManager,
+ mMockINotificationManager,
+ mVisualStabilityManager,
+ TEST_PACKAGE_NAME,
+ mNotificationChannel,
+ mEntry,
+ mBubbleMetadata,
+ null,
+ null,
+ mIconFactory,
+ mContext,
+ mBuilderProvider,
+ true,
+ mTestHandler,
+ mTestHandler, null);
+
+ View fave = mNotificationInfo.findViewById(R.id.priority);
+ fave.performClick();
+ mNotificationInfo.findViewById(R.id.default_behavior).performClick();
+ fave.performClick();
+ mNotificationInfo.findViewById(R.id.done).performClick();
+ mTestableLooper.processAllMessages();
+
+ ArgumentCaptor<NotificationChannel> captor =
+ ArgumentCaptor.forClass(NotificationChannel.class);
+ verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
+ anyString(), anyInt(), captor.capture());
+ assertEquals(IMPORTANCE_HIGH, captor.getValue().getImportance());
+ assertTrue(captor.getValue().isImportantConversation());
+ }
+
+ @Test
public void testDefault_andSave() throws Exception {
mConversationChannel.setAllowBubbles(true);
mConversationChannel.setOriginalImportance(IMPORTANCE_HIGH);
@@ -815,7 +852,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
mNotificationInfo.findViewById(R.id.default_behavior).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
@@ -851,7 +888,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
mNotificationInfo.findViewById(R.id.default_behavior).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
@@ -887,7 +924,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
mNotificationInfo.findViewById(R.id.default_behavior).performClick();
mNotificationInfo.findViewById(R.id.done).performClick();
@@ -922,7 +959,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
View silence = mNotificationInfo.findViewById(R.id.silence);
silence.performClick();
@@ -956,7 +993,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
verify(mMockINotificationManager, times(1)).createConversationNotificationChannelForPackage(
anyString(), anyInt(), anyString(), any(), eq(CONVERSATION_ID));
@@ -981,7 +1018,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
mBuilderProvider,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
verify(mMockINotificationManager, never()).createConversationNotificationChannelForPackage(
anyString(), anyInt(), anyString(), any(), eq(CONVERSATION_ID));
@@ -1016,10 +1053,14 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
() -> b,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
// WHEN user clicks "priority"
mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE);
+ verify(controller, never()).show();
+
+ // and then done
+ mNotificationInfo.findViewById(R.id.done).performClick();
// THEN the user is presented with the priority onboarding screen
verify(controller, atLeastOnce()).show();
@@ -1052,7 +1093,7 @@ public class NotificationConversationInfoTest extends SysuiTestCase {
() -> b,
true,
mTestHandler,
- mTestHandler);
+ mTestHandler, null);
// WHEN user clicks "priority"
mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index 8ee86a237e32..6bf60721cd8e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -236,8 +236,6 @@ public class NotificationInfoTest extends SysuiTestCase {
true);
final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name);
assertEquals(GONE, nameView.getVisibility());
- final TextView dividerView = mNotificationInfo.findViewById(R.id.group_divider);
- assertEquals(GONE, dividerView.getVisibility());
}
@Test
@@ -288,8 +286,6 @@ public class NotificationInfoTest extends SysuiTestCase {
true);
final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
assertEquals(GONE, groupNameView.getVisibility());
- final TextView dividerView = mNotificationInfo.findViewById(R.id.group_divider);
- assertEquals(GONE, dividerView.getVisibility());
}
@Test
@@ -317,8 +313,6 @@ public class NotificationInfoTest extends SysuiTestCase {
final TextView groupNameView = mNotificationInfo.findViewById(R.id.group_name);
assertEquals(View.VISIBLE, groupNameView.getVisibility());
assertEquals("Test Group Name", groupNameView.getText());
- final TextView dividerView = mNotificationInfo.findViewById(R.id.group_divider);
- assertEquals(View.VISIBLE, dividerView.getVisibility());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
index 545b59a4556a..f327967ebd73 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java
@@ -161,25 +161,6 @@ public class PartialConversationInfoTest extends SysuiTestCase {
}
@Test
- public void testBindNotification_SetsTextApplicationName() throws Exception {
- when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name");
- mInfo.bindNotification(
- mMockPackageManager,
- mMockINotificationManager,
- mChannelEditorDialogController,
- TEST_PACKAGE_NAME,
- mNotificationChannel,
- mNotificationChannelSet,
- mEntry,
- null,
- true,
- false);
- final TextView textView = mInfo.findViewById(R.id.pkg_name);
- assertTrue(textView.getText().toString().contains("App Name"));
- assertEquals(VISIBLE, mInfo.findViewById(R.id.header).getVisibility());
- }
-
- @Test
public void testBindNotification_SetsName() {
mInfo.bindNotification(
mMockPackageManager,
@@ -259,8 +240,6 @@ public class PartialConversationInfoTest extends SysuiTestCase {
false);
final TextView nameView = mInfo.findViewById(R.id.delegate_name);
assertEquals(GONE, nameView.getVisibility());
- final TextView dividerView = mInfo.findViewById(R.id.group_divider);
- assertEquals(GONE, dividerView.getVisibility());
}
@Test
@@ -305,8 +284,6 @@ public class PartialConversationInfoTest extends SysuiTestCase {
false);
final TextView groupNameView = mInfo.findViewById(R.id.group_name);
assertEquals(GONE, groupNameView.getVisibility());
- final TextView dividerView = mInfo.findViewById(R.id.group_divider);
- assertEquals(GONE, dividerView.getVisibility());
}
@Test
@@ -331,8 +308,6 @@ public class PartialConversationInfoTest extends SysuiTestCase {
final TextView groupNameView = mInfo.findViewById(R.id.group_name);
assertEquals(View.VISIBLE, groupNameView.getVisibility());
assertEquals("Test Group Name", groupNameView.getText());
- final TextView dividerView = mInfo.findViewById(R.id.group_divider);
- assertEquals(View.VISIBLE, dividerView.getVisibility());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
index 3dc941a0bd20..c55391a387d8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java
@@ -403,11 +403,11 @@ public class NotificationSectionsManagerTest extends SysuiTestCase {
enablePeopleFiltering();
setupMockStack(
- PERSON.headsUp(),
- INCOMING_HEADER,
- ALERTING.headsUp(),
- PEOPLE_HEADER,
- PERSON
+ PERSON.headsUp(), // personHeaderTarget = 0
+ INCOMING_HEADER, // currentIncomingHeaderIdx = 1
+ ALERTING.headsUp(), // alertingHeaderTarget = 1
+ PEOPLE_HEADER, // currentPeopleHeaderIdx = 3
+ PERSON //
);
mSectionsManager.updateSectionBoundaries();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index 1a6921a1d136..05cdd802167a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -172,11 +172,12 @@ public class AutoTileManagerTest extends SysuiTestCase {
}
@Test
- public void testSettingTileAddedComponent_onChanged() {
+ public void testSettingTileAddedComponentAtEnd_onChanged() {
changeValue(TEST_SETTING_COMPONENT, 1);
waitForIdleSync();
verify(mAutoAddTracker).setTileAdded(TEST_CUSTOM_SPEC);
- verify(mQsTileHost).addTile(ComponentName.unflattenFromString(TEST_COMPONENT));
+ verify(mQsTileHost).addTile(ComponentName.unflattenFromString(TEST_COMPONENT)
+ , /* end */ true);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
index be43e19cfc70..177e845bfead 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
@@ -19,6 +19,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.testing.AndroidTestingRunner;
@@ -56,6 +57,8 @@ public class NotificationIconAreaControllerTest extends SysuiTestCase {
@Mock
NotificationMediaManager mNotificationMediaManager;
@Mock
+ NotificationIconContainer mNotificationIconContainer;
+ @Mock
DozeParameters mDozeParameters;
@Mock
NotificationShadeWindowView mNotificationShadeWindowView;
@@ -67,7 +70,7 @@ public class NotificationIconAreaControllerTest extends SysuiTestCase {
when(mStatusBar.getNotificationShadeWindowView()).thenReturn(mNotificationShadeWindowView);
when(mNotificationShadeWindowView.findViewById(anyInt())).thenReturn(
- mock(NotificationIconContainer.class));
+ mNotificationIconContainer);
mController = new NotificationIconAreaController(mContext, mStatusBar,
mStatusBarStateController, mWakeUpCoordinator, mKeyguardBypassController,
@@ -87,4 +90,12 @@ public class NotificationIconAreaControllerTest extends SysuiTestCase {
assertTrue(mController.shouldShouldLowPriorityIcons());
}
+
+ @Test
+ public void testAppearResetsTranslation() {
+ when(mDozeParameters.shouldControlScreenOff()).thenReturn(false);
+ mController.appearAodIcons();
+ verify(mNotificationIconContainer).setTranslationY(0);
+ verify(mNotificationIconContainer).setAlpha(1.0f);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeRepeatableExecutor.java b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeRepeatableExecutor.java
new file mode 100644
index 000000000000..477f615faf2b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/concurrency/FakeRepeatableExecutor.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.concurrency;
+
+/**
+ * A fake to use in tests.
+ */
+public class FakeRepeatableExecutor extends RepeatableExecutorImpl {
+
+ /**
+ * Initializes a fake RepeatableExecutor from a fake executor.
+ *
+ * Use the fake executor to actually process tasks.
+ *
+ * @param executor fake executor.
+ */
+ public FakeRepeatableExecutor(FakeExecutor executor) {
+ super(executor);
+ }
+}
diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
index 8ae30a5c6f92..d07a70c1af9b 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -34,7 +34,7 @@ java_defaults {
],
libs: [
"framework-tethering.impl",
- "framework-wifi-stubs-systemapi",
+ "framework-wifi",
"unsupportedappusage",
],
plugins: ["java_api_finder"],
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
index 6c05b11258f0..c8becce7be82 100644
--- a/packages/Tethering/common/TetheringLib/Android.bp
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -30,11 +30,6 @@ java_sdk_library {
":framework-tethering-srcs",
],
- // TODO(b/155480189) - Remove naming_scheme once references have been resolved.
- // Temporary java_sdk_library component naming scheme to use to ease the transition from separate
- // modules to java_sdk_library.
- naming_scheme: "framework-modules",
-
jarjar_rules: "jarjar-rules.txt",
installable: true,
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index f08429bb0696..3fd9ee9a330b 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -730,12 +730,7 @@ public class IpServer extends StateMachine {
final String upstreamIface = v6only.getInterfaceName();
params = new RaParams();
- // When BPF offload is enabled, we advertise an mtu lower by 16, which is the closest
- // multiple of 8 >= 14, the ethernet header size. This makes kernel ebpf tethering
- // offload happy. This hack should be reverted once we have the kernel fixed up.
- // Note: this will automatically clamp to at least 1280 (ipv6 minimum mtu)
- // see RouterAdvertisementDaemon.java putMtu()
- params.mtu = mUsingBpfOffload ? v6only.getMtu() - 16 : v6only.getMtu();
+ params.mtu = v6only.getMtu();
params.hasDefaultRoute = v6only.hasIpv6DefaultRoute();
if (params.hasDefaultRoute) params.hopLimit = getHopLimit(upstreamIface, ttlAdjustment);
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java
index e095afea52ca..d084ca0966e8 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java
@@ -17,8 +17,10 @@
package com.android.networkstack.tethering;
import static android.Manifest.permission.ACCESS_NETWORK_STATE;
+import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.TETHER_PRIVILEGED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.net.TetheringManager.TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION;
import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION;
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
@@ -240,15 +242,26 @@ public class TetheringService extends Service {
return false;
}
+ private boolean hasNetworkStackPermission() {
+ return checkCallingOrSelfPermission(NETWORK_STACK)
+ || checkCallingOrSelfPermission(PERMISSION_MAINLINE_NETWORK_STACK);
+ }
+
private boolean hasTetherPrivilegedPermission() {
- return mService.checkCallingOrSelfPermission(TETHER_PRIVILEGED) == PERMISSION_GRANTED;
+ return checkCallingOrSelfPermission(TETHER_PRIVILEGED);
+ }
+
+ private boolean checkCallingOrSelfPermission(final String permission) {
+ return mService.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED;
}
private boolean hasTetherChangePermission(final String callerPkg,
final boolean onlyAllowPrivileged) {
+ if (onlyAllowPrivileged && !hasNetworkStackPermission()) return false;
+
if (hasTetherPrivilegedPermission()) return true;
- if (onlyAllowPrivileged || mTethering.isTetherProvisioningRequired()) return false;
+ if (mTethering.isTetherProvisioningRequired()) return false;
int uid = Binder.getCallingUid();
// If callerPkg's uid is not same as Binder.getCallingUid(),
diff --git a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index 2fb7e607d0af..74df11370e50 100644
--- a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -339,7 +339,7 @@ public class EthernetTetheringTest {
private MyTetheringEventCallback enableEthernetTethering(String iface) throws Exception {
return enableEthernetTethering(iface,
new TetheringRequest.Builder(TETHERING_ETHERNET)
- .setExemptFromEntitlementCheck(true).build());
+ .setShouldShowEntitlementUi(false).build());
}
private int getMTU(TestNetworkInterface iface) throws SocketException {
@@ -510,7 +510,7 @@ public class EthernetTetheringTest {
LinkAddress clientAddr = client == null ? null : new LinkAddress(client);
return new TetheringRequest.Builder(TETHERING_ETHERNET)
.setStaticIpv4Addresses(localAddr, clientAddr)
- .setExemptFromEntitlementCheck(true).build();
+ .setShouldShowEntitlementUi(false).build();
}
private void assertInvalidStaticIpv4Request(String iface, String local, String client)
diff --git a/packages/Tethering/tests/unit/Android.bp b/packages/Tethering/tests/unit/Android.bp
index fccc6902e365..45c7b656e28f 100644
--- a/packages/Tethering/tests/unit/Android.bp
+++ b/packages/Tethering/tests/unit/Android.bp
@@ -60,7 +60,7 @@ java_defaults {
"framework-minus-apex",
"framework-res",
"framework-tethering.impl",
- "framework-wifi-stubs-module_libs_api",
+ "framework-wifi.stubs.module_lib",
],
jni_libs: [
// For mockito extended
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
index f4a566659896..22d894bf471e 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
@@ -274,21 +274,32 @@ public final class TetheringServiceTest {
});
}
+ private void runStartTetheringAndVerifyNoPermission(final TestTetheringResult result)
+ throws Exception {
+ final TetheringRequestParcel request = new TetheringRequestParcel();
+ request.tetheringType = TETHERING_WIFI;
+ request.exemptFromEntitlementCheck = true;
+ mTetheringConnector.startTethering(request, TEST_CALLER_PKG, result);
+ result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
+ verifyNoMoreInteractionsForTethering();
+ }
+
@Test
- public void testStartTetheringWithExemptFromEntitlementCheck() throws Exception {
+ public void testFailToBypassEntitlementWithoutNeworkStackPermission() throws Exception {
final TetheringRequestParcel request = new TetheringRequestParcel();
request.tetheringType = TETHERING_WIFI;
request.exemptFromEntitlementCheck = true;
+ runAsNoPermission((result) -> {
+ runStartTetheringAndVerifyNoPermission(result);
+ });
+
runAsTetherPrivileged((result) -> {
- runStartTethering(result, request);
- verifyNoMoreInteractionsForTethering();
+ runStartTetheringAndVerifyNoPermission(result);
});
runAsWriteSettings((result) -> {
- mTetheringConnector.startTethering(request, TEST_CALLER_PKG, result);
- result.assertResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
- verifyNoMoreInteractionsForTethering();
+ runStartTetheringAndVerifyNoPermission(result);
});
}
diff --git a/samples/demo/haptic-assessment/Android.bp b/samples/demo/haptic-assessment/Android.bp
new file mode 100644
index 000000000000..1c006091a755
--- /dev/null
+++ b/samples/demo/haptic-assessment/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+android_app {
+ name: "HapticAssessment",
+ manifest: "AndroidManifest.xml",
+ sdk_version: "current",
+ min_sdk_version: "29",
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
+ static_libs: [
+ "androidx.appcompat_appcompat",
+ "androidx-constraintlayout_constraintlayout",
+ ],
+ resource_dirs: [
+ "res",
+ ],
+ dxflags: ["--multi-dex"],
+} \ No newline at end of file
diff --git a/samples/demo/haptic-assessment/AndroidManifest.xml b/samples/demo/haptic-assessment/AndroidManifest.xml
new file mode 100644
index 000000000000..251646eb975e
--- /dev/null
+++ b/samples/demo/haptic-assessment/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.android.hapticassessment">
+
+ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="30"/>
+
+ <uses-permission android:name="android.permission.VIBRATE" />
+
+ <application
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:roundIcon="@mipmap/ic_launcher_round"
+ android:theme="@style/AppTheme">
+ <activity android:name=".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/samples/demo/haptic-assessment/README.txt b/samples/demo/haptic-assessment/README.txt
new file mode 100644
index 000000000000..8b84cd8c6807
--- /dev/null
+++ b/samples/demo/haptic-assessment/README.txt
@@ -0,0 +1,13 @@
+README
+======
+
+This haptic assessment sample app allows the user to play with three different
+types of VibrationEffects:
+
+1) Predefined click effect with default strength.
+
+2) One shot vibration with 20ms duration at max amplitude.
+
+3) Waveform vibration with 500ms duration at half amplitude, then 500ms duration
+ at max amplitude. This will pass if the device supports vibration amplitude
+ control, and visibly fail otherwise.
diff --git a/samples/demo/haptic-assessment/res/drawable-v24/ic_launcher_foreground.xml b/samples/demo/haptic-assessment/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 000000000000..134813eb4d68
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,46 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
+ <aapt:attr name="android:fillColor">
+ <gradient
+ android:endX="85.84757"
+ android:endY="92.4963"
+ android:startX="42.9492"
+ android:startY="49.59793"
+ 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="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
+ android:strokeWidth="1"
+ android:strokeColor="#00000000" />
+</vector> \ No newline at end of file
diff --git a/samples/demo/haptic-assessment/res/drawable/bluebar.png b/samples/demo/haptic-assessment/res/drawable/bluebar.png
new file mode 100644
index 000000000000..ae163df4295a
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/drawable/bluebar.png
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/drawable/cross_60x60.gif b/samples/demo/haptic-assessment/res/drawable/cross_60x60.gif
new file mode 100644
index 000000000000..cf3561757e38
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/drawable/cross_60x60.gif
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/drawable/ic_launcher_background.xml b/samples/demo/haptic-assessment/res/drawable/ic_launcher_background.xml
new file mode 100644
index 000000000000..5634f725f245
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,185 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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="#3DDC84"
+ 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/samples/demo/haptic-assessment/res/layout/activity_main.xml b/samples/demo/haptic-assessment/res/layout/activity_main.xml
new file mode 100644
index 000000000000..47d45a60a6a4
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/layout/activity_main.xml
@@ -0,0 +1,93 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<androidx.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/click_effect_button"
+ android:layout_width="@dimen/button_width"
+ android:layout_height="@dimen/button_height"
+ android:layout_marginHorizontal="@dimen/button_horizontal_margin"
+ android:layout_marginTop="@dimen/button_vertical_margin"
+ android:text="@string/click_effect_button"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"/>
+
+ <Button
+ android:id="@+id/oneshot_effect_button"
+ android:layout_width="@dimen/button_width"
+ android:layout_height="@dimen/button_height"
+ android:layout_marginHorizontal="@dimen/button_horizontal_margin"
+ android:layout_marginTop="@dimen/button_vertical_margin"
+ android:text="@string/oneshot_effect_button"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/click_effect_button"/>
+
+ <Button
+ android:id="@+id/waveform_effect_button"
+ android:layout_width="@dimen/button_width"
+ android:layout_height="@dimen/button_height"
+ android:layout_marginHorizontal="@dimen/button_horizontal_margin"
+ android:layout_marginTop="@dimen/button_vertical_margin"
+ android:text="@string/waveform_effect_button"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/oneshot_effect_button"/>
+
+ <View
+ android:id="@+id/divider"
+ android:layout_width="363dp"
+ android:layout_height="1dp"
+ android:layout_marginHorizontal="@dimen/button_horizontal_margin"
+ android:layout_marginTop="10dp"
+ android:background="?android:attr/listDivider"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0.5"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/waveform_effect_button"/>
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="363dp"
+ android:layout_height="0dp"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0.5"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/divider">
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:adjustViewBounds="true"
+ android:scaleType="fitXY"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintHorizontal_bias="0.5"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ app:srcCompat="@drawable/bluebar"/>
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
diff --git a/packages/CarSystemUI/res/drawable/nav_button_background.xml b/samples/demo/haptic-assessment/res/mipmap-anydpi-v26/ic_launcher.xml
index 376347cdf4a9..47606a49580f 100644
--- a/packages/CarSystemUI/res/drawable/nav_button_background.xml
+++ b/samples/demo/haptic-assessment/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -1,6 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2018 The Android Open Source Project
+ ~ Copyright (C) 2020 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -12,15 +11,10 @@
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
- ~ limitations under the License
+ ~ limitations under the License.
-->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="@color/nav_bar_ripple_background_color">
- <item android:id="@android:id/mask">
- <shape android:shape="rectangle">
- <solid android:color="?android:colorAccent"/>
- <corners android:radius="6dp"/>
- </shape>
- </item>
-</ripple>
+<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/samples/demo/haptic-assessment/res/mipmap-anydpi-v26/ic_launcher_round.xml b/samples/demo/haptic-assessment/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 000000000000..47606a49580f
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,20 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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/samples/demo/haptic-assessment/res/mipmap-hdpi/ic_launcher.png b/samples/demo/haptic-assessment/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000000..a571e60098c9
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/mipmap-hdpi/ic_launcher_round.png b/samples/demo/haptic-assessment/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 000000000000..61da551c5594
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/mipmap-mdpi/ic_launcher.png b/samples/demo/haptic-assessment/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000000..c41dd2853190
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/mipmap-mdpi/ic_launcher_round.png b/samples/demo/haptic-assessment/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 000000000000..db5080a75273
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-mdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/mipmap-xhdpi/ic_launcher.png b/samples/demo/haptic-assessment/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000000..6dba46dab192
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/mipmap-xhdpi/ic_launcher_round.png b/samples/demo/haptic-assessment/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 000000000000..da31a871c8dc
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/mipmap-xxhdpi/ic_launcher.png b/samples/demo/haptic-assessment/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000000..15ac681720f3
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/mipmap-xxhdpi/ic_launcher_round.png b/samples/demo/haptic-assessment/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 000000000000..b216f2d313cc
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/mipmap-xxxhdpi/ic_launcher.png b/samples/demo/haptic-assessment/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000000..f25a41974472
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/mipmap-xxxhdpi/ic_launcher_round.png b/samples/demo/haptic-assessment/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 000000000000..e96783ccce84
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/samples/demo/haptic-assessment/res/values/colors.xml b/samples/demo/haptic-assessment/res/values/colors.xml
new file mode 100644
index 000000000000..2883b95397a2
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/values/colors.xml
@@ -0,0 +1,21 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <color name="colorPrimary">#009688</color>
+ <color name="colorPrimaryDark">#673AB7</color>
+ <color name="colorAccent">#03DAC5</color>
+</resources>
diff --git a/samples/demo/haptic-assessment/res/values/dimen.xml b/samples/demo/haptic-assessment/res/values/dimen.xml
new file mode 100644
index 000000000000..f9090ed39568
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/values/dimen.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+ <dimen name="button_width">350dp</dimen>
+ <dimen name="button_height">60dp</dimen>
+ <dimen name="button_horizontal_margin">32dp</dimen>
+ <dimen name="button_vertical_margin">5dp</dimen>
+ <dimen name="fab_margin">16dp</dimen>
+</resources>
diff --git a/samples/demo/haptic-assessment/res/values/strings.xml b/samples/demo/haptic-assessment/res/values/strings.xml
new file mode 100644
index 000000000000..a22d8dbe0580
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/values/strings.xml
@@ -0,0 +1,24 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <string name="app_name">Haptic Hardware Assessment 2020</string>
+ <string name="click_effect_button">Effect 1</string>
+ <string name="oneshot_effect_button">Effect 2</string>
+ <string name="waveform_effect_button">Effect 3</string>
+ <string name="button_3_pass">Effect 3: PASS</string>
+ <string name="button_3_fail">Effect 3: FAIL</string>
+</resources>
diff --git a/samples/demo/haptic-assessment/res/values/styles.xml b/samples/demo/haptic-assessment/res/values/styles.xml
new file mode 100644
index 000000000000..1abcab1d2dc9
--- /dev/null
+++ b/samples/demo/haptic-assessment/res/values/styles.xml
@@ -0,0 +1,28 @@
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+ <item name="android:buttonStyle">@style/AppButton</item>
+ <item name="colorPrimary">@color/colorPrimary</item>
+ <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+ <item name="colorAccent">@color/colorAccent</item>
+ </style>
+
+ <style name="AppButton" parent="@android:style/Widget.Button">
+ <item name="android:textSize">18sp</item>
+ </style>
+</resources>
diff --git a/samples/demo/haptic-assessment/src/com/example/android/hapticassessment/MainActivity.kt b/samples/demo/haptic-assessment/src/com/example/android/hapticassessment/MainActivity.kt
new file mode 100644
index 000000000000..d198b51b935c
--- /dev/null
+++ b/samples/demo/haptic-assessment/src/com/example/android/hapticassessment/MainActivity.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.hapticassessment
+
+import android.graphics.Color
+import android.os.Bundle
+import android.os.VibrationEffect
+import android.os.VibrationEffect.EFFECT_CLICK
+import android.os.Vibrator
+import android.view.View
+import android.widget.Button
+
+import androidx.appcompat.app.AppCompatActivity
+
+/** App main screen. */
+class MainActivity : AppCompatActivity() {
+
+ companion object {
+
+ private const val ONE_SHOT_TIMING = 20L
+ private const val ONE_SHOT_AMPLITUDE = 255
+
+ private val WAVEFORM_TIMINGS = longArrayOf(500, 500)
+ private val WAVEFORM_AMPLITUDES = intArrayOf(128, 255)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+
+ val vibrator = getSystemService(Vibrator::class.java)
+
+ findViewById<Button>(R.id.click_effect_button).setOnClickListener {
+ vibrator.vibrate(VibrationEffect.createPredefined(EFFECT_CLICK))
+ }
+
+ findViewById<Button>(R.id.oneshot_effect_button).setOnClickListener {
+ vibrator.vibrate(VibrationEffect.createOneShot(ONE_SHOT_TIMING, ONE_SHOT_AMPLITUDE))
+ }
+
+ findViewById<Button>(R.id.waveform_effect_button).setOnClickListener { view: View ->
+ vibrator.vibrate(
+ VibrationEffect.createWaveform(WAVEFORM_TIMINGS, WAVEFORM_AMPLITUDES, -1))
+
+ val button = view as Button
+ if (vibrator.hasAmplitudeControl()) {
+ button.text = getString(R.string.button_3_pass)
+ button.setBackgroundColor(Color.GREEN)
+ button.setTextColor(Color.BLACK)
+ } else {
+ button.text = getString(R.string.button_3_fail)
+ button.setBackgroundColor(Color.RED)
+ button.setTextColor(Color.WHITE)
+ }
+ }
+ }
+}
diff --git a/services/Android.bp b/services/Android.bp
index 882085a7d0ba..00676e332656 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -87,7 +87,7 @@ java_library {
libs: [
"android.hidl.manager-V1.0-java",
- "framework-tethering-stubs-module_libs_api",
+ "framework-tethering.stubs.module_lib",
],
// Uncomment to enable output of certain warnings (deprecated, unchecked)
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
index 468e93a8f683..d15c60b9501d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityWindowManager.java
@@ -725,7 +725,8 @@ public class AccessibilityWindowManager {
case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
case WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY:
- case WindowManager.LayoutParams.TYPE_SCREENSHOT: {
+ case WindowManager.LayoutParams.TYPE_SCREENSHOT:
+ case WindowManager.LayoutParams.TYPE_TRUSTED_APPLICATION_OVERLAY: {
return AccessibilityWindowInfo.TYPE_SYSTEM;
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
index e2330ca6ffe9..0ec8654f2a20 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSessionController.java
@@ -75,9 +75,7 @@ final class AutofillInlineSessionController {
@NonNull Consumer<InlineSuggestionsRequest> requestConsumer, @NonNull Bundle uiExtras) {
// TODO(b/151123764): rename the method to better reflect what it does.
if (mSession != null) {
- // Send an empty response to IME and destroy the existing session.
- mSession.onInlineSuggestionsResponseLocked(
- InlineFillUi.emptyUi(mSession.getAutofillIdLocked()));
+ // Destroy the existing session.
mSession.destroySessionLocked();
mInlineFillUi = null;
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
index 687b75a8b949..e7a43b75f9d5 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java
@@ -40,7 +40,6 @@ import com.android.server.autofill.ui.InlineFillUi;
import com.android.server.inputmethod.InputMethodManagerInternal;
import java.lang.ref.WeakReference;
-import java.util.Collections;
import java.util.Optional;
import java.util.function.Consumer;
@@ -209,18 +208,9 @@ final class AutofillInlineSuggestionsRequestSession {
if (mDestroyed || mResponseCallback == null) {
return;
}
- if (!mImeInputStarted && mPreviousResponseIsNotEmpty) {
- // 1. if previous response is not empty, and IME is just disconnected from the view,
- // then send empty response to make sure existing responses don't stick around.
- // Although the inline suggestions should disappear when IME hides which removes them
- // from the view hierarchy, but we still send an empty response to indicate that the
- // previous suggestions are invalid now.
- if (sVerbose) Slog.v(TAG, "Send empty inline response");
- updateResponseToImeUncheckLocked(new InlineSuggestionsResponse(Collections.EMPTY_LIST));
- mPreviousResponseIsNotEmpty = false;
- } else if (mImeInputViewStarted && mInlineFillUi != null && match(mAutofillId,
+ if (mImeInputViewStarted && mInlineFillUi != null && match(mAutofillId,
mImeCurrentFieldId)) {
- // 2. if IME is visible, and response is not null, send the response
+ // if IME is visible, and response is not null, send the response
InlineSuggestionsResponse response = mInlineFillUi.getInlineSuggestionsResponse();
boolean isEmptyResponse = response.getInlineSuggestions().isEmpty();
if (isEmptyResponse && !mPreviousResponseIsNotEmpty) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 42e859f9d713..089861bee479 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -192,7 +192,7 @@ public final class AutofillManagerService
public AutofillManagerService(Context context) {
super(context,
new SecureSettingsServiceNameResolver(context, Settings.Secure.AUTOFILL_SERVICE),
- UserManager.DISALLOW_AUTOFILL);
+ UserManager.DISALLOW_AUTOFILL, PACKAGE_UPDATE_POLICY_REFRESH_EAGER);
mUi = new AutoFillUI(ActivityThread.currentActivityThread().getSystemUiContext());
mAm = LocalServices.getService(ActivityManagerInternal.class);
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index ffdb9c83c805..642526d13aff 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -3852,6 +3852,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
for (int i = 0; i < responseCount; i++) {
if (mResponses.keyAt(i) > lastResponseId) {
lastResponseIdx = i;
+ lastResponseId = mResponses.keyAt(i);
}
}
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index a95a0c2eaf28..9e8a8727dc36 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -99,7 +99,7 @@ java_library_static {
"android.hardware.vibrator-java",
"android.net.ipsec.ike.stubs.module_lib",
"app-compat-annotations",
- "framework-tethering-stubs-module_libs_api",
+ "framework-tethering.stubs.module_lib",
"service-permission-stubs",
],
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 3c0d880916ee..0d4efed25da3 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -954,7 +954,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
/**
- * Call IBluetooth.onLeServiceUp() to continue if Bluetooth should be on.
+ * Call IBluetooth.onLeServiceUp() to continue if Bluetooth should be on,
+ * call IBluetooth.onBrEdrDown() to disable if Bluetooth should be off.
*/
private void continueFromBleOnState() {
if (DBG) {
@@ -966,11 +967,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
Slog.e(TAG, "onBluetoothServiceUp: mBluetooth is null!");
return;
}
- if (!mEnableExternal && !isBleAppPresent() && isAirplaneModeOn()) {
- // Airplane mode is turned on while enabling BLE only mode, disable
- // BLE now.
- disableBleScanMode();
- sendBrEdrDownCallback();
+ if (!mEnableExternal && !isBleAppPresent()) {
+ Slog.i(TAG, "Bluetooth was disabled while enabling BLE, disable BLE now");
+ mEnable = false;
+ mBluetooth.onBrEdrDown();
return;
}
if (isBluetoothPersistedStateOnBluetooth() || !isBleAppPresent()) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 1634f6e62897..0ab571854c72 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1374,10 +1374,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (nri == null || net == null || !LOGD_BLOCKED_NETWORKINFO) {
return;
}
- String action = blocked ? "BLOCKED" : "UNBLOCKED";
- log(String.format("Blocked status changed to %s for %d(%d) on netId %d", blocked,
- nri.mUid, nri.request.requestId, net.netId));
- mNetworkInfoBlockingLogs.log(action + " " + nri.mUid);
+ final String action = blocked ? "BLOCKED" : "UNBLOCKED";
+ mNetworkInfoBlockingLogs.log(String.format(
+ "%s %d(%d) on netId %d", action, nri.mUid, nri.request.requestId, net.netId));
}
/**
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index e77458cc955a..fd7abfa65c86 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -239,7 +239,10 @@ public class PackageWatchdog {
mIsPackagesReady = true;
mHealthCheckController.setCallbacks(packageName -> onHealthCheckPassed(packageName),
packages -> onSupportedPackages(packages),
- () -> syncRequestsAsync());
+ () -> {
+ syncRequestsAsync();
+ mSyncRequired = true;
+ });
setPropertyChangedListenerLocked();
updateConfigs();
registerConnectivityModuleHealthListener();
@@ -255,7 +258,6 @@ public class PackageWatchdog {
*/
public void registerHealthObserver(PackageHealthObserver observer) {
synchronized (mLock) {
- mSyncRequired = true;
ObserverInternal internalObserver = mAllObservers.get(observer.getName());
if (internalObserver != null) {
internalObserver.registeredObserver = observer;
@@ -642,7 +644,8 @@ public class PackageWatchdog {
synchronized (mLock) {
if (mIsPackagesReady) {
Set<String> packages = getPackagesPendingHealthChecksLocked();
- if (!packages.equals(mRequestedHealthCheckPackages) || mSyncRequired) {
+ if (mSyncRequired || !packages.equals(mRequestedHealthCheckPackages)
+ || packages.isEmpty()) {
syncRequired = true;
mRequestedHealthCheckPackages = packages;
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index b3e28cb946a9..8eb401a7ee55 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -376,6 +376,7 @@ class StorageManagerService extends IStorageManager.Stub
private class WatchedLockedUsers {
private int[] users = EmptyArray.INT;
public WatchedLockedUsers() {
+ invalidateIsUserUnlockedCache();
}
public void append(int userId) {
users = ArrayUtils.appendInt(users, userId);
@@ -4656,9 +4657,8 @@ class StorageManagerService extends IStorageManager.Stub
private void killAppForOpChange(int code, int uid, String packageName) {
final IActivityManager am = ActivityManager.getService();
try {
- am.killApplication(packageName,
- UserHandle.getAppId(uid),
- UserHandle.USER_ALL, AppOpsManager.opToName(code) + " changed.");
+ am.killUid(UserHandle.getAppId(uid), UserHandle.USER_ALL,
+ AppOpsManager.opToName(code) + " changed.");
} catch (RemoteException e) {
}
}
@@ -4680,7 +4680,12 @@ class StorageManagerService extends IStorageManager.Stub
// results in a bad UX, especially since the gid only gives access
// to unreliable volumes, USB OTGs that are rarely mounted. The app
// will get the external_storage gid on next organic restart.
- killAppForOpChange(code, uid, packageName);
+ if (packageName != null) {
+ killAppForOpChange(code, uid, packageName);
+ } else {
+ // TODO(b/158283222) this can happen, figure out if we need
+ // to kill in this case as well.
+ }
}
return;
case OP_LEGACY_STORAGE:
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index 197a2cef0a62..74bb7d7e90f1 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -198,12 +198,12 @@ public class SystemServiceManager {
Slog.i(TAG, "Starting phase " + mCurrentPhase);
try {
- t.traceBegin("OnBootPhase " + phase);
+ t.traceBegin("OnBootPhase_" + phase);
final int serviceLen = mServices.size();
for (int i = 0; i < serviceLen; i++) {
final SystemService service = mServices.get(i);
long time = SystemClock.elapsedRealtime();
- t.traceBegin("OnBootPhase " + service.getClass().getName());
+ t.traceBegin("OnBootPhase_" + phase + "_" + service.getClass().getName());
try {
service.onBootPhase(mCurrentPhase);
} catch (Exception ex) {
@@ -332,7 +332,7 @@ public class SystemServiceManager {
}
continue;
}
- t.traceBegin("ssm.on" + onWhat + "User-" + curUserId + " " + serviceName);
+ t.traceBegin("ssm.on" + onWhat + "User-" + curUserId + "_" + serviceName);
long time = SystemClock.elapsedRealtime();
try {
switch (onWhat) {
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index e066d99147ba..a153d4191a5c 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -1894,6 +1894,8 @@ public class VibratorService extends IVibratorService.Stub
return runWaveform();
} else if ("prebaked".equals(cmd)) {
return runPrebaked();
+ } else if ("capabilities".equals(cmd)) {
+ return runCapabilities();
} else if ("cancel".equals(cmd)) {
cancelVibrate(mToken);
return 0;
@@ -2016,10 +2018,15 @@ public class VibratorService extends IVibratorService.Stub
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runPrebaked");
try {
CommonOptions commonOptions = new CommonOptions();
+ boolean shouldFallback = false;
String opt;
while ((opt = getNextOption()) != null) {
- commonOptions.check(opt);
+ if ("-b".equals(opt)) {
+ shouldFallback = true;
+ } else {
+ commonOptions.check(opt);
+ }
}
if (checkDoNotDisturb(commonOptions)) {
@@ -2033,8 +2040,7 @@ public class VibratorService extends IVibratorService.Stub
description = "Shell command";
}
- VibrationEffect effect =
- VibrationEffect.get(id, false);
+ VibrationEffect effect = VibrationEffect.get(id, shouldFallback);
VibrationAttributes attrs = createVibrationAttributes(commonOptions);
vibrate(Binder.getCallingUid(), description, effect, attrs, "Shell Command",
mToken);
@@ -2044,12 +2050,39 @@ public class VibratorService extends IVibratorService.Stub
}
}
+ private int runCapabilities() {
+ Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runCapabilities");
+ try (PrintWriter pw = getOutPrintWriter();) {
+ pw.println("Vibrator capabilities:");
+ if (hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
+ pw.println(" Always on effects");
+ }
+ if (hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
+ pw.println(" Compose effects");
+ }
+ if (mSupportsAmplitudeControl || hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
+ pw.println(" Amplitude control");
+ }
+ if (mSupportsExternalControl || hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
+ pw.println(" External control");
+ }
+ if (hasCapability(IVibrator.CAP_EXTERNAL_AMPLITUDE_CONTROL)) {
+ pw.println(" External amplitude control");
+ }
+ pw.println("");
+ return 0;
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+ }
+ }
+
private VibrationAttributes createVibrationAttributes(CommonOptions commonOptions) {
final int flags = commonOptions.force
? VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY
: 0;
return new VibrationAttributes.Builder()
- .setUsage(VibrationAttributes.USAGE_UNKNOWN)
+ // Used to apply Settings.System.HAPTIC_FEEDBACK_INTENSITY to scale effects.
+ .setUsage(VibrationAttributes.USAGE_TOUCH)
.replaceFlags(flags)
.build();
}
@@ -2062,19 +2095,26 @@ public class VibratorService extends IVibratorService.Stub
pw.println(" Prints this help text.");
pw.println("");
pw.println(" vibrate duration [description]");
- pw.println(" Vibrates for duration milliseconds; ignored when device is on DND ");
- pw.println(" (Do Not Disturb) mode.");
+ pw.println(" Vibrates for duration milliseconds; ignored when device is on ");
+ pw.println(" DND (Do Not Disturb) mode; touch feedback strength user setting ");
+ pw.println(" will be used to scale amplitude.");
pw.println(" waveform [-d description] [-r index] [-a] duration [amplitude] ...");
- pw.println(" Vibrates for durations and amplitudes in list;");
- pw.println(" ignored when device is on DND (Do Not Disturb) mode.");
+ pw.println(" Vibrates for durations and amplitudes in list; ignored when ");
+ pw.println(" device is on DND (Do Not Disturb) mode; touch feedback strength ");
+ pw.println(" user setting will be used to scale amplitude.");
pw.println(" If -r is provided, the waveform loops back to the specified");
pw.println(" index (e.g. 0 loops from the beginning)");
pw.println(" If -a is provided, the command accepts duration-amplitude pairs;");
pw.println(" otherwise, it accepts durations only and alternates off/on");
pw.println(" Duration is in milliseconds; amplitude is a scale of 1-255.");
- pw.println(" prebaked effect-id [description]");
+ pw.println(" prebaked [-b] effect-id [description]");
pw.println(" Vibrates with prebaked effect; ignored when device is on DND ");
- pw.println(" (Do Not Disturb) mode.");
+ pw.println(" (Do Not Disturb) mode; touch feedback strength user setting ");
+ pw.println(" will be used to scale amplitude.");
+ pw.println(" If -b is provided, the prebaked fallback effect will be played if");
+ pw.println(" the device doesn't support the given effect-id.");
+ pw.println(" capabilities");
+ pw.println(" Prints capabilities of this device.");
pw.println(" cancel");
pw.println(" Cancels any active vibration");
pw.println("Common Options:");
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 5046070647d6..c5c3cafa8813 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2460,16 +2460,22 @@ public final class ActiveServices {
&& mAm.isValidSingletonCall(callingUid, sInfo.applicationInfo.uid)) {
userId = 0;
smap = getServiceMapLocked(0);
- ResolveInfo rInfoForUserId0 =
- mAm.getPackageManagerInternalLocked().resolveService(service,
- resolvedType, flags, userId, callingUid);
- if (rInfoForUserId0 == null) {
- Slog.w(TAG_SERVICE,
- "Unable to resolve service " + service + " U=" + userId
- + ": not found");
- return null;
+ // Bypass INTERACT_ACROSS_USERS permission check
+ final long token = Binder.clearCallingIdentity();
+ try {
+ ResolveInfo rInfoForUserId0 =
+ mAm.getPackageManagerInternalLocked().resolveService(service,
+ resolvedType, flags, userId, callingUid);
+ if (rInfoForUserId0 == null) {
+ Slog.w(TAG_SERVICE,
+ "Unable to resolve service " + service + " U=" + userId
+ + ": not found");
+ return null;
+ }
+ sInfo = rInfoForUserId0.serviceInfo;
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
- sInfo = rInfoForUserId0.serviceInfo;
}
sInfo = new ServiceInfo(sInfo);
sInfo.applicationInfo = mAm.getAppInfoForUser(sInfo.applicationInfo, userId);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a4e45cd334bf..caaa8371af53 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -18900,30 +18900,8 @@ public class ActivityManagerService extends IActivityManager.Stub
@Override
public int checkContentProviderUriPermission(Uri uri, int userId,
int callingUid, int modeFlags) {
- // We can find ourselves needing to check Uri permissions while
- // already holding the WM lock, which means reaching back here for
- // the AM lock would cause an inversion. The WM team has requested
- // that we use the strategy below instead of shifting where Uri
- // grants are calculated.
-
- // Since we could also arrive here while holding the AM lock, we
- // can't always delegate the call through the handler, and we need
- // to delicately dance between the deadlocks.
- if (Thread.currentThread().holdsLock(ActivityManagerService.this)) {
- return ActivityManagerService.this.checkContentProviderUriPermission(uri,
- userId, callingUid, modeFlags);
- } else {
- final CompletableFuture<Integer> res = new CompletableFuture<>();
- mHandler.post(() -> {
- res.complete(ActivityManagerService.this.checkContentProviderUriPermission(uri,
- userId, callingUid, modeFlags));
- });
- try {
- return res.get();
- } catch (InterruptedException | ExecutionException e) {
- throw new RuntimeException(e);
- }
- }
+ return ActivityManagerService.this.checkContentProviderUriPermission(uri,
+ userId, callingUid, modeFlags);
}
@Override
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 5427dd2328a6..27d9ba08e4a2 100755
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1908,31 +1908,11 @@ public class AudioService extends IAudioService.Stub
/** @see AudioManager#adjustVolume(int, int) */
public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
String callingPackage, String caller) {
- final IAudioPolicyCallback extVolCtlr;
- synchronized (mExtVolumeControllerLock) {
- extVolCtlr = mExtVolumeController;
- }
- new MediaMetrics.Item(mMetricsId + "adjustSuggestedStreamVolume")
- .setUid(Binder.getCallingUid())
- .set(MediaMetrics.Property.CALLING_PACKAGE, callingPackage)
- .set(MediaMetrics.Property.CLIENT_NAME, caller)
- .set(MediaMetrics.Property.DIRECTION, direction > 0
- ? MediaMetrics.Value.UP : MediaMetrics.Value.DOWN)
- .set(MediaMetrics.Property.EXTERNAL, extVolCtlr != null
- ? MediaMetrics.Value.YES : MediaMetrics.Value.NO)
- .set(MediaMetrics.Property.FLAGS, flags)
- .record();
- if (extVolCtlr != null) {
- sendMsg(mAudioHandler, MSG_NOTIFY_VOL_EVENT, SENDMSG_QUEUE,
- direction, 0 /*ignored*/,
- extVolCtlr, 0 /*delay*/);
- } else {
- final boolean hasModifyAudioSettings =
- mContext.checkCallingPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
- == PackageManager.PERMISSION_GRANTED;
- adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
- caller, Binder.getCallingUid(), hasModifyAudioSettings, VOL_ADJUST_NORMAL);
- }
+ boolean hasModifyAudioSettings =
+ mContext.checkCallingPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS)
+ == PackageManager.PERMISSION_GRANTED;
+ adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
+ caller, Binder.getCallingUid(), hasModifyAudioSettings, VOL_ADJUST_NORMAL);
}
private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
@@ -1947,6 +1927,24 @@ public class AudioService extends IAudioService.Stub
direction/*val1*/, flags/*val2*/, new StringBuilder(callingPackage)
.append("/").append(caller).append(" uid:").append(uid).toString()));
}
+
+ boolean hasExternalVolumeController = notifyExternalVolumeController(direction);
+
+ new MediaMetrics.Item(mMetricsId + "adjustSuggestedStreamVolume")
+ .setUid(Binder.getCallingUid())
+ .set(MediaMetrics.Property.CALLING_PACKAGE, callingPackage)
+ .set(MediaMetrics.Property.CLIENT_NAME, caller)
+ .set(MediaMetrics.Property.DIRECTION, direction > 0
+ ? MediaMetrics.Value.UP : MediaMetrics.Value.DOWN)
+ .set(MediaMetrics.Property.EXTERNAL, hasExternalVolumeController
+ ? MediaMetrics.Value.YES : MediaMetrics.Value.NO)
+ .set(MediaMetrics.Property.FLAGS, flags)
+ .record();
+
+ if (hasExternalVolumeController) {
+ return;
+ }
+
final int streamType;
synchronized (mForceControlStreamLock) {
// Request lock in case mVolumeControlStream is changed by other thread.
@@ -1995,6 +1993,21 @@ public class AudioService extends IAudioService.Stub
hasModifyAudioSettings, keyEventMode);
}
+ private boolean notifyExternalVolumeController(int direction) {
+ final IAudioPolicyCallback externalVolumeController;
+ synchronized (mExtVolumeControllerLock) {
+ externalVolumeController = mExtVolumeController;
+ }
+ if (externalVolumeController == null) {
+ return false;
+ }
+
+ sendMsg(mAudioHandler, MSG_NOTIFY_VOL_EVENT, SENDMSG_QUEUE,
+ direction, 0 /*ignored*/,
+ externalVolumeController, 0 /*delay*/);
+ return true;
+ }
+
/** @see AudioManager#adjustStreamVolume(int, int, int)
* Part of service interface, check permissions here */
public void adjustStreamVolume(int streamType, int direction, int flags,
@@ -7370,6 +7383,7 @@ public class AudioService extends IAudioService.Stub
pw.print(" mIsSingleVolume="); pw.println(mIsSingleVolume);
pw.print(" mUseFixedVolume="); pw.println(mUseFixedVolume);
pw.print(" mFixedVolumeDevices="); pw.println(dumpDeviceTypes(mFixedVolumeDevices));
+ pw.print(" mExtVolumeController="); pw.println(mExtVolumeController);
pw.print(" mHdmiCecSink="); pw.println(mHdmiCecSink);
pw.print(" mHdmiAudioSystemClient="); pw.println(mHdmiAudioSystemClient);
pw.print(" mHdmiPlaybackClient="); pw.println(mHdmiPlaybackClient);
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 9de95abafdda..b9669c74a6df 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -40,6 +40,7 @@ import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.HdmiHotplugEvent;
import android.hardware.hdmi.HdmiPortInfo;
+import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener;
import android.hardware.hdmi.IHdmiControlCallback;
import android.hardware.hdmi.IHdmiControlService;
import android.hardware.hdmi.IHdmiControlStatusChangeListener;
@@ -63,6 +64,7 @@ import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.PowerManager;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -268,6 +270,11 @@ public class HdmiControlService extends SystemService {
private final ArrayList<HdmiControlStatusChangeListenerRecord>
mHdmiControlStatusChangeListenerRecords = new ArrayList<>();
+ // List of records for HDMI control volume control status change listener for death monitoring.
+ @GuardedBy("mLock")
+ private final RemoteCallbackList<IHdmiCecVolumeControlFeatureListener>
+ mHdmiCecVolumeControlFeatureListenerRecords = new RemoteCallbackList<>();
+
// List of records for hotplug event listener to handle the the caller killed in action.
@GuardedBy("mLock")
private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords =
@@ -1814,6 +1821,21 @@ public class HdmiControlService extends SystemService {
}
@Override
+ public void addHdmiCecVolumeControlFeatureListener(
+ final IHdmiCecVolumeControlFeatureListener listener) {
+ enforceAccessPermission();
+ HdmiControlService.this.addHdmiCecVolumeControlFeatureListener(listener);
+ }
+
+ @Override
+ public void removeHdmiCecVolumeControlFeatureListener(
+ final IHdmiCecVolumeControlFeatureListener listener) {
+ enforceAccessPermission();
+ HdmiControlService.this.removeHdmiControlVolumeControlStatusChangeListener(listener);
+ }
+
+
+ @Override
public void addHotplugEventListener(final IHdmiHotplugEventListener listener) {
enforceAccessPermission();
HdmiControlService.this.addHotplugEventListener(listener);
@@ -2409,6 +2431,33 @@ public class HdmiControlService extends SystemService {
}
}
+ @VisibleForTesting
+ void addHdmiCecVolumeControlFeatureListener(
+ final IHdmiCecVolumeControlFeatureListener listener) {
+ mHdmiCecVolumeControlFeatureListenerRecords.register(listener);
+
+ runOnServiceThread(new Runnable() {
+ @Override
+ public void run() {
+ // Return the current status of mHdmiCecVolumeControlEnabled;
+ synchronized (mLock) {
+ try {
+ listener.onHdmiCecVolumeControlFeature(mHdmiCecVolumeControlEnabled);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to report HdmiControlVolumeControlStatusChange: "
+ + mHdmiCecVolumeControlEnabled, e);
+ }
+ }
+ }
+ });
+ }
+
+ @VisibleForTesting
+ void removeHdmiControlVolumeControlStatusChangeListener(
+ final IHdmiCecVolumeControlFeatureListener listener) {
+ mHdmiCecVolumeControlFeatureListenerRecords.unregister(listener);
+ }
+
private void addHotplugEventListener(final IHdmiHotplugEventListener listener) {
final HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener);
try {
@@ -2682,6 +2731,19 @@ public class HdmiControlService extends SystemService {
}
}
+ private void announceHdmiCecVolumeControlFeatureChange(boolean isEnabled) {
+ assertRunOnServiceThread();
+ mHdmiCecVolumeControlFeatureListenerRecords.broadcast(listener -> {
+ try {
+ listener.onHdmiCecVolumeControlFeature(isEnabled);
+ } catch (RemoteException e) {
+ Slog.e(TAG,
+ "Failed to report HdmiControlVolumeControlStatusChange: "
+ + isEnabled);
+ }
+ });
+ }
+
public HdmiCecLocalDeviceTv tv() {
return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_TV);
}
@@ -3026,6 +3088,7 @@ public class HdmiControlService extends SystemService {
isHdmiCecVolumeControlEnabled);
}
}
+ announceHdmiCecVolumeControlFeatureChange(isHdmiCecVolumeControlEnabled);
}
boolean isHdmiCecVolumeControlEnabled() {
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
index 13f0f4ae4a92..5d913d12b79f 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
@@ -64,12 +64,6 @@ final class SystemAudioStatusAction extends HdmiCecFeatureAction {
}
private void handleSendGiveAudioStatusFailure() {
- // Inform to all application that the audio status (volume, mute) of
- // the audio amplifier is unknown.
- tv().setAudioStatus(false, Constants.UNKNOWN_VOLUME);
-
- sendUserControlPressedAndReleased(mAvrAddress,
- HdmiCecKeycode.getMuteKey(!tv().isSystemAudioActivated()));
// Still return SUCCESS to callback.
finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index ccbe96f30e04..067bdcb111fb 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -28,6 +28,9 @@ import static android.os.PowerManager.locationPowerSaveModeToString;
import static com.android.server.location.CallerIdentity.PERMISSION_COARSE;
import static com.android.server.location.CallerIdentity.PERMISSION_FINE;
+import static com.android.server.location.UserInfoHelper.UserListener.CURRENT_USER_CHANGED;
+import static com.android.server.location.UserInfoHelper.UserListener.USER_STARTED;
+import static com.android.server.location.UserInfoHelper.UserListener.USER_STOPPED;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
@@ -64,6 +67,7 @@ import android.location.LocationProvider;
import android.location.LocationRequest;
import android.location.LocationTime;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Handler;
@@ -101,7 +105,7 @@ import com.android.server.location.AbstractLocationProvider.State;
import com.android.server.location.CallerIdentity.PermissionLevel;
import com.android.server.location.LocationRequestStatistics.PackageProviderKey;
import com.android.server.location.LocationRequestStatistics.PackageStatistics;
-import com.android.server.location.UserInfoHelper.UserListener;
+import com.android.server.location.UserInfoHelper.UserListener.UserChange;
import com.android.server.location.gnss.GnssManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
@@ -132,11 +136,13 @@ public class LocationManagerService extends ILocationManager.Stub {
*/
public static class Lifecycle extends SystemService {
+ private final UserInfoHelper mUserInfoHelper;
private final LocationManagerService mService;
public Lifecycle(Context context) {
super(context);
- mService = new LocationManagerService(context);
+ mUserInfoHelper = new SystemUserInfoHelper(context);
+ mService = new LocationManagerService(context, mUserInfoHelper);
}
@Override
@@ -161,6 +167,29 @@ public class LocationManagerService extends ILocationManager.Stub {
mService.onSystemThirdPartyAppsCanStart();
}
}
+
+ @Override
+ public void onUserStarting(TargetUser user) {
+ mUserInfoHelper.dispatchOnUserStarted(user.getUserIdentifier());
+ }
+
+ @Override
+ public void onUserSwitching(TargetUser from, TargetUser to) {
+ mUserInfoHelper.dispatchOnCurrentUserChanged(from.getUserIdentifier(),
+ to.getUserIdentifier());
+ }
+
+ @Override
+ public void onUserStopped(TargetUser user) {
+ mUserInfoHelper.dispatchOnUserStopped(user.getUserIdentifier());
+ }
+
+ private static class SystemUserInfoHelper extends UserInfoHelper {
+
+ SystemUserInfoHelper(Context context) {
+ super(context);
+ }
+ }
}
public static final String TAG = "LocationManagerService";
@@ -232,7 +261,7 @@ public class LocationManagerService extends ILocationManager.Stub {
@PowerManager.LocationPowerSaveMode
private int mBatterySaverMode;
- private LocationManagerService(Context context) {
+ private LocationManagerService(Context context, UserInfoHelper userInfoHelper) {
mContext = context.createAttributionContext(ATTRIBUTION_TAG);
mHandler = FgThread.getHandler();
mLocalService = new LocalService();
@@ -240,7 +269,7 @@ public class LocationManagerService extends ILocationManager.Stub {
LocalServices.addService(LocationManagerInternal.class, mLocalService);
mAppOpsHelper = new AppOpsHelper(mContext);
- mUserInfoHelper = new UserInfoHelper(mContext);
+ mUserInfoHelper = userInfoHelper;
mSettingsHelper = new SettingsHelper(mContext, mHandler);
mAppForegroundHelper = new AppForegroundHelper(mContext);
mLocationUsageLogger = new LocationUsageLogger();
@@ -342,7 +371,7 @@ public class LocationManagerService extends ILocationManager.Stub {
// initialize the current users. we would get the user started notifications for these
// users eventually anyways, but this takes care of it as early as possible.
for (int userId: mUserInfoHelper.getCurrentUserIds()) {
- onUserChanged(userId, UserListener.USER_STARTED);
+ onUserChanged(userId, USER_STARTED);
}
}
}
@@ -596,32 +625,23 @@ public class LocationManagerService extends ILocationManager.Stub {
}
}
- private void onUserChanged(@UserIdInt int userId, @UserListener.UserChange int change) {
+ private void onUserChanged(@UserIdInt int userId, @UserChange int change) {
switch (change) {
- case UserListener.USER_SWITCHED:
- if (D) {
- Log.d(TAG, "user " + userId + " current status changed");
- }
+ case CURRENT_USER_CHANGED:
synchronized (mLock) {
for (LocationProviderManager manager : mProviderManagers) {
manager.onEnabledChangedLocked(userId);
}
}
break;
- case UserListener.USER_STARTED:
- if (D) {
- Log.d(TAG, "user " + userId + " started");
- }
+ case USER_STARTED:
synchronized (mLock) {
for (LocationProviderManager manager : mProviderManagers) {
manager.onUserStarted(userId);
}
}
break;
- case UserListener.USER_STOPPED:
- if (D) {
- Log.d(TAG, "user " + userId + " stopped");
- }
+ case USER_STOPPED:
synchronized (mLock) {
for (LocationProviderManager manager : mProviderManagers) {
manager.onUserStopped(userId);
@@ -957,10 +977,22 @@ public class LocationManagerService extends ILocationManager.Stub {
pw.increaseIndent();
// for now we only dump for the parent user
- int userId = mUserInfoHelper.getCurrentUserIds()[0];
- pw.println("last location=" + mLastLocation.get(userId));
- pw.println("last coarse location=" + mLastCoarseLocation.get(userId));
- pw.println("enabled=" + isEnabled(userId));
+ int[] userIds = mUserInfoHelper.getCurrentUserIds();
+ if (userIds.length == 1) {
+ int userId = userIds[0];
+ pw.println("last location=" + mLastLocation.get(userId));
+ pw.println("last coarse location=" + mLastCoarseLocation.get(userId));
+ pw.println("enabled=" + isEnabled(userId));
+ } else {
+ for (int userId : userIds) {
+ pw.println("user " + userId + ":");
+ pw.increaseIndent();
+ pw.println("last location=" + mLastLocation.get(userId));
+ pw.println("last coarse location=" + mLastCoarseLocation.get(userId));
+ pw.println("enabled=" + isEnabled(userId));
+ pw.decreaseIndent();
+ }
+ }
}
mProvider.dump(fd, pw, args);
@@ -1666,6 +1698,9 @@ public class LocationManagerService extends ILocationManager.Stub {
* Note: must be constructed with lock held.
*/
private UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
mExpirationRealtimeMs = request.getExpirationRealtimeMs(SystemClock.elapsedRealtime());
mProvider = provider;
mRealRequest = request;
@@ -1703,6 +1738,10 @@ public class LocationManagerService extends ILocationManager.Stub {
* Method to be called when a record will no longer be used.
*/
private void disposeLocked(boolean removeReceiver) {
+ if (Build.IS_DEBUGGABLE) {
+ Preconditions.checkState(Thread.holdsLock(mLock));
+ }
+
CallerIdentity identity = mReceiver.mCallerIdentity;
mRequestStatistics.stopRequesting(identity.packageName, identity.featureId, mProvider);
diff --git a/services/core/java/com/android/server/location/UserInfoHelper.java b/services/core/java/com/android/server/location/UserInfoHelper.java
index a3dcc40bdf2d..53bff8eacb4c 100644
--- a/services/core/java/com/android/server/location/UserInfoHelper.java
+++ b/services/core/java/com/android/server/location/UserInfoHelper.java
@@ -20,48 +20,48 @@ import static android.os.UserManager.DISALLOW_SHARE_LOCATION;
import static com.android.server.location.LocationManagerService.D;
import static com.android.server.location.LocationManagerService.TAG;
+import static com.android.server.location.UserInfoHelper.UserListener.CURRENT_USER_CHANGED;
+import static com.android.server.location.UserInfoHelper.UserListener.USER_STARTED;
+import static com.android.server.location.UserInfoHelper.UserListener.USER_STOPPED;
+import android.annotation.CallSuper;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.app.ActivityManager;
-import android.content.BroadcastReceiver;
+import android.app.ActivityManagerInternal;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.os.Binder;
-import android.os.Build;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
-import com.android.server.FgThread;
+import com.android.server.LocalServices;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
+import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Provides accessors and listeners for all user info.
*/
-public class UserInfoHelper {
+public abstract class UserInfoHelper {
/**
* Listener for current user changes.
*/
public interface UserListener {
- int USER_SWITCHED = 1;
+ int CURRENT_USER_CHANGED = 1;
int USER_STARTED = 2;
int USER_STOPPED = 3;
- @IntDef({USER_SWITCHED, USER_STARTED, USER_STOPPED})
+ @IntDef({CURRENT_USER_CHANGED, USER_STARTED, USER_STOPPED})
@Retention(RetentionPolicy.SOURCE)
@interface UserChange {}
@@ -75,143 +75,101 @@ public class UserInfoHelper {
private final CopyOnWriteArrayList<UserListener> mListeners;
@GuardedBy("this")
- @Nullable private UserManager mUserManager;
-
- @UserIdInt private volatile int mCurrentUserId;
-
+ @Nullable private ActivityManagerInternal mActivityManagerInternal;
@GuardedBy("this")
- @UserIdInt private int mCachedParentUserId;
- @GuardedBy("this")
- private int[] mCachedProfileUserIds;
+ @Nullable private UserManager mUserManager;
public UserInfoHelper(Context context) {
mContext = context;
mListeners = new CopyOnWriteArrayList<>();
-
- mCurrentUserId = UserHandle.USER_NULL;
- mCachedParentUserId = UserHandle.USER_NULL;
- mCachedProfileUserIds = new int[]{UserHandle.USER_NULL};
}
/** Called when system is ready. */
+ @CallSuper
public synchronized void onSystemReady() {
- if (mUserManager != null) {
+ if (mActivityManagerInternal != null) {
return;
}
+ mActivityManagerInternal = Objects.requireNonNull(
+ LocalServices.getService(ActivityManagerInternal.class));
mUserManager = mContext.getSystemService(UserManager.class);
-
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
- intentFilter.addAction(Intent.ACTION_USER_STARTED);
- intentFilter.addAction(Intent.ACTION_USER_STOPPED);
- intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
- intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
-
- mContext.registerReceiverAsUser(new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action == null) {
- return;
- }
- int userId;
- switch (action) {
- case Intent.ACTION_USER_SWITCHED:
- userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
- if (userId != UserHandle.USER_NULL) {
- onCurrentUserChanged(userId);
- }
- break;
- case Intent.ACTION_USER_STARTED:
- userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
- if (userId != UserHandle.USER_NULL) {
- onUserStarted(userId);
- }
- break;
- case Intent.ACTION_USER_STOPPED:
- userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
- if (userId != UserHandle.USER_NULL) {
- onUserStopped(userId);
- }
- break;
- case Intent.ACTION_MANAGED_PROFILE_ADDED:
- case Intent.ACTION_MANAGED_PROFILE_REMOVED:
- onUserProfilesChanged();
- break;
- }
- }
- }, UserHandle.ALL, intentFilter, null, FgThread.getHandler());
-
- mCurrentUserId = ActivityManager.getCurrentUser();
}
/**
* Adds a listener for user changed events. Callbacks occur on an unspecified thread.
*/
- public void addListener(UserListener listener) {
+ public final void addListener(UserListener listener) {
mListeners.add(listener);
}
/**
* Removes a listener for user changed events.
*/
- public void removeListener(UserListener listener) {
+ public final void removeListener(UserListener listener) {
mListeners.remove(listener);
}
- private void onCurrentUserChanged(@UserIdInt int newUserId) {
- if (newUserId == mCurrentUserId) {
- return;
- }
-
+ protected void dispatchOnUserStarted(@UserIdInt int userId) {
if (D) {
- Log.d(TAG, "current user switched from u" + mCurrentUserId + " to u" + newUserId);
+ Log.d(TAG, "u" + userId + " started");
}
- int oldUserId = mCurrentUserId;
- mCurrentUserId = newUserId;
-
- onUserChanged(oldUserId, UserListener.USER_SWITCHED);
- onUserChanged(newUserId, UserListener.USER_SWITCHED);
+ for (UserListener listener : mListeners) {
+ listener.onUserChanged(userId, USER_STARTED);
+ }
}
- private void onUserStarted(@UserIdInt int userId) {
+ protected void dispatchOnUserStopped(@UserIdInt int userId) {
if (D) {
- Log.d(TAG, "u" + userId + " started");
+ Log.d(TAG, "u" + userId + " stopped");
}
- onUserChanged(userId, UserListener.USER_STARTED);
+ for (UserListener listener : mListeners) {
+ listener.onUserChanged(userId, USER_STOPPED);
+ }
}
- private void onUserStopped(@UserIdInt int userId) {
+ protected void dispatchOnCurrentUserChanged(@UserIdInt int fromUserId,
+ @UserIdInt int toUserId) {
+ int[] fromUserIds = getProfileIds(fromUserId);
+ int[] toUserIds = getProfileIds(toUserId);
if (D) {
- Log.d(TAG, "u" + userId + " stopped");
+ Log.d(TAG, "current user changed from u" + Arrays.toString(fromUserIds) + " to u"
+ + Arrays.toString(toUserIds));
}
- onUserChanged(userId, UserListener.USER_STOPPED);
- }
-
- private void onUserChanged(@UserIdInt int userId, @UserListener.UserChange int change) {
for (UserListener listener : mListeners) {
- listener.onUserChanged(userId, change);
+ for (int userId : fromUserIds) {
+ listener.onUserChanged(userId, CURRENT_USER_CHANGED);
+ }
}
- }
- private synchronized void onUserProfilesChanged() {
- // this intent is only sent to the current user
- if (mCachedParentUserId == mCurrentUserId) {
- mCachedParentUserId = UserHandle.USER_NULL;
- mCachedProfileUserIds = new int[]{UserHandle.USER_NULL};
+ for (UserListener listener : mListeners) {
+ for (int userId : toUserIds) {
+ listener.onUserChanged(userId, CURRENT_USER_CHANGED);
+ }
}
}
/**
* Returns an array of current user ids. This will always include the current user, and will
- * also include any profiles of the current user.
+ * also include any profiles of the current user. The caller must never mutate the returned
+ * array.
*/
public int[] getCurrentUserIds() {
- return getProfileUserIdsForParentUser(mCurrentUserId);
+ synchronized (this) {
+ if (mActivityManagerInternal == null) {
+ return new int[] {};
+ }
+ }
+
+ long identity = Binder.clearCallingIdentity();
+ try {
+ return mActivityManagerInternal.getCurrentProfileIds();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
/**
@@ -219,54 +177,47 @@ public class UserInfoHelper {
* user.
*/
public boolean isCurrentUserId(@UserIdInt int userId) {
- int currentUserId = mCurrentUserId;
- return userId == currentUserId || ArrayUtils.contains(
- getProfileUserIdsForParentUser(currentUserId), userId);
- }
+ synchronized (this) {
+ if (mActivityManagerInternal == null) {
+ return false;
+ }
+ }
- @GuardedBy("this")
- private synchronized int[] getProfileUserIdsForParentUser(@UserIdInt int parentUserId) {
- if (parentUserId != mCachedParentUserId) {
- long identity = Binder.clearCallingIdentity();
- try {
- Preconditions.checkState(mUserManager != null);
-
- // more expensive check - check that argument really is a parent user id
- if (Build.IS_DEBUGGABLE) {
- Preconditions.checkArgument(
- mUserManager.getProfileParent(parentUserId) == null);
- }
+ long identity = Binder.clearCallingIdentity();
+ try {
+ return mActivityManagerInternal.isCurrentProfile(userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
- mCachedParentUserId = parentUserId;
- mCachedProfileUserIds = mUserManager.getProfileIdsWithDisabled(parentUserId);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ private int[] getProfileIds(@UserIdInt int userId) {
+ synchronized (this) {
+ Preconditions.checkState(mUserManager != null);
}
- return mCachedProfileUserIds;
+ long identity = Binder.clearCallingIdentity();
+ try {
+ return mUserManager.getEnabledProfileIds(userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
/**
* Dump info for debugging.
*/
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- boolean systemRunning;
- synchronized (this) {
- systemRunning = mUserManager != null;
- }
-
- if (systemRunning) {
- int[] currentUserIds = getProfileUserIdsForParentUser(mCurrentUserId);
- pw.println("current users: " + Arrays.toString(currentUserIds));
- for (int userId : currentUserIds) {
- if (mUserManager.hasUserRestrictionForUser(DISALLOW_SHARE_LOCATION,
+ int[] currentUserProfiles = getCurrentUserIds();
+ pw.println("current users: " + Arrays.toString(currentUserProfiles));
+ UserManager userManager = mContext.getSystemService(UserManager.class);
+ if (userManager != null) {
+ for (int userId : currentUserProfiles) {
+ if (userManager.hasUserRestrictionForUser(DISALLOW_SHARE_LOCATION,
UserHandle.of(userId))) {
pw.println(" u" + userId + " restricted");
}
}
- } else {
- pw.println("current user: " + mCurrentUserId);
}
}
}
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index 53205add0b38..d6b98e2de901 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -44,7 +44,6 @@ import java.util.Objects;
/**
* Maintains a connection to a particular {@link MediaRoute2ProviderService}.
*/
-// TODO: Need to revisit the bind/unbind/connect/disconnect logic in this class.
final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
implements ServiceConnection {
private static final String TAG = "MR2ProviderSvcProxy";
@@ -265,8 +264,6 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider
if (DEBUG) {
Slog.d(TAG, this + ": Service binding died");
}
- // TODO: Investigate whether it tries to bind endlessly when the service is
- // badly implemented.
if (shouldBind()) {
unbind();
bind();
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index c65800a17f82..75a89a213052 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -1026,7 +1026,8 @@ class MediaRouter2ServiceImpl {
mHandler = new UserHandler(MediaRouter2ServiceImpl.this, this);
}
- // TODO: This assumes that only one router exists in a package. Is it true?
+ // TODO: This assumes that only one router exists in a package.
+ // Do this in Android S or later.
RouterRecord findRouterRecordLocked(String packageName) {
for (RouterRecord routerRecord : mRouterRecords) {
if (TextUtils.equals(routerRecord.mPackageName, packageName)) {
@@ -1121,7 +1122,6 @@ class MediaRouter2ServiceImpl {
private final UserRecord mUserRecord;
private final MediaRoute2ProviderWatcher mWatcher;
- //TODO: Make this thread-safe.
private final SystemMediaRoute2Provider mSystemProvider;
private final ArrayList<MediaRoute2Provider> mRouteProviders =
new ArrayList<>();
@@ -1153,7 +1153,6 @@ class MediaRouter2ServiceImpl {
private void stop() {
if (mRunning) {
mRunning = false;
- //TODO: may unselect routes
mWatcher.stop(); // also stops all providers
}
}
@@ -1386,7 +1385,6 @@ class MediaRouter2ServiceImpl {
final String providerId = route.getProviderId();
final MediaRoute2Provider provider = findProvider(providerId);
- // TODO: Remove this null check when the mMediaProviders are referenced only in handler.
if (provider == null) {
return;
}
@@ -1405,7 +1403,6 @@ class MediaRouter2ServiceImpl {
final String providerId = route.getProviderId();
final MediaRoute2Provider provider = findProvider(providerId);
- // TODO: Remove this null check when the mMediaProviders are referenced only in handler.
if (provider == null) {
return;
}
@@ -1425,7 +1422,6 @@ class MediaRouter2ServiceImpl {
final String providerId = route.getProviderId();
final MediaRoute2Provider provider = findProvider(providerId);
- // TODO: Remove this null check when the mMediaProviders are referenced only in handler.
if (provider == null) {
return;
}
@@ -1641,8 +1637,8 @@ class MediaRouter2ServiceImpl {
// TODO: Notify router too when the related callback is introduced.
}
- // TODO: Find a way to prevent providers from notifying error on random uniqueRequestId.
- // Solutions can be:
+ // TODO(b/157873556): Find a way to prevent providers from notifying error on random reqID.
+ // Possible solutions can be:
// 1) Record the other type of requests too (not only session creation request)
// 2) Throw exception on providers when they try to notify error on
// random uniqueRequestId.
diff --git a/services/core/java/com/android/server/notification/BadgeExtractor.java b/services/core/java/com/android/server/notification/BadgeExtractor.java
index af8baa50d501..d323d8095525 100644
--- a/services/core/java/com/android/server/notification/BadgeExtractor.java
+++ b/services/core/java/com/android/server/notification/BadgeExtractor.java
@@ -19,6 +19,7 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
import android.content.Context;
import android.util.Slog;
+import android.app.Notification;
/**
* Determines whether a badge should be shown for this notification
@@ -61,6 +62,10 @@ public class BadgeExtractor implements NotificationSignalExtractor {
record.setShowBadge(false);
}
+ Notification.BubbleMetadata metadata = record.getNotification().getBubbleMetadata();
+ if (metadata != null && metadata.isNotificationSuppressed()) {
+ record.setShowBadge(false);
+ }
return null;
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6ae58ec7feea..a95dc3035200 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -246,6 +246,7 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
+import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
@@ -1952,7 +1953,8 @@ public class NotificationManagerService extends SystemService {
mRankingHandler,
mZenModeHelper,
new NotificationChannelLoggerImpl(),
- mAppOps);
+ mAppOps,
+ new SysUiStatsEvent.BuilderFactory());
mRankingHelper = new RankingHelper(getContext(),
mRankingHandler,
mPreferencesHelper,
@@ -2172,19 +2174,19 @@ public class NotificationManagerService extends SystemService {
mStatsManager.setPullAtomCallback(
PACKAGE_NOTIFICATION_PREFERENCES,
null, // use default PullAtomMetadata values
- BackgroundThread.getExecutor(),
+ ConcurrentUtils.DIRECT_EXECUTOR,
mPullAtomCallback
);
mStatsManager.setPullAtomCallback(
PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES,
null, // use default PullAtomMetadata values
- BackgroundThread.getExecutor(),
+ ConcurrentUtils.DIRECT_EXECUTOR,
mPullAtomCallback
);
mStatsManager.setPullAtomCallback(
PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES,
null, // use default PullAtomMetadata values
- BackgroundThread.getExecutor(),
+ ConcurrentUtils.DIRECT_EXECUTOR,
mPullAtomCallback
);
}
@@ -6802,9 +6804,13 @@ public class NotificationManagerService extends SystemService {
boolean hasValidVibrate = false;
boolean hasValidSound = false;
boolean sentAccessibilityEvent = false;
- // If the notification will appear in the status bar, it should send an accessibility
- // event
- if (!record.isUpdate && record.getImportance() > IMPORTANCE_MIN) {
+
+ // If the notification will appear in the status bar, it should send an accessibility event
+ final boolean suppressedByDnd = record.isIntercepted()
+ && (record.getSuppressedVisualEffects() & SUPPRESSED_EFFECT_STATUS_BAR) != 0;
+ if (!record.isUpdate
+ && record.getImportance() > IMPORTANCE_MIN
+ && !suppressedByDnd) {
sendAccessibilityEvent(notification, record.getSbn().getPackageName());
sentAccessibilityEvent = true;
}
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 77b030f9ed0d..e472e3097777 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -140,6 +140,7 @@ public class PreferencesHelper implements RankingConfig {
* fields.
*/
private static final int DEFAULT_LOCKED_APP_FIELDS = 0;
+ private final SysUiStatsEvent.BuilderFactory mStatsEventBuilderFactory;
/**
* All user-lockable fields for a given application.
@@ -171,13 +172,15 @@ public class PreferencesHelper implements RankingConfig {
public PreferencesHelper(Context context, PackageManager pm, RankingHandler rankingHandler,
ZenModeHelper zenHelper, NotificationChannelLogger notificationChannelLogger,
- AppOpsManager appOpsManager) {
+ AppOpsManager appOpsManager,
+ SysUiStatsEvent.BuilderFactory statsEventBuilderFactory) {
mContext = context;
mZenModeHelper = zenHelper;
mRankingHandler = rankingHandler;
mPm = pm;
mNotificationChannelLogger = notificationChannelLogger;
mAppOps = appOpsManager;
+ mStatsEventBuilderFactory = statsEventBuilderFactory;
updateBadgingEnabled();
updateBubblesEnabled();
@@ -1898,7 +1901,7 @@ public class PreferencesHelper implements RankingConfig {
if (i > NOTIFICATION_PREFERENCES_PULL_LIMIT) {
break;
}
- StatsEvent.Builder event = StatsEvent.newBuilder()
+ SysUiStatsEvent.Builder event = mStatsEventBuilderFactory.newBuilder()
.setAtomId(PACKAGE_NOTIFICATION_PREFERENCES);
final PackagePreferences r = mPackagePreferences.valueAt(i);
event.writeInt(r.uid);
@@ -1927,7 +1930,7 @@ public class PreferencesHelper implements RankingConfig {
if (++totalChannelsPulled > NOTIFICATION_CHANNEL_PULL_LIMIT) {
break;
}
- StatsEvent.Builder event = StatsEvent.newBuilder()
+ SysUiStatsEvent.Builder event = mStatsEventBuilderFactory.newBuilder()
.setAtomId(PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES);
event.writeInt(r.uid);
event.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
@@ -1962,7 +1965,7 @@ public class PreferencesHelper implements RankingConfig {
if (++totalGroupsPulled > NOTIFICATION_CHANNEL_GROUP_PULL_LIMIT) {
break;
}
- StatsEvent.Builder event = StatsEvent.newBuilder()
+ SysUiStatsEvent.Builder event = mStatsEventBuilderFactory.newBuilder()
.setAtomId(PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES);
event.writeInt(r.uid);
event.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true);
diff --git a/services/core/java/com/android/server/notification/SysUiStatsEvent.java b/services/core/java/com/android/server/notification/SysUiStatsEvent.java
new file mode 100644
index 000000000000..9bc2346d4e96
--- /dev/null
+++ b/services/core/java/com/android/server/notification/SysUiStatsEvent.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+import android.util.StatsEvent;
+
+/**
+ * Wrapper for StatsEvent that enables unit testing.
+ */
+public class SysUiStatsEvent {
+
+ static class Builder {
+ private final StatsEvent.Builder mBuilder;
+
+ protected Builder(StatsEvent.Builder builder) {
+ mBuilder = builder;
+ }
+
+ public StatsEvent build() {
+ return mBuilder.build();
+ }
+
+ public Builder setAtomId(int atomId) {
+ mBuilder.setAtomId(atomId);
+ return this;
+ }
+
+ public Builder writeInt(int value) {
+ mBuilder.writeInt(value);
+ return this;
+ }
+
+ public Builder addBooleanAnnotation(byte annotation, boolean value) {
+ mBuilder.addBooleanAnnotation(annotation, value);
+ return this;
+ }
+
+ public Builder writeString(String value) {
+ mBuilder.writeString(value);
+ return this;
+ }
+
+ public Builder writeBoolean(boolean value) {
+ mBuilder.writeBoolean(value);
+ return this;
+ }
+ }
+
+ static class BuilderFactory {
+ Builder newBuilder() {
+ return new Builder(StatsEvent.newBuilder());
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index 59735ebb24d2..d6b1b27360ca 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -65,7 +65,7 @@ final class IdmapManager {
* modified.
*/
boolean createIdmap(@NonNull final PackageInfo targetPackage,
- @NonNull final PackageInfo overlayPackage, int additionalPolicies, int userId) {
+ @NonNull final PackageInfo overlayPackage, int userId) {
if (DEBUG) {
Slog.d(TAG, "create idmap for " + targetPackage.packageName + " and "
+ overlayPackage.packageName);
@@ -73,14 +73,13 @@ final class IdmapManager {
final String targetPath = targetPackage.applicationInfo.getBaseCodePath();
final String overlayPath = overlayPackage.applicationInfo.getBaseCodePath();
try {
+ int policies = calculateFulfilledPolicies(targetPackage, overlayPackage, userId);
boolean enforce = enforceOverlayable(overlayPackage);
- int policies = calculateFulfilledPolicies(targetPackage, overlayPackage, userId)
- | additionalPolicies;
if (mIdmapDaemon.verifyIdmap(targetPath, overlayPath, policies, enforce, userId)) {
return false;
}
- return mIdmapDaemon.createIdmap(targetPath, overlayPath, policies, enforce, userId)
- != null;
+ return mIdmapDaemon.createIdmap(targetPath, overlayPath, policies,
+ enforce, userId) != null;
} catch (Exception e) {
Slog.w(TAG, "failed to generate idmap for " + targetPath + " and "
+ overlayPath + ": " + e.getMessage());
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 3c5e47625fa2..396815399874 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -45,7 +45,6 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
import android.content.res.ApkAssets;
-import android.content.res.Resources;
import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
@@ -63,7 +62,6 @@ import android.util.AtomicFile;
import android.util.Slog;
import android.util.SparseArray;
-import com.android.internal.R;
import com.android.internal.content.om.OverlayConfig;
import com.android.server.FgThread;
import com.android.server.IoThread;
@@ -252,8 +250,7 @@ public final class OverlayManagerService extends SystemService {
mSettings = new OverlayManagerSettings();
mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
OverlayConfig.getSystemInstance(), getDefaultOverlayPackages(),
- new OverlayChangeListener(), getOverlayableConfigurator(),
- getOverlayableConfiguratorTargets());
+ new OverlayChangeListener());
mActorEnforcer = new OverlayActorEnforcer(mPackageManager);
final IntentFilter packageFilter = new IntentFilter();
@@ -336,28 +333,6 @@ public final class OverlayManagerService extends SystemService {
return defaultPackages.toArray(new String[defaultPackages.size()]);
}
-
- /**
- * Retrieves the package name that is recognized as an actor for the packages specified by
- * {@link #getOverlayableConfiguratorTargets()}.
- */
- @Nullable
- private String getOverlayableConfigurator() {
- return TextUtils.nullIfEmpty(Resources.getSystem()
- .getString(R.string.config_overlayableConfigurator));
- }
-
- /**
- * Retrieves the target packages that recognize the {@link #getOverlayableConfigurator} as an
- * actor for itself. Overlays targeting one of the specified targets that are signed with the
- * same signature as the overlayable configurator will be granted the "actor" policy.
- */
- @Nullable
- private String[] getOverlayableConfiguratorTargets() {
- return Resources.getSystem().getStringArray(
- R.array.config_overlayableConfiguratorTargets);
- }
-
private final class PackageReceiver extends BroadcastReceiver {
@Override
public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 879ad4fdf011..05a4a38feef1 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -31,7 +31,6 @@ import android.annotation.Nullable;
import android.content.om.OverlayInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
-import android.os.OverlayablePolicy;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -74,9 +73,6 @@ final class OverlayManagerServiceImpl {
private final String[] mDefaultOverlays;
private final OverlayChangeListener mListener;
- private final String mOverlayableConfigurator;
- private final String[] mOverlayableConfiguratorTargets;
-
/**
* Helper method to merge the overlay manager's (as read from overlays.xml)
* and package manager's (as parsed from AndroidManifest.xml files) views
@@ -119,17 +115,13 @@ final class OverlayManagerServiceImpl {
@NonNull final OverlayManagerSettings settings,
@NonNull final OverlayConfig overlayConfig,
@NonNull final String[] defaultOverlays,
- @NonNull final OverlayChangeListener listener,
- @Nullable final String overlayableConfigurator,
- @Nullable final String[] overlayableConfiguratorTargets) {
+ @NonNull final OverlayChangeListener listener) {
mPackageManager = packageManager;
mIdmapManager = idmapManager;
mSettings = settings;
mOverlayConfig = overlayConfig;
mDefaultOverlays = defaultOverlays;
mListener = listener;
- mOverlayableConfigurator = overlayableConfigurator;
- mOverlayableConfiguratorTargets = overlayableConfiguratorTargets;
}
/**
@@ -714,25 +706,7 @@ final class OverlayManagerServiceImpl {
if (targetPackage != null && overlayPackage != null
&& !("android".equals(targetPackageName)
&& !isPackageConfiguredMutable(overlayPackageName))) {
-
- int additionalPolicies = 0;
- if (TextUtils.nullIfEmpty(mOverlayableConfigurator) != null
- && ArrayUtils.contains(mOverlayableConfiguratorTargets, targetPackageName)
- && isPackageConfiguredMutable(overlayPackageName)
- && mPackageManager.signaturesMatching(mOverlayableConfigurator,
- overlayPackageName, userId)) {
- // The overlay targets a package that has the overlayable configurator configured as
- // its actor. The overlay and this actor are signed with the same signature, so
- // the overlay fulfills the actor policy.
- modified |= mSettings.setHasConfiguratorActorPolicy(overlayPackageName, userId,
- true);
- additionalPolicies |= OverlayablePolicy.ACTOR_SIGNATURE;
- } else if (mSettings.hasConfiguratorActorPolicy(overlayPackageName, userId)) {
- additionalPolicies |= OverlayablePolicy.ACTOR_SIGNATURE;
- }
-
- modified |= mIdmapManager.createIdmap(targetPackage, overlayPackage, additionalPolicies,
- userId);
+ modified |= mIdmapManager.createIdmap(targetPackage, overlayPackage, userId);
}
if (overlayPackage != null) {
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index f8226faf1336..3d520bf59068 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -73,7 +73,7 @@ final class OverlayManagerSettings {
remove(packageName, userId);
insert(new SettingsItem(packageName, userId, targetPackageName, targetOverlayableName,
baseCodePath, OverlayInfo.STATE_UNKNOWN, isEnabled, isMutable, priority,
- overlayCategory, false /* hasConfiguratorActorPolicy */));
+ overlayCategory));
}
/**
@@ -160,26 +160,6 @@ final class OverlayManagerSettings {
return mItems.get(idx).setState(state);
}
- boolean hasConfiguratorActorPolicy(@NonNull final String packageName, final int userId) {
- final int idx = select(packageName, userId);
- if (idx < 0) {
- throw new BadKeyException(packageName, userId);
- }
- return mItems.get(idx).hasConfiguratorActorPolicy();
- }
-
- /**
- * Returns true if the settings were modified, false if they remain the same.
- */
- boolean setHasConfiguratorActorPolicy(@NonNull final String packageName, final int userId,
- boolean hasPolicy) {
- final int idx = select(packageName, userId);
- if (idx < 0) {
- throw new BadKeyException(packageName, userId);
- }
- return mItems.get(idx).setHasConfiguratorActorPolicy(hasPolicy);
- }
-
List<OverlayInfo> getOverlaysForTarget(@NonNull final String targetPackageName,
final int userId) {
// Immutable RROs targeting "android" are loaded from AssetManager, and so they should be
@@ -343,17 +323,16 @@ final class OverlayManagerSettings {
pw.println(item.mPackageName + ":" + item.getUserId() + " {");
pw.increaseIndent();
- pw.println("mPackageName................: " + item.mPackageName);
- pw.println("mUserId.....................: " + item.getUserId());
- pw.println("mTargetPackageName..........: " + item.getTargetPackageName());
- pw.println("mTargetOverlayableName......: " + item.getTargetOverlayableName());
- pw.println("mBaseCodePath...............: " + item.getBaseCodePath());
- pw.println("mState......................: " + OverlayInfo.stateToString(item.getState()));
- pw.println("mIsEnabled..................: " + item.isEnabled());
- pw.println("mIsMutable..................: " + item.isMutable());
- pw.println("mPriority...................: " + item.mPriority);
- pw.println("mCategory...................: " + item.mCategory);
- pw.println("mHasConfiguratorActorPolicy.: " + item.hasConfiguratorActorPolicy());
+ pw.println("mPackageName...........: " + item.mPackageName);
+ pw.println("mUserId................: " + item.getUserId());
+ pw.println("mTargetPackageName.....: " + item.getTargetPackageName());
+ pw.println("mTargetOverlayableName.: " + item.getTargetOverlayableName());
+ pw.println("mBaseCodePath..........: " + item.getBaseCodePath());
+ pw.println("mState.................: " + OverlayInfo.stateToString(item.getState()));
+ pw.println("mIsEnabled.............: " + item.isEnabled());
+ pw.println("mIsMutable.............: " + item.isMutable());
+ pw.println("mPriority..............: " + item.mPriority);
+ pw.println("mCategory..............: " + item.mCategory);
pw.decreaseIndent();
pw.println("}");
@@ -392,9 +371,6 @@ final class OverlayManagerSettings {
case "category":
pw.println(item.mCategory);
break;
- case "hasconfiguratoractorpolicy":
- pw.println(item.mHasConfiguratorActorPolicy);
- break;
}
}
@@ -422,8 +398,6 @@ final class OverlayManagerSettings {
private static final String ATTR_CATEGORY = "category";
private static final String ATTR_USER_ID = "userId";
private static final String ATTR_VERSION = "version";
- private static final String ATTR_HAS_CONFIGURATOR_ACTOR_POLICY =
- "hasConfiguratorActorPolicy";
@VisibleForTesting
static final int CURRENT_VERSION = 4;
@@ -461,6 +435,10 @@ final class OverlayManagerSettings {
// Throw an exception which will cause the overlay file to be ignored
// and overwritten.
throw new XmlPullParserException("old version " + oldVersion + "; ignoring");
+ case 3:
+ // Upgrading from version 3 to 4 is not a breaking change so do not ignore the
+ // overlay file.
+ return;
default:
throw new XmlPullParserException("unrecognized version " + oldVersion);
}
@@ -480,12 +458,9 @@ final class OverlayManagerSettings {
final boolean isStatic = XmlUtils.readBooleanAttribute(parser, ATTR_IS_STATIC);
final int priority = XmlUtils.readIntAttribute(parser, ATTR_PRIORITY);
final String category = XmlUtils.readStringAttribute(parser, ATTR_CATEGORY);
- final boolean hasConfiguratorActorPolicy = XmlUtils.readBooleanAttribute(parser,
- ATTR_HAS_CONFIGURATOR_ACTOR_POLICY);
return new SettingsItem(packageName, userId, targetPackageName, targetOverlayableName,
- baseCodePath, state, isEnabled, !isStatic, priority, category,
- hasConfiguratorActorPolicy);
+ baseCodePath, state, isEnabled, !isStatic, priority, category);
}
public static void persist(@NonNull final ArrayList<SettingsItem> table,
@@ -520,8 +495,6 @@ final class OverlayManagerSettings {
XmlUtils.writeBooleanAttribute(xml, ATTR_IS_STATIC, !item.mIsMutable);
XmlUtils.writeIntAttribute(xml, ATTR_PRIORITY, item.mPriority);
XmlUtils.writeStringAttribute(xml, ATTR_CATEGORY, item.mCategory);
- XmlUtils.writeBooleanAttribute(xml, ATTR_HAS_CONFIGURATOR_ACTOR_POLICY,
- item.mHasConfiguratorActorPolicy);
xml.endTag(null, TAG_ITEM);
}
}
@@ -538,14 +511,12 @@ final class OverlayManagerSettings {
private boolean mIsMutable;
private int mPriority;
private String mCategory;
- private boolean mHasConfiguratorActorPolicy;
SettingsItem(@NonNull final String packageName, final int userId,
@NonNull final String targetPackageName,
@Nullable final String targetOverlayableName, @NonNull final String baseCodePath,
final @OverlayInfo.State int state, final boolean isEnabled,
- final boolean isMutable, final int priority, @Nullable String category,
- final boolean hasConfiguratorActorPolicy) {
+ final boolean isMutable, final int priority, @Nullable String category) {
mPackageName = packageName;
mUserId = userId;
mTargetPackageName = targetPackageName;
@@ -557,7 +528,6 @@ final class OverlayManagerSettings {
mCache = null;
mIsMutable = isMutable;
mPriority = priority;
- mHasConfiguratorActorPolicy = hasConfiguratorActorPolicy;
}
private String getTargetPackageName() {
@@ -648,18 +618,6 @@ final class OverlayManagerSettings {
private int getPriority() {
return mPriority;
}
-
- private boolean hasConfiguratorActorPolicy() {
- return mHasConfiguratorActorPolicy;
- }
-
- private boolean setHasConfiguratorActorPolicy(boolean hasPolicy) {
- if (mHasConfiguratorActorPolicy != hasPolicy) {
- mHasConfiguratorActorPolicy = hasPolicy;
- return true;
- }
- return false;
- }
}
private int select(@NonNull final String packageName, final int userId) {
diff --git a/services/core/java/com/android/server/pm/DataLoaderManagerService.java b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
index 81ee7d9eeef7..52fdc7983636 100644
--- a/services/core/java/com/android/server/pm/DataLoaderManagerService.java
+++ b/services/core/java/com/android/server/pm/DataLoaderManagerService.java
@@ -21,7 +21,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.content.pm.ApplicationInfo;
import android.content.pm.DataLoaderParamsParcel;
import android.content.pm.IDataLoader;
import android.content.pm.IDataLoaderManager;
@@ -122,19 +121,7 @@ public class DataLoaderManagerService extends SystemService {
ri.serviceInfo.packageName, ri.serviceInfo.name);
// There should only be one matching provider inside the given package.
// If there's more than one, return the first one found.
- try {
- ApplicationInfo ai = pm.getApplicationInfo(resolved.getPackageName(), 0);
- if (!ai.isPrivilegedApp()) {
- Slog.w(TAG,
- "Data loader: " + resolved + " is not a privileged app, skipping.");
- continue;
- }
- return resolved;
- } catch (PackageManager.NameNotFoundException ex) {
- Slog.w(TAG,
- "Privileged data loader: " + resolved + " not found, skipping.");
- }
-
+ return resolved;
}
Slog.e(TAG, "Didn't find any matching data loader service provider.");
return null;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 236a6816b3e3..f827721be3b7 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -40,6 +40,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageInstaller.SessionParams;
+import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.VersionedPackage;
@@ -126,8 +127,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS;
/** Automatically destroy staged sessions that have not changed state in this time */
private static final long MAX_TIME_SINCE_UPDATE_MILLIS = 7 * DateUtils.DAY_IN_MILLIS;
- /** Upper bound on number of active sessions for a UID */
- private static final long MAX_ACTIVE_SESSIONS = 1024;
+ /** Upper bound on number of active sessions for a UID that has INSTALL_PACKAGES */
+ private static final long MAX_ACTIVE_SESSIONS_WITH_PERMISSION = 1024;
+ /** Upper bound on number of active sessions for a UID without INSTALL_PACKAGES */
+ private static final long MAX_ACTIVE_SESSIONS_NO_PERMISSION = 50;
/** Upper bound on number of historical sessions for a UID */
private static final long MAX_HISTORICAL_SESSIONS = 1048576;
@@ -503,7 +506,18 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
+ "to use a data loader");
}
- String requestedInstallerPackageName = params.installerPackageName != null
+ // App package name and label length is restricted so that really long strings aren't
+ // written to disk.
+ if (params.appPackageName != null
+ && params.appPackageName.length() > SessionParams.MAX_PACKAGE_NAME_LENGTH) {
+ params.appPackageName = null;
+ }
+
+ params.appLabel = TextUtils.trimToSize(params.appLabel,
+ PackageItemInfo.MAX_SAFE_LABEL_LENGTH);
+
+ String requestedInstallerPackageName = (params.installerPackageName != null
+ && params.installerPackageName.length() < SessionParams.MAX_PACKAGE_NAME_LENGTH)
? params.installerPackageName : installerPackageName;
if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
@@ -635,12 +649,23 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
}
+ if (params.whitelistedRestrictedPermissions != null) {
+ mPermissionManager.retainHardAndSoftRestrictedPermissions(
+ params.whitelistedRestrictedPermissions);
+ }
+
final int sessionId;
final PackageInstallerSession session;
synchronized (mSessions) {
// Sanity check that installer isn't going crazy
final int activeCount = getSessionCount(mSessions, callingUid);
- if (activeCount >= MAX_ACTIVE_SESSIONS) {
+ if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
+ == PackageManager.PERMISSION_GRANTED) {
+ if (activeCount >= MAX_ACTIVE_SESSIONS_WITH_PERMISSION) {
+ throw new IllegalStateException(
+ "Too many active sessions for UID " + callingUid);
+ }
+ } else if (activeCount >= MAX_ACTIVE_SESSIONS_NO_PERMISSION) {
throw new IllegalStateException(
"Too many active sessions for UID " + callingUid);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index fd861b56b729..766fae64f647 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -148,6 +148,8 @@ import android.app.ResourcesManager;
import android.app.admin.IDevicePolicyManager;
import android.app.admin.SecurityLog;
import android.app.backup.IBackupManager;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -639,6 +641,19 @@ public class PackageManagerService extends IPackageManager.Stub
*/
private static final int DEFAULT_VERIFICATION_RESPONSE = PackageManager.VERIFICATION_ALLOW;
+ /**
+ * Adding an installer package name to a package that does not have one set requires the
+ * INSTALL_PACKAGES permission.
+ *
+ * If the caller targets R, this will throw a SecurityException. Otherwise the request will
+ * fail silently. In both cases, and regardless of whether this change is enabled, the
+ * installer package will remain unchanged.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
+ private static final long THROW_EXCEPTION_ON_REQUIRE_INSTALL_PACKAGES_TO_ADD_INSTALLER_PACKAGE =
+ 150857253;
+
public static final String PLATFORM_PACKAGE_NAME = "android";
private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
@@ -5264,15 +5279,17 @@ public class PackageManagerService extends IPackageManager.Stub
* </ul>
*/
int updateFlagsForResolve(int flags, int userId, int callingUid, boolean wantInstantApps,
- boolean matchSystemOnly) {
+ boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
return updateFlagsForResolve(flags, userId, callingUid,
- wantInstantApps, matchSystemOnly, false /*onlyExposedExplicitly*/);
+ wantInstantApps, false /*onlyExposedExplicitly*/,
+ isImplicitImageCaptureIntentAndNotSetByDpc);
}
int updateFlagsForResolve(int flags, int userId, int callingUid,
- boolean wantInstantApps, boolean onlyExposedExplicitly, boolean matchSystemOnly) {
+ boolean wantInstantApps, boolean onlyExposedExplicitly,
+ boolean isImplicitImageCaptureIntentAndNotSetByDpc) {
// Safe mode means we shouldn't match any third-party components
- if (mSafeMode || matchSystemOnly) {
+ if (mSafeMode || isImplicitImageCaptureIntentAndNotSetByDpc) {
flags |= PackageManager.MATCH_SYSTEM_ONLY;
}
if (getInstantAppPackageName(callingUid) != null) {
@@ -6400,7 +6417,8 @@ public class PackageManagerService extends IPackageManager.Stub
if (!mUserManager.exists(userId)) return null;
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart,
- intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+ flags));
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");
@@ -6438,7 +6456,7 @@ public class PackageManagerService extends IPackageManager.Stub
final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
final int flags = updateFlagsForResolve(
0, userId, callingUid, false /*includeInstantApps*/,
- intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType, 0));
final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags,
userId);
synchronized (mLock) {
@@ -6684,6 +6702,40 @@ public class PackageManagerService extends IPackageManager.Stub
return true;
}
+ /**
+ * From Android R, camera intents have to match system apps. The only exception to this is if
+ * the DPC has set the camera persistent preferred activity. This case was introduced
+ * because it is important that the DPC has the ability to set both system and non-system
+ * camera persistent preferred activities.
+ *
+ * @return {@code true} if the intent is a camera intent and the persistent preferred
+ * activity was not set by the DPC.
+ */
+ @GuardedBy("mLock")
+ private boolean isImplicitImageCaptureIntentAndNotSetByDpcLocked(Intent intent, int userId,
+ String resolvedType, int flags) {
+ return intent.isImplicitImageCaptureIntent() && !isPersistentPreferredActivitySetByDpm(
+ intent, userId, resolvedType, flags);
+ }
+
+ private boolean isPersistentPreferredActivitySetByDpm(Intent intent, int userId,
+ String resolvedType, int flags) {
+ PersistentPreferredIntentResolver ppir = mSettings.mPersistentPreferredActivities
+ .get(userId);
+ //TODO(b/158003772): Remove double query
+ List<PersistentPreferredActivity> pprefs = ppir != null
+ ? ppir.queryIntent(intent, resolvedType,
+ (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
+ userId)
+ : new ArrayList<>();
+ for (PersistentPreferredActivity ppa : pprefs) {
+ if (ppa.mIsSetByDpm) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@GuardedBy("mLock")
private ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType,
int flags, List<ResolveInfo> query, boolean debug, int userId) {
@@ -6767,7 +6819,8 @@ public class PackageManagerService extends IPackageManager.Stub
android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1;
flags = updateFlagsForResolve(
flags, userId, callingUid, false /*includeInstantApps*/,
- intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+ flags));
intent = updateIntentForResolve(intent);
// writer
synchronized (mLock) {
@@ -6980,7 +7033,8 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
int flags = updateFlagsForResolve(0, parent.id, callingUid,
false /*includeInstantApps*/,
- intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, parent.id,
+ resolvedType, 0));
CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr(
intent, resolvedType, flags, sourceUserId, parent.id);
return xpDomainInfo != null;
@@ -7067,7 +7121,8 @@ public class PackageManagerService extends IPackageManager.Stub
flags = updateFlagsForResolve(flags, userId, filterCallingUid, resolveForStart,
comp != null || pkgName != null /*onlyExposedExplicitly*/,
- intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+ flags));
if (comp != null) {
final List<ResolveInfo> list = new ArrayList<>(1);
final ActivityInfo ai = getActivityInfo(comp, flags, userId);
@@ -7856,7 +7911,8 @@ public class PackageManagerService extends IPackageManager.Stub
if (!mUserManager.exists(userId)) return Collections.emptyList();
final int callingUid = Binder.getCallingUid();
flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
- intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+ flags));
mPermissionManager.enforceCrossUserPermission(callingUid, userId,
false /*requireFullPermission*/, false /*checkShell*/,
"query intent activity options");
@@ -8043,7 +8099,8 @@ public class PackageManagerService extends IPackageManager.Stub
"query intent receivers");
final String instantAppPkgName = getInstantAppPackageName(callingUid);
flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
- intent.isImplicitImageCaptureIntent() /*matchSystemOnly*/);
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
+ flags));
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
@@ -8134,7 +8191,7 @@ public class PackageManagerService extends IPackageManager.Stub
int userId, int callingUid) {
if (!mUserManager.exists(userId)) return null;
flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
- false /* matchSystemOnly */);
+ false /* isImplicitImageCaptureIntentAndNotSetByDpc */);
List<ResolveInfo> query = queryIntentServicesInternal(
intent, resolvedType, flags, userId, callingUid, false /*includeInstantApps*/);
if (query != null) {
@@ -8166,7 +8223,7 @@ public class PackageManagerService extends IPackageManager.Stub
"query intent receivers");
final String instantAppPkgName = getInstantAppPackageName(callingUid);
flags = updateFlagsForResolve(flags, userId, callingUid, includeInstantApps,
- false /* matchSystemOnly */);
+ false /* isImplicitImageCaptureIntentAndNotSetByDpc */);
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
@@ -8304,7 +8361,7 @@ public class PackageManagerService extends IPackageManager.Stub
final int callingUid = Binder.getCallingUid();
final String instantAppPkgName = getInstantAppPackageName(callingUid);
flags = updateFlagsForResolve(flags, userId, callingUid, false /*includeInstantApps*/,
- false /* matchSystemOnly */);
+ false /* isImplicitImageCaptureIntentAndNotSetByDpc */);
ComponentName comp = intent.getComponent();
if (comp == null) {
if (intent.getSelector() != null) {
@@ -13451,7 +13508,7 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
for (String packageName : packagesToChange) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps.getSuspended(userId)) {
+ if (ps != null && ps.getSuspended(userId)) {
ps.removeSuspension(suspendingPackagePredicate, userId);
if (!ps.getSuspended(userId)) {
unsuspendedPackages.add(ps.name);
@@ -13492,7 +13549,7 @@ public class PackageManagerService extends IPackageManager.Stub
synchronized (mLock) {
for (String packageName : packagesToChange) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps.getDistractionFlags(userId) != 0) {
+ if (ps != null && ps.getDistractionFlags(userId) != 0) {
ps.setDistractionFlags(0, userId);
changedPackages.add(ps.name);
changedUids.add(UserHandle.getUid(userId, ps.getAppId()));
@@ -14130,19 +14187,38 @@ public class PackageManagerService extends IPackageManager.Stub
// be signed with the same cert as the caller.
String targetInstallerPackageName =
targetPackageSetting.installSource.installerPackageName;
- if (targetInstallerPackageName != null) {
- PackageSetting setting = mSettings.mPackages.get(
- targetInstallerPackageName);
- // If the currently set package isn't valid, then it's always
- // okay to change it.
- if (setting != null) {
- if (compareSignatures(callerSignature,
- setting.signatures.mSigningDetails.signatures)
- != PackageManager.SIGNATURE_MATCH) {
- throw new SecurityException(
- "Caller does not have same cert as old installer package "
- + targetInstallerPackageName);
+ PackageSetting targetInstallerPkgSetting = targetInstallerPackageName == null ? null :
+ mSettings.mPackages.get(targetInstallerPackageName);
+
+ if (targetInstallerPkgSetting != null) {
+ if (compareSignatures(callerSignature,
+ targetInstallerPkgSetting.signatures.mSigningDetails.signatures)
+ != PackageManager.SIGNATURE_MATCH) {
+ throw new SecurityException(
+ "Caller does not have same cert as old installer package "
+ + targetInstallerPackageName);
+ }
+ } else if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES)
+ != PackageManager.PERMISSION_GRANTED) {
+ // This is probably an attempt to exploit vulnerability b/150857253 of taking
+ // privileged installer permissions when the installer has been uninstalled or
+ // was never set.
+ EventLog.writeEvent(0x534e4554, "150857253", callingUid, "");
+
+ long binderToken = Binder.clearCallingIdentity();
+ try {
+ if (mInjector.getCompatibility().isChangeEnabledByUid(
+ THROW_EXCEPTION_ON_REQUIRE_INSTALL_PACKAGES_TO_ADD_INSTALLER_PACKAGE,
+ callingUid)) {
+ throw new SecurityException("Neither user " + callingUid
+ + " nor current process has "
+ + Manifest.permission.INSTALL_PACKAGES);
+ } else {
+ // If change disabled, fail silently for backwards compatibility
+ return;
}
+ } finally {
+ Binder.restoreCallingIdentity(binderToken);
}
}
@@ -18884,6 +18960,7 @@ public class PackageManagerService extends IPackageManager.Stub
int userId) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DELETE_PACKAGES, null);
+ // TODO (b/157774108): This should fail on non-existent packages.
synchronized (mLock) {
// Cannot block uninstall of static shared libs as they are
// considered a part of the using app (emulating static linking).
@@ -19839,7 +19916,7 @@ public class PackageManagerService extends IPackageManager.Stub
}
synchronized (mLock) {
mSettings.editPersistentPreferredActivitiesLPw(userId).addFilter(
- new PersistentPreferredActivity(filter, activity));
+ new PersistentPreferredActivity(filter, activity, true));
scheduleWritePackageRestrictionsLocked(userId);
}
updateDefaultHomeNotLocked(userId);
diff --git a/services/core/java/com/android/server/pm/PersistentPreferredActivity.java b/services/core/java/com/android/server/pm/PersistentPreferredActivity.java
index 0d4cdf9dee53..5a6fd0923f53 100644
--- a/services/core/java/com/android/server/pm/PersistentPreferredActivity.java
+++ b/services/core/java/com/android/server/pm/PersistentPreferredActivity.java
@@ -16,31 +16,34 @@
package com.android.server.pm;
+import android.content.ComponentName;
+import android.content.IntentFilter;
+import android.util.Log;
+
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
-import android.content.ComponentName;
-import android.content.IntentFilter;
-import android.util.Log;
-
import java.io.IOException;
class PersistentPreferredActivity extends IntentFilter {
private static final String ATTR_NAME = "name"; // component name
private static final String ATTR_FILTER = "filter"; // filter
+ private static final String ATTR_SET_BY_DPM = "set-by-dpm"; // set by DPM
private static final String TAG = "PersistentPreferredActivity";
private static final boolean DEBUG_FILTERS = false;
final ComponentName mComponent;
+ final boolean mIsSetByDpm;
- PersistentPreferredActivity(IntentFilter filter, ComponentName activity) {
+ PersistentPreferredActivity(IntentFilter filter, ComponentName activity, boolean isSetByDpm) {
super(filter);
mComponent = activity;
+ mIsSetByDpm = isSetByDpm;
}
PersistentPreferredActivity(XmlPullParser parser) throws XmlPullParserException, IOException {
@@ -52,6 +55,8 @@ class PersistentPreferredActivity extends IntentFilter {
"Bad activity name " + shortComponent +
" at " + parser.getPositionDescription());
}
+ mIsSetByDpm = Boolean.parseBoolean(parser.getAttributeValue(null, ATTR_SET_BY_DPM));
+
int outerDepth = parser.getDepth();
String tagName = parser.getName();
int type;
@@ -83,6 +88,7 @@ class PersistentPreferredActivity extends IntentFilter {
public void writeToXml(XmlSerializer serializer) throws IOException {
serializer.attribute(null, ATTR_NAME, mComponent.flattenToShortString());
+ serializer.attribute(null, ATTR_SET_BY_DPM, Boolean.toString(mIsSetByDpm));
serializer.startTag(null, ATTR_FILTER);
super.writeToXml(serializer);
serializer.endTag(null, ATTR_FILTER);
@@ -91,6 +97,7 @@ class PersistentPreferredActivity extends IntentFilter {
@Override
public String toString() {
return "PersistentPreferredActivity{0x" + Integer.toHexString(System.identityHashCode(this))
- + " " + mComponent.flattenToShortString() + "}";
+ + " " + mComponent.flattenToShortString()
+ + ", mIsSetByDpm=" + mIsSetByDpm + "}";
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 3ec139763e80..0c42ff6be520 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -2419,6 +2419,9 @@ public class ShortcutService extends IShortcutService.Stub {
@Override
public ParceledListSlice<ShortcutManager.ShareShortcutInfo> getShareTargets(String packageName,
IntentFilter filter, @UserIdInt int userId) {
+ Preconditions.checkStringNotEmpty(packageName, "packageName");
+ Objects.requireNonNull(filter, "intentFilter");
+
verifyCaller(packageName, userId);
enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APP_PREDICTIONS,
"getShareTargets");
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 79805e3b42ae..8ccf837f64dc 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -77,7 +77,11 @@ import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.rollback.WatchdogRollbackLogger;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -102,6 +106,9 @@ public class StagingManager {
private final PreRebootVerificationHandler mPreRebootVerificationHandler;
private final Supplier<PackageParser2> mPackageParserSupplier;
+ private final File mFailureReasonFile = new File("/metadata/staged-install/failure_reason.txt");
+ private String mFailureReason;
+
@GuardedBy("mStagedSessions")
private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();
@@ -125,6 +132,12 @@ public class StagingManager {
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mPreRebootVerificationHandler = new PreRebootVerificationHandler(
BackgroundThread.get().getLooper());
+
+ if (mFailureReasonFile.exists()) {
+ try (BufferedReader reader = new BufferedReader(new FileReader(mFailureReasonFile))) {
+ mFailureReason = reader.readLine();
+ } catch (Exception ignore) { }
+ }
}
/**
@@ -383,10 +396,19 @@ public class StagingManager {
}
// Reverts apex sessions and user data (if checkpoint is supported). Also reboots the device.
- private void abortCheckpoint(String errorMsg) {
- Slog.e(TAG, "Aborting checkpoint: " + errorMsg);
+ private void abortCheckpoint(int sessionId, String errorMsg) {
+ String failureReason = "Failed to install sessionId: " + sessionId + " Error: " + errorMsg;
+ Slog.e(TAG, failureReason);
try {
if (supportsCheckpoint() && needsCheckpoint()) {
+ // Store failure reason for next reboot
+ try (BufferedWriter writer =
+ new BufferedWriter(new FileWriter(mFailureReasonFile))) {
+ writer.write(failureReason);
+ } catch (Exception e) {
+ Slog.w(TAG, "Failed to save failure reason: ", e);
+ }
+
// Only revert apex sessions if device supports updating apex
if (mApexManager.isApexSupported()) {
mApexManager.revertActiveSessions();
@@ -592,14 +614,12 @@ public class StagingManager {
// If checkpoint is supported, then we only resume sessions if we are in checkpointing
// mode. If not, we fail all sessions.
if (supportsCheckpoint() && !needsCheckpoint()) {
- // TODO(b/146343545): Persist failure reason across checkpoint reboot
- Slog.d(TAG, "Reverting back to safe state. Marking " + session.sessionId
- + " as failed.");
- String errorMsg = "Reverting back to safe state";
- if (!TextUtils.isEmpty(mNativeFailureReason)) {
- errorMsg = "Entered fs-rollback mode and reverted session due to crashing "
- + "native process: " + mNativeFailureReason;
+ String errorMsg = "Reverting back to safe state. Marking " + session.sessionId
+ + " as failed";
+ if (!TextUtils.isEmpty(mFailureReason)) {
+ errorMsg = errorMsg + ": " + mFailureReason;
}
+ Slog.d(TAG, errorMsg);
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_UNKNOWN, errorMsg);
return;
}
@@ -624,7 +644,7 @@ public class StagingManager {
+ "supposed to be activated";
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
errorMsg);
- abortCheckpoint(errorMsg);
+ abortCheckpoint(session.sessionId, errorMsg);
return;
}
if (isApexSessionFailed(apexSessionInfo)) {
@@ -636,7 +656,7 @@ public class StagingManager {
}
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
errorMsg);
- abortCheckpoint(errorMsg);
+ abortCheckpoint(session.sessionId, errorMsg);
return;
}
if (!apexSessionInfo.isActivated && !apexSessionInfo.isSuccess) {
@@ -647,7 +667,7 @@ public class StagingManager {
+ "didn't activate nor fail. Marking it as failed anyway.";
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
errorMsg);
- abortCheckpoint(errorMsg);
+ abortCheckpoint(session.sessionId, errorMsg);
return;
}
}
@@ -664,7 +684,7 @@ public class StagingManager {
installApksInSession(session);
} catch (PackageManagerException e) {
session.setStagedSessionFailed(e.error, e.getMessage());
- abortCheckpoint(e.getMessage());
+ abortCheckpoint(session.sessionId, e.getMessage());
// If checkpoint is not supported, we have to handle failure for one staged session.
if (!hasApex) {
@@ -1189,6 +1209,8 @@ public class StagingManager {
ctx.unregisterReceiver(this);
}
}, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+
+ mFailureReasonFile.delete();
}
private static class LocalIntentReceiverAsync {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index b0e3ecb6d17b..40fa798309c1 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -491,6 +491,7 @@ public class UserManagerService extends IUserManager.Stub {
final SparseIntArray states;
public WatchedUserStates() {
states = new SparseIntArray();
+ invalidateIsUserUnlockedCache();
}
public int get(int userId) {
return states.get(userId);
@@ -2249,9 +2250,6 @@ public class UserManagerService extends IUserManager.Stub {
// Managed profiles have their own specific rules.
final boolean isManagedProfile = type.isManagedProfile();
if (isManagedProfile) {
- if (ActivityManager.isLowRamDeviceStatic()) {
- return false;
- }
if (!mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_MANAGED_USERS)) {
return false;
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 8f3bf39d4fc5..cd53fb9ba52f 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -816,7 +816,7 @@ public final class DefaultPermissionGrantPolicy {
if (!TextUtils.isEmpty(contentCapturePackageName)) {
grantPermissionsToSystemPackage(pm, contentCapturePackageName, userId,
PHONE_PERMISSIONS, SMS_PERMISSIONS, ALWAYS_LOCATION_PERMISSIONS,
- CONTACTS_PERMISSIONS, STORAGE_PERMISSIONS);
+ CONTACTS_PERMISSIONS);
}
// Atthention Service
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 b0d4d957fc21..d3f3ba1dc6bb 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -26,6 +26,7 @@ import static android.content.pm.ApplicationInfo.AUTO_REVOKE_DISCOURAGED;
import static android.content.pm.PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_DEFAULT;
+import static android.content.pm.PackageManager.FLAG_PERMISSION_GRANTED_BY_ROLE;
import static android.content.pm.PackageManager.FLAG_PERMISSION_ONE_TIME;
import static android.content.pm.PackageManager.FLAG_PERMISSION_POLICY_FIXED;
import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
@@ -1804,8 +1805,9 @@ public class PermissionManagerService extends IPermissionManager.Stub {
continue;
}
- // If this permission was granted by default, make sure it is.
- if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0) {
+ // If this permission was granted by default or role, make sure it is.
+ if ((oldFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0
+ || (oldFlags & FLAG_PERMISSION_GRANTED_BY_ROLE) != 0) {
// PermissionPolicyService will handle the app op for runtime permissions later.
grantRuntimePermissionInternal(permName, packageName, false,
Process.SYSTEM_UID, userId, delayingPermCallback);
@@ -4948,6 +4950,20 @@ public class PermissionManagerService extends IPermissionManager.Stub {
StorageManager.UUID_PRIVATE_INTERNAL, true, mDefaultPermissionCallback);
}
}
+
+ @Override
+ public void retainHardAndSoftRestrictedPermissions(@NonNull List<String> permissions) {
+ synchronized (mLock) {
+ Iterator<String> iterator = permissions.iterator();
+ while (iterator.hasNext()) {
+ String permission = iterator.next();
+ BasePermission basePermission = mSettings.mPermissions.get(permission);
+ if (basePermission == null || !basePermission.isHardOrSoftRestricted()) {
+ iterator.remove();
+ }
+ }
+ }
+ }
}
private static final class OnPermissionChangeListeners extends Handler {
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 57a25eddf7ce..4412162a5cc8 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -36,6 +36,7 @@ import java.util.function.Consumer;
* TODO: Should be merged into PermissionManagerInternal, but currently uses internal classes.
*/
public abstract class PermissionManagerServiceInternal extends PermissionManagerInternal {
+
/**
* Provider for package names.
*/
@@ -455,4 +456,10 @@ public abstract class PermissionManagerServiceInternal extends PermissionManager
/** Called when a new user has been created. */
public abstract void onNewUserCreated(@UserIdInt int userId);
+
+ /**
+ * Removes invalid permissions which are not {@link PermissionInfo#FLAG_HARD_RESTRICTED} or
+ * {@link PermissionInfo#FLAG_SOFT_RESTRICTED} from the input.
+ */
+ public abstract void retainHardAndSoftRestrictedPermissions(@NonNull List<String> permissions);
}
diff --git a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
index 49c781905898..2f963b7e6b35 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerModule.java
@@ -20,11 +20,16 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.hardware.soundtrigger.V2_1.ISoundTriggerHwCallback;
import android.hardware.soundtrigger.V2_2.ISoundTriggerHw;
+import android.media.audio.common.AudioConfig;
+import android.media.audio.common.AudioOffloadInfo;
import android.media.soundtrigger_middleware.ISoundTriggerCallback;
import android.media.soundtrigger_middleware.ISoundTriggerModule;
import android.media.soundtrigger_middleware.ModelParameterRange;
+import android.media.soundtrigger_middleware.PhraseRecognitionEvent;
+import android.media.soundtrigger_middleware.PhraseRecognitionExtra;
import android.media.soundtrigger_middleware.PhraseSoundModel;
import android.media.soundtrigger_middleware.RecognitionConfig;
+import android.media.soundtrigger_middleware.RecognitionEvent;
import android.media.soundtrigger_middleware.SoundModel;
import android.media.soundtrigger_middleware.SoundModelType;
import android.media.soundtrigger_middleware.SoundTriggerModuleProperties;
@@ -540,20 +545,20 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient {
switch (mModelType) {
case SoundModelType.GENERIC: {
android.media.soundtrigger_middleware.RecognitionEvent event =
- new android.media.soundtrigger_middleware.RecognitionEvent();
+ newEmptyRecognitionEvent();
event.status =
android.media.soundtrigger_middleware.RecognitionStatus.ABORTED;
+ event.type = SoundModelType.GENERIC;
mCallback.onRecognition(mHandle, event);
}
break;
case SoundModelType.KEYPHRASE: {
android.media.soundtrigger_middleware.PhraseRecognitionEvent event =
- new android.media.soundtrigger_middleware.PhraseRecognitionEvent();
- event.common =
- new android.media.soundtrigger_middleware.RecognitionEvent();
+ newEmptyPhraseRecognitionEvent();
event.common.status =
android.media.soundtrigger_middleware.RecognitionStatus.ABORTED;
+ event.common.type = SoundModelType.KEYPHRASE;
mCallback.onPhraseRecognition(mHandle, event);
}
break;
@@ -614,4 +619,35 @@ class SoundTriggerModule implements IHwBinder.DeathRecipient {
}
}
}
+
+ /**
+ * Creates a default-initialized recognition event.
+ *
+ * Object fields are default constructed.
+ * Array fields are initialized to 0 length.
+ *
+ * @return The event.
+ */
+ private static RecognitionEvent newEmptyRecognitionEvent() {
+ RecognitionEvent result = new RecognitionEvent();
+ result.audioConfig = new AudioConfig();
+ result.audioConfig.offloadInfo = new AudioOffloadInfo();
+ result.data = new byte[0];
+ return result;
+ }
+
+ /**
+ * Creates a default-initialized phrase recognition event.
+ *
+ * Object fields are default constructed.
+ * Array fields are initialized to 0 length.
+ *
+ * @return The event.
+ */
+ private static PhraseRecognitionEvent newEmptyPhraseRecognitionEvent() {
+ PhraseRecognitionEvent result = new PhraseRecognitionEvent();
+ result.common = newEmptyRecognitionEvent();
+ result.phraseExtras = new PhraseRecognitionExtra[0];
+ return result;
+ }
}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 22455ad39960..ab459fdadd21 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -19,6 +19,8 @@ package com.android.server.stats.pull;
import static android.app.AppOpsManager.OP_FLAG_SELF;
import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
import static android.app.usage.NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN;
+import static android.app.usage.NetworkStatsManager.FLAG_POLL_FORCE;
+import static android.app.usage.NetworkStatsManager.FLAG_POLL_ON_OPEN;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -243,11 +245,6 @@ public class StatsPullAtomService extends SystemService {
private static final String DANGEROUS_PERMISSION_STATE_SAMPLE_RATE =
"dangerous_permission_state_sample_rate";
- private final Object mNetworkStatsLock = new Object();
- @GuardedBy("mNetworkStatsLock")
- @Nullable
- private INetworkStatsSession mNetworkStatsSession;
-
private final Object mThermalLock = new Object();
@GuardedBy("mThermalLock")
private IThermalService mThermalService;
@@ -325,7 +322,7 @@ public class StatsPullAtomService extends SystemService {
// Listener for monitoring subscriptions changed event.
private StatsSubscriptionsListener mStatsSubscriptionsListener;
- // List that store SubInfo of subscriptions that ever appeared since boot.
+ // List that stores SubInfo of subscriptions that ever appeared since boot.
private final CopyOnWriteArrayList<SubInfo> mHistoricalSubs = new CopyOnWriteArrayList<>();
public StatsPullAtomService(Context context) {
@@ -681,7 +678,7 @@ public class StatsPullAtomService extends SystemService {
collectNetworkStatsSnapshotForAtom(FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER));
// Listen to subscription changes to record historical subscriptions that activated before
- // pulling, this is used by {@link #pullMobileBytesTransfer}.
+ // pulling, this is used by {@code DATA_USAGE_BYTES_TRANSFER}.
mSubscriptionManager.addOnSubscriptionsChangedListener(
BackgroundThread.getExecutor(), mStatsSubscriptionsListener);
@@ -696,32 +693,26 @@ public class StatsPullAtomService extends SystemService {
/**
* Return the {@code INetworkStatsSession} object that holds the necessary properties needed
* for the subsequent queries to {@link com.android.server.net.NetworkStatsService}. Or
- * null if the service or binder cannot be obtained.
+ * null if the service or binder cannot be obtained. Calling this method will trigger poll
+ * in NetworkStatsService with once per 15 seconds rate-limit, unless {@code bypassRateLimit}
+ * is set to true. This is needed in {@link #getUidNetworkStatsSnapshotForTemplate}, where
+ * bypassing the limit is necessary for perfd to supply realtime stats to developers looking at
+ * the network usage of their app.
*/
@Nullable
- private INetworkStatsSession getNetworkStatsSession() {
- synchronized (mNetworkStatsLock) {
- if (mNetworkStatsSession != null) return mNetworkStatsSession;
-
- final INetworkStatsService networkStatsService =
- INetworkStatsService.Stub.asInterface(
- ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
- if (networkStatsService == null) return null;
+ private INetworkStatsSession getNetworkStatsSession(boolean bypassRateLimit) {
+ final INetworkStatsService networkStatsService =
+ INetworkStatsService.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+ if (networkStatsService == null) return null;
- try {
- networkStatsService.asBinder().linkToDeath(() -> {
- synchronized (mNetworkStatsLock) {
- mNetworkStatsSession = null;
- }
- }, /* flags */ 0);
- mNetworkStatsSession = networkStatsService.openSessionForUsageStats(
- FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, mContext.getOpPackageName());
- } catch (RemoteException e) {
- Slog.e(TAG, "Cannot get NetworkStats session", e);
- mNetworkStatsSession = null;
- }
-
- return mNetworkStatsSession;
+ try {
+ return networkStatsService.openSessionForUsageStats(
+ FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN | (bypassRateLimit ? FLAG_POLL_FORCE
+ : FLAG_POLL_ON_OPEN), mContext.getOpPackageName());
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Cannot get NetworkStats session", e);
+ return null;
}
}
@@ -1032,7 +1023,13 @@ public class StatsPullAtomService extends SystemService {
final long bucketDuration = Settings.Global.getLong(mContext.getContentResolver(),
NETSTATS_UID_BUCKET_DURATION, NETSTATS_UID_DEFAULT_BUCKET_DURATION_MS);
try {
- final NetworkStats stats = getNetworkStatsSession().getSummaryForAllUid(template,
+ // TODO (b/156313635): This is short-term hack to allow perfd gets updated networkStats
+ // history when query in every second in order to show realtime statistics. However,
+ // this is not a good long-term solution since NetworkStatsService will make frequent
+ // I/O and also block main thread when polling.
+ // Consider making perfd queries NetworkStatsService directly.
+ final NetworkStats stats = getNetworkStatsSession(template.getMatchRule()
+ == NetworkTemplate.MATCH_WIFI_WILDCARD).getSummaryForAllUid(template,
currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration,
currentTimeInMillis, includeTags);
return stats;
@@ -3322,8 +3319,8 @@ public class StatsPullAtomService extends SystemService {
public void run() {
try {
estimateAppOpsSamplingRate();
- } catch (Exception e) {
- Slog.e(TAG, "AppOps sampling ratio estimation failed");
+ } catch (Throwable e) {
+ Slog.e(TAG, "AppOps sampling ratio estimation failed: ", e);
synchronized (mAppOpsSamplingRateLock) {
mAppOpsSamplingRate = min(mAppOpsSamplingRate, 10);
}
@@ -3364,7 +3361,7 @@ public class StatsPullAtomService extends SystemService {
Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli(),
Long.MAX_VALUE).setFlags(
OP_FLAGS_PULLED).build();
- appOps.getHistoricalOps(histOpsRequest, mContext.getMainExecutor(), ops::complete);
+ appOps.getHistoricalOps(histOpsRequest, AsyncTask.THREAD_POOL_EXECUTOR, ops::complete);
HistoricalOps histOps = ops.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
TimeUnit.MILLISECONDS);
List<AppOpEntry> opsList =
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index e675f4e8a46c..1c96a2e8c5c2 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -74,7 +74,6 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Queue;
-import java.util.stream.Collectors;
/**
* A manager for TextClassifier services.
@@ -883,6 +882,9 @@ public final class TextClassificationManagerService extends ITextClassifierServi
Slog.d(LOG_TAG, "Binding to " + serviceIntent.getComponent());
willBind = mContext.bindServiceAsUser(
serviceIntent, mConnection, mBindServiceFlags, UserHandle.of(mUserId));
+ if (!willBind) {
+ Slog.e(LOG_TAG, "Could not bind to " + componentName);
+ }
mBinding = willBind;
} finally {
Binder.restoreCallingIdentity(identity);
@@ -955,16 +957,19 @@ public final class TextClassificationManagerService extends ITextClassifierServi
@Override
public void onServiceDisconnected(ComponentName name) {
+ Slog.i(LOG_TAG, "onServiceDisconnected called with " + name);
cleanupService();
}
@Override
public void onBindingDied(ComponentName name) {
+ Slog.i(LOG_TAG, "onBindingDied called with " + name);
cleanupService();
}
@Override
public void onNullBinding(ComponentName name) {
+ Slog.i(LOG_TAG, "onNullBinding called with " + name);
cleanupService();
}
@@ -1047,18 +1052,26 @@ public final class TextClassificationManagerService extends ITextClassifierServi
private static void rewriteTextClassificationIcons(Bundle result) {
final TextClassification classification = TextClassifierService.getResponse(result);
boolean rewrite = false;
- for (RemoteAction action : classification.getActions()) {
- rewrite |= shouldRewriteIcon(action);
+ final List<RemoteAction> actions = classification.getActions();
+ final int size = actions.size();
+ final List<RemoteAction> validActions = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ final RemoteAction action = actions.get(i);
+ final RemoteAction validAction;
+ if (shouldRewriteIcon(action)) {
+ rewrite = true;
+ validAction = validAction(action);
+ } else {
+ validAction = action;
+ }
+ validActions.add(validAction);
}
if (rewrite) {
TextClassifierService.putResponse(
result,
classification.toBuilder()
.clearActions()
- .addActions(classification.getActions()
- .stream()
- .map(action -> validAction(action))
- .collect(Collectors.toList()))
+ .addActions(validActions)
.build());
}
}
@@ -1066,29 +1079,30 @@ public final class TextClassificationManagerService extends ITextClassifierServi
private static void rewriteConversationActionsIcons(Bundle result) {
final ConversationActions convActions = TextClassifierService.getResponse(result);
boolean rewrite = false;
- for (ConversationAction convAction : convActions.getConversationActions()) {
- rewrite |= shouldRewriteIcon(convAction.getAction());
+ final List<ConversationAction> origConvActions = convActions.getConversationActions();
+ final int size = origConvActions.size();
+ final List<ConversationAction> validConvActions = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ final ConversationAction convAction = origConvActions.get(i);
+ final ConversationAction validConvAction;
+ if (shouldRewriteIcon(convAction.getAction())) {
+ rewrite = true;
+ validConvAction = convAction.toBuilder()
+ .setAction(validAction(convAction.getAction()))
+ .build();
+ } else {
+ validConvAction = convAction;
+ }
+ validConvActions.add(validConvAction);
}
if (rewrite) {
TextClassifierService.putResponse(
result,
- new ConversationActions(
- convActions.getConversationActions()
- .stream()
- .map(convAction -> convAction.toBuilder()
- .setAction(validAction(convAction.getAction()))
- .build())
- .collect(Collectors.toList()),
- convActions.getId()));
+ new ConversationActions(validConvActions, convActions.getId()));
}
}
- @Nullable
- private static RemoteAction validAction(@Nullable RemoteAction action) {
- if (!shouldRewriteIcon(action)) {
- return action;
- }
-
+ private static RemoteAction validAction(RemoteAction action) {
final RemoteAction newAction = new RemoteAction(
changeIcon(action.getIcon()),
action.getTitle(),
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index 9476e9260c73..c38d649ada9b 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -77,6 +77,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
@@ -122,6 +123,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
PackageManagerInternal mPmInternal;
/** File storing persisted {@link #mGrantedUriPermissions}. */
+ @GuardedBy("mLock")
private final AtomicFile mGrantFile;
/** XML constants used in {@link #mGrantFile} */
@@ -142,6 +144,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
* This optimized lookup structure maps from {@link UriPermission#targetUid}
* to {@link UriPermission#uri} to {@link UriPermission}.
*/
+ @GuardedBy("mLock")
private final SparseArray<ArrayMap<GrantUri, UriPermission>>
mGrantedUriPermissions = new SparseArray<>();
@@ -206,39 +209,44 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
}
}
+ @Override
+ public void grantUriPermissionFromOwner(IBinder token, int fromUid, String targetPkg,
+ Uri uri, final int modeFlags, int sourceUserId, int targetUserId) {
+ grantUriPermissionFromOwnerUnlocked(token, fromUid, targetPkg, uri, modeFlags, sourceUserId,
+ targetUserId);
+ }
+
/**
* @param uri This uri must NOT contain an embedded userId.
* @param sourceUserId The userId in which the uri is to be resolved.
* @param targetUserId The userId of the app that receives the grant.
*/
- @Override
- public void grantUriPermissionFromOwner(IBinder token, int fromUid, String targetPkg, Uri uri,
- final int modeFlags, int sourceUserId, int targetUserId) {
+ private void grantUriPermissionFromOwnerUnlocked(IBinder token, int fromUid, String targetPkg,
+ Uri uri, final int modeFlags, int sourceUserId, int targetUserId) {
targetUserId = mAmInternal.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), targetUserId, false, ALLOW_FULL_ONLY,
"grantUriPermissionFromOwner", null);
- synchronized(mLock) {
- UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
- if (owner == null) {
- throw new IllegalArgumentException("Unknown owner: " + token);
- }
- if (fromUid != Binder.getCallingUid()) {
- if (Binder.getCallingUid() != myUid()) {
- // Only system code can grant URI permissions on behalf
- // of other users.
- throw new SecurityException("nice try");
- }
- }
- if (targetPkg == null) {
- throw new IllegalArgumentException("null target");
- }
- if (uri == null) {
- throw new IllegalArgumentException("null uri");
- }
- grantUriPermission(fromUid, targetPkg, new GrantUri(sourceUserId, uri, modeFlags),
- modeFlags, owner, targetUserId);
+ UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
+ if (owner == null) {
+ throw new IllegalArgumentException("Unknown owner: " + token);
}
+ if (fromUid != Binder.getCallingUid()) {
+ if (Binder.getCallingUid() != myUid()) {
+ // Only system code can grant URI permissions on behalf
+ // of other users.
+ throw new SecurityException("nice try");
+ }
+ }
+ if (targetPkg == null) {
+ throw new IllegalArgumentException("null target");
+ }
+ if (uri == null) {
+ throw new IllegalArgumentException("null uri");
+ }
+
+ grantUriPermissionUnlocked(fromUid, targetPkg, new GrantUri(sourceUserId, uri, modeFlags),
+ modeFlags, owner, targetUserId);
}
@Override
@@ -362,7 +370,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
persistChanged |= prefixPerm.takePersistableModes(modeFlags);
}
- persistChanged |= maybePrunePersistedUriGrants(uid);
+ persistChanged |= maybePrunePersistedUriGrantsLocked(uid);
if (persistChanged) {
schedulePersistUriGrants();
@@ -374,8 +382,8 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
public void clearGrantedUriPermissions(String packageName, int userId) {
mAmInternal.enforceCallingPermission(
CLEAR_APP_GRANTED_URI_PERMISSIONS, "clearGrantedUriPermissions");
- synchronized(mLock) {
- removeUriPermissionsForPackage(packageName, userId, true, true);
+ synchronized (mLock) {
+ removeUriPermissionsForPackageLocked(packageName, userId, true, true);
}
}
@@ -416,11 +424,11 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
if (exactPerm != null) {
persistChanged |= exactPerm.releasePersistableModes(modeFlags);
- removeUriPermissionIfNeeded(exactPerm);
+ removeUriPermissionIfNeededLocked(exactPerm);
}
if (prefixPerm != null) {
persistChanged |= prefixPerm.releasePersistableModes(modeFlags);
- removeUriPermissionIfNeeded(prefixPerm);
+ removeUriPermissionIfNeededLocked(prefixPerm);
}
if (persistChanged) {
@@ -441,8 +449,9 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
* @param targetOnly When {@code true}, only remove permissions where the app is the target,
* not source.
*/
- void removeUriPermissionsForPackage(
- String packageName, int userHandle, boolean persistable, boolean targetOnly) {
+ @GuardedBy("mLock")
+ private void removeUriPermissionsForPackageLocked(String packageName, int userHandle,
+ boolean persistable, boolean targetOnly) {
if (userHandle == UserHandle.USER_ALL && packageName == null) {
throw new IllegalArgumentException("Must narrow by either package or user");
}
@@ -494,7 +503,9 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
}
/** Returns if the ContentProvider has granted a uri to callingUid */
- boolean checkAuthorityGrants(int callingUid, ProviderInfo cpi, int userId, boolean checkUser) {
+ @GuardedBy("mLock")
+ private boolean checkAuthorityGrantsLocked(int callingUid, ProviderInfo cpi, int userId,
+ boolean checkUser) {
final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
if (perms != null) {
for (int i = perms.size() - 1; i >= 0; i--) {
@@ -530,7 +541,8 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
*
* @return if any mutations occured that require persisting.
*/
- private boolean maybePrunePersistedUriGrants(int uid) {
+ @GuardedBy("mLock")
+ private boolean maybePrunePersistedUriGrantsLocked(int uid) {
final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(uid);
if (perms == null) return false;
if (perms.size() < MAX_PERSISTED_URI_GRANTS) return false;
@@ -552,14 +564,14 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
if (DEBUG) Slog.v(TAG, "Trimming grant created at " + perm.persistedCreateTime);
perm.releasePersistableModes(~0);
- removeUriPermissionIfNeeded(perm);
+ removeUriPermissionIfNeededLocked(perm);
}
return true;
}
/** Like checkGrantUriPermission, but takes an Intent. */
- NeededUriGrants checkGrantUriPermissionFromIntent(int callingUid,
+ private NeededUriGrants checkGrantUriPermissionFromIntentUnlocked(int callingUid,
String targetPkg, Intent intent, int mode, NeededUriGrants needed, int targetUserId) {
if (DEBUG) Slog.v(TAG,
"Checking URI perm to data=" + (intent != null ? intent.getData() : null)
@@ -598,7 +610,8 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
}
if (data != null) {
GrantUri grantUri = GrantUri.resolve(contentUserHint, data, mode);
- targetUid = checkGrantUriPermission(callingUid, targetPkg, grantUri, mode, targetUid);
+ targetUid = checkGrantUriPermissionUnlocked(callingUid, targetPkg, grantUri, mode,
+ targetUid);
if (targetUid > 0) {
if (needed == null) {
needed = new NeededUriGrants(targetPkg, targetUid, mode);
@@ -611,7 +624,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
Uri uri = clip.getItemAt(i).getUri();
if (uri != null) {
GrantUri grantUri = GrantUri.resolve(contentUserHint, uri, mode);
- targetUid = checkGrantUriPermission(callingUid, targetPkg,
+ targetUid = checkGrantUriPermissionUnlocked(callingUid, targetPkg,
grantUri, mode, targetUid);
if (targetUid > 0) {
if (needed == null) {
@@ -622,7 +635,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
} else {
Intent clipIntent = clip.getItemAt(i).getIntent();
if (clipIntent != null) {
- NeededUriGrants newNeeded = checkGrantUriPermissionFromIntent(
+ NeededUriGrants newNeeded = checkGrantUriPermissionFromIntentUnlocked(
callingUid, targetPkg, clipIntent, mode, needed, targetUserId);
if (newNeeded != null) {
needed = newNeeded;
@@ -635,7 +648,8 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
return needed;
}
- void readGrantedUriPermissions() {
+ @GuardedBy("mLock")
+ private void readGrantedUriPermissionsLocked() {
if (DEBUG) Slog.v(TAG, "readGrantedUriPermissions()");
final long now = System.currentTimeMillis();
@@ -681,7 +695,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
if (targetUid != -1) {
final GrantUri grantUri = new GrantUri(sourceUserId, uri,
prefix ? Intent.FLAG_GRANT_PREFIX_URI_PERMISSION : 0);
- final UriPermission perm = findOrCreateUriPermission(
+ final UriPermission perm = findOrCreateUriPermissionLocked(
sourcePkg, targetPkg, targetUid, grantUri);
perm.initPersistedModes(modeFlags, createdTime);
}
@@ -703,7 +717,8 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
}
}
- private UriPermission findOrCreateUriPermission(String sourcePkg,
+ @GuardedBy("mLock")
+ private UriPermission findOrCreateUriPermissionLocked(String sourcePkg,
String targetPkg, int targetUid, GrantUri grantUri) {
ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
if (targetUris == null) {
@@ -740,15 +755,18 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
return;
}
- final UriPermission perm = findOrCreateUriPermission(
- pi.packageName, targetPkg, targetUid, grantUri);
+ final UriPermission perm;
+ synchronized (mLock) {
+ perm = findOrCreateUriPermissionLocked(pi.packageName, targetPkg, targetUid, grantUri);
+ }
perm.grantModes(modeFlags, owner);
mPmInternal.grantImplicitAccess(UserHandle.getUserId(targetUid), null,
UserHandle.getAppId(targetUid), pi.applicationInfo.uid, false /*direct*/);
}
/** Like grantUriPermissionUnchecked, but takes an Intent. */
- void grantUriPermissionUncheckedFromIntent(NeededUriGrants needed, UriPermissionOwner owner) {
+ private void grantUriPermissionUncheckedFromIntent(NeededUriGrants needed,
+ UriPermissionOwner owner) {
if (needed == null) {
return;
}
@@ -759,7 +777,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
}
}
- void grantUriPermission(int callingUid, String targetPkg, GrantUri grantUri,
+ private void grantUriPermissionUnlocked(int callingUid, String targetPkg, GrantUri grantUri,
final int modeFlags, UriPermissionOwner owner, int targetUserId) {
if (targetPkg == null) {
throw new NullPointerException("targetPkg");
@@ -767,7 +785,8 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
int targetUid = mPmInternal.getPackageUidInternal(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
targetUserId);
- targetUid = checkGrantUriPermission(callingUid, targetPkg, grantUri, modeFlags, targetUid);
+ targetUid = checkGrantUriPermissionUnlocked(callingUid, targetPkg, grantUri, modeFlags,
+ targetUid);
if (targetUid < 0) {
return;
}
@@ -775,7 +794,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
grantUriPermissionUnchecked(targetUid, targetPkg, grantUri, modeFlags, owner);
}
- void revokeUriPermission(String targetPackage, int callingUid, GrantUri grantUri,
+ private void revokeUriPermission(String targetPackage, int callingUid, GrantUri grantUri,
final int modeFlags) {
if (DEBUG) Slog.v(TAG, "Revoking all granted permissions to " + grantUri);
@@ -788,8 +807,19 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
return;
}
+ final boolean callerHoldsPermissions = checkHoldingPermissionsUnlocked(pi, grantUri,
+ callingUid, modeFlags);
+ synchronized (mLock) {
+ revokeUriPermissionLocked(targetPackage, callingUid, grantUri, modeFlags,
+ callerHoldsPermissions);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void revokeUriPermissionLocked(String targetPackage, int callingUid, GrantUri grantUri,
+ final int modeFlags, final boolean callerHoldsPermissions) {
// Does the caller have this permission on the URI?
- if (!checkHoldingPermissions(pi, grantUri, callingUid, modeFlags)) {
+ if (!callerHoldsPermissions) {
// If they don't have direct access to the URI, then revoke any
// ownerless URI permissions that have been granted to them.
final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
@@ -861,7 +891,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
* the given {@link ProviderInfo}. Final permission checking is always done
* in {@link ContentProvider}.
*/
- private boolean checkHoldingPermissions(
+ private boolean checkHoldingPermissionsUnlocked(
ProviderInfo pi, GrantUri grantUri, int uid, final int modeFlags) {
if (DEBUG) Slog.v(TAG, "checkHoldingPermissions: uri=" + grantUri + " uid=" + uid);
if (UserHandle.getUserId(uid) != grantUri.sourceUserId) {
@@ -870,11 +900,17 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
return false;
}
}
- return checkHoldingPermissionsInternal(pi, grantUri, uid, modeFlags, true);
+ return checkHoldingPermissionsInternalUnlocked(pi, grantUri, uid, modeFlags, true);
}
- private boolean checkHoldingPermissionsInternal(ProviderInfo pi,
+ private boolean checkHoldingPermissionsInternalUnlocked(ProviderInfo pi,
GrantUri grantUri, int uid, final int modeFlags, boolean considerUidPermissions) {
+ // We must never hold our local mLock in this method, since we may need
+ // to call into ActivityManager for dynamic permission checks
+ if (Thread.holdsLock(mLock)) {
+ throw new IllegalStateException("Must never hold local mLock");
+ }
+
if (pi.applicationInfo.uid == uid) {
return true;
} else if (!pi.exported) {
@@ -968,7 +1004,8 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
return readMet && writeMet && forceMet;
}
- private void removeUriPermissionIfNeeded(UriPermission perm) {
+ @GuardedBy("mLock")
+ private void removeUriPermissionIfNeededLocked(UriPermission perm) {
if (perm.modeFlags != 0) {
return;
}
@@ -985,6 +1022,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
}
}
+ @GuardedBy("mLock")
private UriPermission findUriPermissionLocked(int targetUid, GrantUri grantUri) {
final ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
if (targetUris != null) {
@@ -1020,7 +1058,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
* If you already know the uid of the target, you can supply it in
* lastTargetUid else set that to -1.
*/
- int checkGrantUriPermission(int callingUid, String targetPkg, GrantUri grantUri,
+ private int checkGrantUriPermissionUnlocked(int callingUid, String targetPkg, GrantUri grantUri,
int modeFlags, int lastTargetUid) {
if (!Intent.isAccessUriMode(modeFlags)) {
return -1;
@@ -1076,7 +1114,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
boolean targetHoldsPermission = false;
if (targetUid >= 0) {
// First... does the target actually need this permission?
- if (checkHoldingPermissions(pi, grantUri, targetUid, modeFlags)) {
+ if (checkHoldingPermissionsUnlocked(pi, grantUri, targetUid, modeFlags)) {
// No need to grant the target this permission.
if (DEBUG) Slog.v(TAG,
"Target " + targetPkg + " already has full permission to " + grantUri);
@@ -1144,7 +1182,7 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
*/
boolean specialCrossUserGrant = targetUid >= 0
&& UserHandle.getUserId(targetUid) != grantUri.sourceUserId
- && checkHoldingPermissionsInternal(pi, grantUri, callingUid,
+ && checkHoldingPermissionsInternalUnlocked(pi, grantUri, callingUid,
modeFlags, false /*without considering the uid permissions*/);
// Second... is the provider allowing granting of URI permissions?
@@ -1179,9 +1217,13 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
}
// Third... does the caller itself have permission to access this uri?
- if (!checkHoldingPermissions(pi, grantUri, callingUid, modeFlags)) {
+ if (!checkHoldingPermissionsUnlocked(pi, grantUri, callingUid, modeFlags)) {
// Require they hold a strong enough Uri permission
- if (!checkUriPermission(grantUri, callingUid, modeFlags)) {
+ final boolean res;
+ synchronized (mLock) {
+ res = checkUriPermissionLocked(grantUri, callingUid, modeFlags);
+ }
+ if (!res) {
if (android.Manifest.permission.MANAGE_DOCUMENTS.equals(pi.readPermission)) {
throw new SecurityException(
"UID " + callingUid + " does not have permission to " + grantUri
@@ -1200,13 +1242,14 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
/**
* @param userId The userId in which the uri is to be resolved.
*/
- int checkGrantUriPermission(int callingUid, String targetPkg, Uri uri, int modeFlags,
- int userId) {
- return checkGrantUriPermission(callingUid, targetPkg,
+ private int checkGrantUriPermissionUnlocked(int callingUid, String targetPkg, Uri uri,
+ int modeFlags, int userId) {
+ return checkGrantUriPermissionUnlocked(callingUid, targetPkg,
new GrantUri(userId, uri, modeFlags), modeFlags, -1);
}
- boolean checkUriPermission(GrantUri grantUri, int uid, final int modeFlags) {
+ @GuardedBy("mLock")
+ private boolean checkUriPermissionLocked(GrantUri grantUri, int uid, final int modeFlags) {
final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
final int minStrength = persistable ? UriPermission.STRENGTH_PERSISTABLE
: UriPermission.STRENGTH_OWNED;
@@ -1238,7 +1281,8 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
return false;
}
- private void writeGrantedUriPermissions() {
+ @GuardedBy("mLock")
+ private void writeGrantedUriPermissionsLocked() {
if (DEBUG) Slog.v(TAG, "writeGrantedUriPermissions()");
final long startTime = SystemClock.uptimeMillis();
@@ -1299,34 +1343,35 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
public void handleMessage(Message msg) {
switch (msg.what) {
case PERSIST_URI_GRANTS_MSG: {
- writeGrantedUriPermissions();
+ synchronized (mLock) {
+ writeGrantedUriPermissionsLocked();
+ }
break;
}
}
}
}
- final class LocalService implements UriGrantsManagerInternal {
+ private final class LocalService implements UriGrantsManagerInternal {
@Override
public void removeUriPermissionIfNeeded(UriPermission perm) {
synchronized (mLock) {
- UriGrantsManagerService.this.removeUriPermissionIfNeeded(perm);
+ UriGrantsManagerService.this.removeUriPermissionIfNeededLocked(perm);
}
}
@Override
public void revokeUriPermission(String targetPackage, int callingUid, GrantUri grantUri,
int modeFlags) {
- synchronized (mLock) {
- UriGrantsManagerService.this.revokeUriPermission(
- targetPackage, callingUid, grantUri, modeFlags);
- }
+ UriGrantsManagerService.this.revokeUriPermission(
+ targetPackage, callingUid, grantUri, modeFlags);
}
@Override
public boolean checkUriPermission(GrantUri grantUri, int uid, int modeFlags) {
synchronized (mLock) {
- return UriGrantsManagerService.this.checkUriPermission(grantUri, uid, modeFlags);
+ return UriGrantsManagerService.this.checkUriPermissionLocked(grantUri, uid,
+ modeFlags);
}
}
@@ -1334,83 +1379,73 @@ public class UriGrantsManagerService extends IUriGrantsManager.Stub {
public int checkGrantUriPermission(int callingUid, String targetPkg, Uri uri, int modeFlags,
int userId) {
enforceNotIsolatedCaller("checkGrantUriPermission");
- synchronized (mLock) {
- return UriGrantsManagerService.this.checkGrantUriPermission(
- callingUid, targetPkg, uri, modeFlags, userId);
- }
+ return UriGrantsManagerService.this.checkGrantUriPermissionUnlocked(
+ callingUid, targetPkg, uri, modeFlags, userId);
}
@Override
public NeededUriGrants checkGrantUriPermissionFromIntent(Intent intent, int callingUid,
String targetPkg, int targetUserId) {
- synchronized (mLock) {
- final int mode = (intent != null) ? intent.getFlags() : 0;
- return UriGrantsManagerService.this.checkGrantUriPermissionFromIntent(
- callingUid, targetPkg, intent, mode, null, targetUserId);
- }
+ final int mode = (intent != null) ? intent.getFlags() : 0;
+ return UriGrantsManagerService.this.checkGrantUriPermissionFromIntentUnlocked(
+ callingUid, targetPkg, intent, mode, null, targetUserId);
}
@Override
public void grantUriPermissionUncheckedFromIntent(NeededUriGrants needed,
UriPermissionOwner owner) {
- synchronized (mLock) {
- UriGrantsManagerService.this.grantUriPermissionUncheckedFromIntent(needed, owner);
- }
+ UriGrantsManagerService.this.grantUriPermissionUncheckedFromIntent(needed, owner);
}
@Override
public void onSystemReady() {
synchronized (mLock) {
- UriGrantsManagerService.this.readGrantedUriPermissions();
+ UriGrantsManagerService.this.readGrantedUriPermissionsLocked();
}
}
@Override
public IBinder newUriPermissionOwner(String name) {
enforceNotIsolatedCaller("newUriPermissionOwner");
- synchronized(mLock) {
- UriPermissionOwner owner = new UriPermissionOwner(this, name);
- return owner.getExternalToken();
- }
+ UriPermissionOwner owner = new UriPermissionOwner(this, name);
+ return owner.getExternalToken();
}
@Override
public void removeUriPermissionsForPackage(String packageName, int userHandle,
boolean persistable, boolean targetOnly) {
- synchronized(mLock) {
- UriGrantsManagerService.this.removeUriPermissionsForPackage(
+ synchronized (mLock) {
+ UriGrantsManagerService.this.removeUriPermissionsForPackageLocked(
packageName, userHandle, persistable, targetOnly);
}
}
@Override
public void revokeUriPermissionFromOwner(IBinder token, Uri uri, int mode, int userId) {
- synchronized(mLock) {
- final UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
- if (owner == null) {
- throw new IllegalArgumentException("Unknown owner: " + token);
- }
+ final UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
+ if (owner == null) {
+ throw new IllegalArgumentException("Unknown owner: " + token);
+ }
- if (uri == null) {
- owner.removeUriPermissions(mode);
- } else {
- owner.removeUriPermission(new GrantUri(userId, uri, mode), mode);
- }
+ if (uri == null) {
+ owner.removeUriPermissions(mode);
+ } else {
+ owner.removeUriPermission(new GrantUri(userId, uri, mode), mode);
}
}
@Override
public boolean checkAuthorityGrants(int callingUid, ProviderInfo cpi, int userId,
boolean checkUser) {
- synchronized(mLock) {
- return UriGrantsManagerService.this.checkAuthorityGrants(
+ synchronized (mLock) {
+ return UriGrantsManagerService.this.checkAuthorityGrantsLocked(
callingUid, cpi, userId, checkUser);
}
}
@Override
public void dump(PrintWriter pw, boolean dumpAll, String dumpPackage) {
- synchronized(mLock) {
+ synchronized (mLock) {
boolean needSep = false;
boolean printedAnything = false;
if (mGrantedUriPermissions.size() > 0) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 7c33c7cf6398..fe2b144bcdd6 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1001,6 +1001,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (info.minAspectRatio != 0) {
pw.println(prefix + "minAspectRatio=" + info.minAspectRatio);
}
+ if (info.supportsSizeChanges) {
+ pw.println(prefix + "supportsSizeChanges=true");
+ }
}
}
@@ -6376,6 +6379,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
* aspect ratio.
*/
boolean shouldUseSizeCompatMode() {
+ if (info.supportsSizeChanges) {
+ return false;
+ }
if (inMultiWindowMode() || getWindowConfiguration().hasWindowDecorCaption()) {
final ActivityRecord root = task != null ? task.getRootActivity() : null;
if (root != null && root != this && !root.shouldUseSizeCompatMode()) {
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 00b2a58dbe8f..0d5621dc0e4f 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -23,7 +23,6 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.app.WindowConfiguration.activityTypeToString;
import static android.app.WindowConfiguration.windowingModeToString;
@@ -269,9 +268,6 @@ class ActivityStack extends Task {
private final AnimatingActivityRegistry mAnimatingActivityRegistry =
new AnimatingActivityRegistry();
- /** Stores the override windowing-mode from before a transient mode change (eg. split) */
- private int mRestoreOverrideWindowingMode = WINDOWING_MODE_UNDEFINED;
-
private boolean mTopActivityOccludesKeyguard;
private ActivityRecord mTopDismissingKeyguardActivity;
@@ -662,19 +658,6 @@ class ActivityStack extends Task {
}
/**
- * A transient windowing mode is one which activities enter into temporarily. Examples of this
- * are Split window modes and pip. Non-transient modes are modes that displays can adopt.
- *
- * @param windowingMode the windowingMode to test for transient-ness.
- * @return {@code true} if the windowing mode is transient, {@code false} otherwise.
- */
- private static boolean isTransientWindowingMode(int windowingMode) {
- return windowingMode == WINDOWING_MODE_PINNED
- || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
- }
-
- /**
* Specialization of {@link #setWindowingMode(int)} for this subclass.
*
* @param preferredWindowingMode the preferred windowing mode. This may not be honored depending
@@ -698,11 +681,6 @@ class ActivityStack extends Task {
final int currentOverrideMode = getRequestedOverrideWindowingMode();
final Task topTask = getTopMostTask();
int windowingMode = preferredWindowingMode;
- if (preferredWindowingMode == WINDOWING_MODE_UNDEFINED
- && isTransientWindowingMode(currentMode)) {
- // Leaving a transient mode. Interpret UNDEFINED as "restore"
- windowingMode = mRestoreOverrideWindowingMode;
- }
// Need to make sure windowing mode is supported. If we in the process of creating the stack
// no need to resolve the windowing mode again as it is already resolved to the right mode.
@@ -712,29 +690,16 @@ class ActivityStack extends Task {
windowingMode = WINDOWING_MODE_UNDEFINED;
}
}
- if (taskDisplayArea.getRootSplitScreenPrimaryTask() == this
- && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
- // Resolution to split-screen secondary for the primary split-screen stack means
- // we want to leave split-screen mode.
- windowingMode = mRestoreOverrideWindowingMode;
- }
final boolean alreadyInSplitScreenMode = taskDisplayArea.isSplitScreenModeActivated();
- // Take any required action due to us not supporting the preferred windowing mode.
- if (alreadyInSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN
+ if (creating && alreadyInSplitScreenMode && windowingMode == WINDOWING_MODE_FULLSCREEN
&& isActivityTypeStandardOrUndefined()) {
- final boolean preferredSplitScreen =
- preferredWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- || preferredWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
- if (preferredSplitScreen || creating) {
- // Looks like we can't launch in split screen mode or the stack we are launching
- // doesn't support split-screen mode, go ahead an dismiss split-screen and display a
- // warning toast about it.
- mAtmService.getTaskChangeNotificationController()
- .notifyActivityDismissingDockedStack();
- taskDisplayArea.onSplitScreenModeDismissed(this);
- }
+ // If the stack is being created explicitly in fullscreen mode, dismiss split-screen
+ // and display a warning toast about it.
+ mAtmService.getTaskChangeNotificationController()
+ .notifyActivityDismissingDockedStack();
+ taskDisplayArea.onSplitScreenModeDismissed(this);
}
if (currentMode == windowingMode) {
@@ -797,9 +762,6 @@ class ActivityStack extends Task {
+ " while there is already one isn't currently supported");
//return;
}
- if (isTransientWindowingMode(windowingMode) && !isTransientWindowingMode(currentMode)) {
- mRestoreOverrideWindowingMode = currentOverrideMode;
- }
mTmpRect2.setEmpty();
if (windowingMode != WINDOWING_MODE_FULLSCREEN) {
@@ -819,6 +781,22 @@ class ActivityStack extends Task {
mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
mRootWindowContainer.resumeFocusedStacksTopActivities();
+
+ final boolean pinnedToFullscreen = currentMode == WINDOWING_MODE_PINNED
+ && windowingMode == WINDOWING_MODE_FULLSCREEN;
+ if (pinnedToFullscreen && topActivity != null && !isForceHidden()) {
+ mDisplayContent.getPinnedStackController().setPipWindowingModeChanging(true);
+ try {
+ // Report orientation as soon as possible so that the display can freeze earlier if
+ // the display orientation will be changed. Because the surface bounds of activity
+ // may have been set to fullscreen but the activity hasn't redrawn its content yet,
+ // the rotation animation needs to capture snapshot earlier to avoid animating from
+ // an intermediate state.
+ topActivity.reportDescendantOrientationChangeIfNeeded();
+ } finally {
+ mDisplayContent.getPinnedStackController().setPipWindowingModeChanging(false);
+ }
+ }
}
@Override
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 8903776469db..a5b94b327699 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1481,6 +1481,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
// has it own policy for bounds, the activity bounds based on parent is unknown.
return false;
}
+ if (mPinnedStackControllerLocked.isPipActiveOrWindowingModeChanging()) {
+ // Use normal rotation animation because seamless PiP rotation is not supported yet.
+ return false;
+ }
setFixedRotationLaunchingApp(r, rotation);
return true;
@@ -4772,6 +4776,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
* @param sc The new SurfaceControl, where the DisplayContent's surfaces will be re-parented to.
*/
void reparentDisplayContent(WindowState win, SurfaceControl sc) {
+ if (mParentWindow != null) {
+ mParentWindow.removeEmbeddedDisplayContent(this);
+ }
mParentWindow = win;
mParentWindow.addEmbeddedDisplayContent(this);
mParentSurfaceControl = sc;
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 56312aa1b0b8..52ada472f0aa 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -23,7 +23,6 @@ import android.app.RemoteAction;
import android.content.ComponentName;
import android.content.pm.ParceledListSlice;
import android.content.res.Resources;
-import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.DisplayMetrics;
@@ -33,8 +32,6 @@ import android.view.DisplayInfo;
import android.view.IPinnedStackController;
import android.view.IPinnedStackListener;
-import com.android.server.UiThread;
-
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -61,7 +58,6 @@ class PinnedStackController {
private final WindowManagerService mService;
private final DisplayContent mDisplayContent;
- private final Handler mHandler = UiThread.getHandler();
private IPinnedStackListener mPinnedStackListener;
private final PinnedStackListenerDeathHandler mPinnedStackListenerDeathHandler =
@@ -69,6 +65,9 @@ class PinnedStackController {
private final PinnedStackControllerCallback mCallbacks = new PinnedStackControllerCallback();
+ /** Whether the PiP is entering or leaving. */
+ private boolean mIsPipWindowingModeChanging;
+
private boolean mIsImeShowing;
private int mImeHeight;
@@ -161,6 +160,20 @@ class PinnedStackController {
Float.compare(aspectRatio, mMaxAspectRatio) <= 0;
}
+ /** Returns {@code true} if the PiP is on screen or is changing windowing mode. */
+ boolean isPipActiveOrWindowingModeChanging() {
+ if (mIsPipWindowingModeChanging) {
+ return true;
+ }
+ final Task pinnedTask = mDisplayContent.getDefaultTaskDisplayArea().getRootPinnedTask();
+ return pinnedTask != null && pinnedTask.hasChild();
+ }
+
+ /** Sets whether a visible stack is changing from or to pinned mode. */
+ void setPipWindowingModeChanging(boolean isPipWindowingModeChanging) {
+ mIsPipWindowingModeChanging = isPipWindowingModeChanging;
+ }
+
/**
* Activity is hidden (either stopped or removed), resets the last saved snap fraction
* so that the default bounds will be returned for the next session.
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 0143eb1abe03..1b77fd2e8782 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -388,18 +388,15 @@ class SurfaceAnimator {
final SurfaceControl.Builder builder = animatable.makeAnimationLeash()
.setParent(animatable.getAnimationLeashParent())
.setName(surface + " - animation-leash")
- .setColorLayer();
+ // TODO(b/151665759) Defer reparent calls
+ // We want the leash to be visible immediately because the transaction which shows
+ // the leash may be deferred but the reparent will not. This will cause the leashed
+ // surface to be invisible until the deferred transaction is applied. If this
+ // doesn't work, you will can see the 2/3 button nav bar flicker during seamless
+ // rotation.
+ .setHidden(hidden)
+ .setEffectLayer();
final SurfaceControl leash = builder.build();
- if (!hidden) {
- // TODO(b/151665759) Defer reparent calls
- // We want the leash to be visible immediately but we want to set the effects on
- // the layer. Since the transaction used in this function may be deferred, we apply
- // another transaction immediately with the correct visibility and effects.
- // If this doesn't work, you will can see the 2/3 button nav bar flicker during
- // seamless rotation.
- transactionFactory.get().unsetColor(leash).show(leash).apply();
- }
- t.unsetColor(leash);
t.setWindowCrop(leash, width, height);
t.setPosition(leash, x, y);
t.show(leash);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 345928e17768..48609e17ba40 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3164,6 +3164,11 @@ class Task extends WindowContainer<WindowContainer> {
}
@Override
+ public SurfaceControl.Builder makeAnimationLeash() {
+ return super.makeAnimationLeash().setMetadata(METADATA_TASK_ID, mTaskId);
+ }
+
+ @Override
public SurfaceControl getAnimationLeashParent() {
if (WindowManagerService.sHierarchicalAnimations) {
return super.getAnimationLeashParent();
@@ -3203,14 +3208,8 @@ class Task extends WindowContainer<WindowContainer> {
}
@Override
- void onSurfaceShown(SurfaceControl.Transaction t) {
- super.onSurfaceShown(t);
- t.unsetColor(mSurfaceControl);
- }
-
- @Override
void setInitialSurfaceControlProperties(SurfaceControl.Builder b) {
- b.setColorLayer().setMetadata(METADATA_TASK_ID, mTaskId);
+ b.setEffectLayer().setMetadata(METADATA_TASK_ID, mTaskId);
super.setInitialSurfaceControlProperties(b);
}
@@ -3510,7 +3509,7 @@ class Task extends WindowContainer<WindowContainer> {
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
"applyAnimationUnchecked, control: %s, task: %s, transit: %s",
control, asTask(), AppTransition.appTransitionToString(transit));
- control.addTaskToTargets(getRootTask(), finishedCallback);
+ control.addTaskToTargets(this, finishedCallback);
}
} else {
super.applyAnimationUnchecked(lp, enter, transit, isVoiceInteraction, finishedCallback);
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index df0fa9cc3272..6e9428ee6976 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -61,6 +61,7 @@ class TaskChangeNotificationController {
private static final int NOTIFY_TASK_LIST_FROZEN_UNFROZEN_MSG = 26;
private static final int NOTIFY_TASK_FOCUS_CHANGED_MSG = 27;
private static final int NOTIFY_TASK_REQUESTED_ORIENTATION_CHANGED_MSG = 28;
+ private static final int NOTIFY_ACTIVITY_ROTATED_MSG = 29;
// Delay in notifying task stack change listeners (in millis)
private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
@@ -183,6 +184,10 @@ class TaskChangeNotificationController {
l.onTaskRequestedOrientationChanged(m.arg1, m.arg2);
};
+ private final TaskStackConsumer mNotifyOnActivityRotation = (l, m) -> {
+ l.onActivityRotation();
+ };
+
@FunctionalInterface
public interface TaskStackConsumer {
void accept(ITaskStackListener t, Message m) throws RemoteException;
@@ -277,6 +282,9 @@ class TaskChangeNotificationController {
case NOTIFY_TASK_REQUESTED_ORIENTATION_CHANGED_MSG:
forAllRemoteListeners(mNotifyTaskRequestedOrientationChanged, msg);
break;
+ case NOTIFY_ACTIVITY_ROTATED_MSG:
+ forAllRemoteListeners(mNotifyOnActivityRotation, msg);
+ break;
}
if (msg.obj instanceof SomeArgs) {
((SomeArgs) msg.obj).recycle();
@@ -574,4 +582,11 @@ class TaskChangeNotificationController {
forAllLocalListeners(mNotifyTaskRequestedOrientationChanged, msg);
msg.sendToTarget();
}
+
+ /** @see android.app.ITaskStackListener#onActivityRotation() */
+ void notifyOnActivityRotation() {
+ final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_ROTATED_MSG);
+ forAllLocalListeners(mNotifyOnActivityRotation, msg);
+ msg.sendToTarget();
+ }
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 392557045b4a..e26f1e1fe06f 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -391,6 +391,7 @@ class TaskSnapshotSurface implements StartingSurface {
frame = null;
mTmpSnapshotSize.set(0, 0, buffer.getWidth(), buffer.getHeight());
mTmpDstFrame.set(mFrame);
+ mTmpDstFrame.offsetTo(0, 0);
}
// Scale the mismatch dimensions to fill the task bounds
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index d1cb2105246a..aee5a1d7838b 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -106,6 +106,8 @@ class WallpaperController {
private static final int WALLPAPER_DRAW_TIMEOUT = 2;
private int mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
+ private boolean mShouldUpdateZoom;
+
/**
* Temporary storage for taking a screenshot of the wallpaper.
* @see #screenshotWallpaperLocked()
@@ -400,6 +402,7 @@ class WallpaperController {
void setWallpaperZoomOut(WindowState window, float zoom) {
if (Float.compare(window.mWallpaperZoomOut, zoom) != 0) {
window.mWallpaperZoomOut = zoom;
+ mShouldUpdateZoom = true;
updateWallpaperOffsetLocked(window, false);
}
}
@@ -623,9 +626,7 @@ class WallpaperController {
mLastWallpaperX = mWallpaperTarget.mWallpaperX;
mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep;
}
- if (mWallpaperTarget.mWallpaperZoomOut >= 0) {
- mLastWallpaperZoomOut = mWallpaperTarget.mWallpaperZoomOut;
- }
+ computeLastWallpaperZoomOut();
if (mWallpaperTarget.mWallpaperY >= 0) {
mLastWallpaperY = mWallpaperTarget.mWallpaperY;
mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep;
@@ -804,8 +805,11 @@ class WallpaperController {
* we'll have conflicts and break the "depth system" mental model.
*/
private void computeLastWallpaperZoomOut() {
- mLastWallpaperZoomOut = 0;
- mDisplayContent.forAllWindows(mComputeMaxZoomOutFunction, true);
+ if (mShouldUpdateZoom) {
+ mLastWallpaperZoomOut = 0;
+ mDisplayContent.forAllWindows(mComputeMaxZoomOutFunction, true);
+ mShouldUpdateZoom = false;
+ }
}
private float zoomOutToScale(float zoom) {
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 46680662c030..90156fd4f475 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1165,15 +1165,12 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
mOrientation = orientation;
- final int configOrientation = getRequestedConfigurationOrientation();
- if (getRequestedOverrideConfiguration().orientation != configOrientation) {
- mTmpConfig.setTo(getRequestedOverrideConfiguration());
- mTmpConfig.orientation = configOrientation;
- onRequestedOverrideConfigurationChanged(mTmpConfig);
- }
-
final WindowContainer parent = getParent();
if (parent != null) {
+ if (getConfiguration().orientation != getRequestedConfigurationOrientation()) {
+ // Resolve the requested orientation.
+ onConfigurationChanged(parent.getConfiguration());
+ }
onDescendantOrientationChanged(freezeDisplayToken, requestingContainer);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f34510e2104a..8934e8f5c2e0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3848,6 +3848,11 @@ public class WindowManagerService extends IWindowManager.Stub
final boolean rotationChanged = displayContent.updateRotationUnchecked();
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ if (rotationChanged) {
+ mAtmService.getTaskChangeNotificationController()
+ .notifyOnActivityRotation();
+ }
+
if (!rotationChanged || forceRelayout) {
displayContent.setLayoutNeeded();
layoutNeeded = true;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 46d6009b9ab8..36232e13fcf1 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -21,6 +21,7 @@ import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.OP_NONE;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.isSplitScreenWindowingMode;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.os.PowerManager.DRAW_WAKE_LOCK;
@@ -3757,6 +3758,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (!inSplitScreenWindowingMode() && !inFreeformWindowingMode()) {
return false;
}
+ // TODO(157912944): formalize drag-resizing so that exceptions aren't hardcoded like this
+ if (task.getActivityType() == ACTIVITY_TYPE_HOME) {
+ // The current sys-ui implementations never live-resize home, so to prevent WSA from
+ // creating/destroying surfaces (which messes up sync-transactions), skip HOME tasks.
+ return false;
+ }
if (mAttrs.width != MATCH_PARENT || mAttrs.height != MATCH_PARENT) {
// Floating windows never enter drag resize mode.
return false;
@@ -5783,10 +5790,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// be invoked and we need to invoke it ourself.
if (mLocalSyncId >= 0) {
mBLASTSyncEngine.setReady(mLocalSyncId);
- } else {
- mWaitingListener.onTransactionReady(mWaitingSyncId, mBLASTSyncTransaction);
+ return mWinAnimator.finishDrawingLocked(null);
}
+ mWaitingListener.onTransactionReady(mWaitingSyncId, mBLASTSyncTransaction);
mUsingBLASTSyncTransaction = false;
mWaitingSyncId = 0;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 42c21930bdf7..c0252363a159 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -418,25 +418,25 @@ class WindowStateAnimator {
if (!mDestroyPreservedSurfaceUponRedraw) {
return;
}
- if (mSurfaceController != null) {
- if (mPendingDestroySurface != null) {
- // If we are preserving a surface but we aren't relaunching that means
- // we are just doing an in-place switch. In that case any SurfaceFlinger side
- // child layers need to be reparented to the new surface to make this
- // transparent to the app.
- if (mWin.mActivityRecord == null || mWin.mActivityRecord.isRelaunching() == false) {
- mPostDrawTransaction.reparentChildren(
- mPendingDestroySurface.getClientViewRootSurface(),
- mSurfaceController.mSurfaceControl).apply();
- }
- }
+
+ // If we are preserving a surface but we aren't relaunching that means
+ // we are just doing an in-place switch. In that case any SurfaceFlinger side
+ // child layers need to be reparented to the new surface to make this
+ // transparent to the app.
+ // If the children are detached, we don't want to reparent them to the new surface.
+ // Instead let the children get removed when the old surface is deleted.
+ if (mSurfaceController != null && mPendingDestroySurface != null && !mChildrenDetached
+ && (mWin.mActivityRecord == null || !mWin.mActivityRecord.isRelaunching())) {
+ mPostDrawTransaction.reparentChildren(
+ mPendingDestroySurface.getClientViewRootSurface(),
+ mSurfaceController.mSurfaceControl).apply();
}
destroyDeferredSurfaceLocked();
mDestroyPreservedSurfaceUponRedraw = false;
}
- void markPreservedSurfaceForDestroy() {
+ private void markPreservedSurfaceForDestroy() {
if (mDestroyPreservedSurfaceUponRedraw
&& !mService.mDestroyPreservedSurface.contains(mWin)) {
mService.mDestroyPreservedSurface.add(mWin);
@@ -1363,9 +1363,13 @@ class WindowStateAnimator {
if (mPendingDestroySurface != null && mDestroyPreservedSurfaceUponRedraw) {
final SurfaceControl pendingSurfaceControl = mPendingDestroySurface.mSurfaceControl;
mPostDrawTransaction.reparent(pendingSurfaceControl, null);
- mPostDrawTransaction.reparentChildren(
- mPendingDestroySurface.getClientViewRootSurface(),
- mSurfaceController.mSurfaceControl);
+ // If the children are detached, we don't want to reparent them to the new surface.
+ // Instead let the children get removed when the old surface is deleted.
+ if (!mChildrenDetached) {
+ mPostDrawTransaction.reparentChildren(
+ mPendingDestroySurface.getClientViewRootSurface(),
+ mSurfaceController.mSurfaceControl);
+ }
}
SurfaceControl.mergeToGlobalTransaction(mPostDrawTransaction);
@@ -1593,6 +1597,12 @@ class WindowStateAnimator {
mSurfaceController.detachChildren();
}
mChildrenDetached = true;
+ // If the children are detached, it means the app is exiting. We don't want to tear the
+ // content down too early, otherwise we could end up with a flicker. By preserving the
+ // current surface, we ensure the content remains on screen until the window is completely
+ // removed. It also ensures that the old surface is cleaned up when started again since it
+ // forces mSurfaceController to be set to null.
+ preserveSurfaceLocked();
}
void setOffsetPositionForStackResize(boolean offsetPositionForStackResize) {
diff --git a/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java b/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java
index d89bbe9dd14e..d008b72c6bad 100644
--- a/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java
+++ b/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java
@@ -148,6 +148,9 @@ class UsageStatsQueryHelper {
UsageStatsManager.INTERVAL_BEST, startTime, endTime,
/* obfuscateInstantApps= */ false);
Map<String, AppUsageStatsData> aggregatedStats = new ArrayMap<>();
+ if (stats == null) {
+ return aggregatedStats;
+ }
for (UsageStats stat : stats) {
String packageName = stat.getPackageName();
if (packageNameFilter.contains(packageName)) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/UserInfoHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/location/UserInfoHelperTest.java
index 71e79b331cae..56727e81bda5 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/UserInfoHelperTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/UserInfoHelperTest.java
@@ -16,34 +16,23 @@
package com.android.server.location;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
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.isNull;
-import static org.mockito.Mockito.doAnswer;
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.MockitoAnnotations.initMocks;
-import android.app.ActivityManager;
-import android.content.BroadcastReceiver;
+import android.app.ActivityManagerInternal;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.UserInfo;
-import android.os.Handler;
-import android.os.UserHandle;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.dx.mockito.inline.extended.StaticMockitoSession;
+import com.android.server.LocalServices;
import com.android.server.location.UserInfoHelper.UserListener;
import org.junit.After;
@@ -51,16 +40,18 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.quality.Strictness;
-
-import java.util.ArrayList;
-import java.util.List;
@Presubmit
@SmallTest
@RunWith(AndroidJUnit4.class)
public class UserInfoHelperTest {
+ private static class TestUserInfoHelper extends UserInfoHelper {
+ TestUserInfoHelper(Context context) {
+ super(context);
+ }
+ }
+
private static final int USER1_ID = 1;
private static final int USER1_MANAGED_ID = 11;
private static final int[] USER1_PROFILES = new int[]{USER1_ID, USER1_MANAGED_ID};
@@ -70,69 +61,30 @@ public class UserInfoHelperTest {
@Mock private Context mContext;
@Mock private UserManager mUserManager;
+ @Mock private ActivityManagerInternal mActivityManagerInternal;
- private StaticMockitoSession mMockingSession;
- private List<BroadcastReceiver> mBroadcastReceivers = new ArrayList<>();
-
- private UserInfoHelper mHelper;
+ private TestUserInfoHelper mHelper;
@Before
public void setUp() {
- mMockingSession = mockitoSession()
- .initMocks(this)
- .spyStatic(ActivityManager.class)
- .strictness(Strictness.WARN)
- .startMocking();
+ initMocks(this);
+ LocalServices.addService(ActivityManagerInternal.class, mActivityManagerInternal);
doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
- doAnswer(invocation -> {
- mBroadcastReceivers.add(invocation.getArgument(0));
- return null;
- }).when(mContext).registerReceiverAsUser(any(BroadcastReceiver.class), any(
- UserHandle.class), any(IntentFilter.class), isNull(), any(Handler.class));
- doReturn(USER1_PROFILES).when(mUserManager).getProfileIdsWithDisabled(USER1_ID);
- doReturn(USER2_PROFILES).when(mUserManager).getProfileIdsWithDisabled(USER2_ID);
- doReturn(new UserInfo(USER1_ID, "", 0)).when(mUserManager).getProfileParent(
- USER1_MANAGED_ID);
- doReturn(new UserInfo(USER2_ID, "", 0)).when(mUserManager).getProfileParent(
- USER2_MANAGED_ID);
-
- doReturn(USER1_ID).when(ActivityManager::getCurrentUser);
-
- mHelper = new UserInfoHelper(mContext);
+
+ doReturn(USER1_PROFILES).when(mUserManager).getEnabledProfileIds(USER1_ID);
+ doReturn(USER2_PROFILES).when(mUserManager).getEnabledProfileIds(USER2_ID);
+ doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER1_ID);
+ doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER1_MANAGED_ID);
+ doReturn(USER1_PROFILES).when(mActivityManagerInternal).getCurrentProfileIds();
+
+ mHelper = new TestUserInfoHelper(mContext);
mHelper.onSystemReady();
}
@After
public void tearDown() {
- if (mMockingSession != null) {
- mMockingSession.finishMocking();
- }
- }
-
- private void switchUser(int userId) {
- doReturn(userId).when(ActivityManager::getCurrentUser);
- Intent intent = new Intent(Intent.ACTION_USER_SWITCHED).putExtra(Intent.EXTRA_USER_HANDLE,
- userId);
- for (BroadcastReceiver broadcastReceiver : mBroadcastReceivers) {
- broadcastReceiver.onReceive(mContext, intent);
- }
- }
-
- private void startUser(int userId) {
- Intent intent = new Intent(Intent.ACTION_USER_STARTED).putExtra(Intent.EXTRA_USER_HANDLE,
- userId);
- for (BroadcastReceiver broadcastReceiver : mBroadcastReceivers) {
- broadcastReceiver.onReceive(mContext, intent);
- }
- }
-
- private void stopUser(int userId) {
- Intent intent = new Intent(Intent.ACTION_USER_STOPPED).putExtra(Intent.EXTRA_USER_HANDLE,
- userId);
- for (BroadcastReceiver broadcastReceiver : mBroadcastReceivers) {
- broadcastReceiver.onReceive(mContext, intent);
- }
+ LocalServices.removeServiceForTest(ActivityManagerInternal.class);
}
@Test
@@ -140,16 +92,21 @@ public class UserInfoHelperTest {
UserListener listener = mock(UserListener.class);
mHelper.addListener(listener);
- switchUser(USER1_ID);
- verify(listener, never()).onUserChanged(anyInt(), anyInt());
-
- switchUser(USER2_ID);
- verify(listener, times(1)).onUserChanged(USER1_ID, UserListener.USER_SWITCHED);
- verify(listener, times(1)).onUserChanged(USER2_ID, UserListener.USER_SWITCHED);
-
- switchUser(USER1_ID);
- verify(listener, times(2)).onUserChanged(USER1_ID, UserListener.USER_SWITCHED);
- verify(listener, times(2)).onUserChanged(USER2_ID, UserListener.USER_SWITCHED);
+ mHelper.dispatchOnCurrentUserChanged(USER1_ID, USER2_ID);
+ verify(listener, times(1)).onUserChanged(USER1_ID, UserListener.CURRENT_USER_CHANGED);
+ verify(listener, times(1)).onUserChanged(USER1_MANAGED_ID,
+ UserListener.CURRENT_USER_CHANGED);
+ verify(listener, times(1)).onUserChanged(USER2_ID, UserListener.CURRENT_USER_CHANGED);
+ verify(listener, times(1)).onUserChanged(USER2_MANAGED_ID,
+ UserListener.CURRENT_USER_CHANGED);
+
+ mHelper.dispatchOnCurrentUserChanged(USER2_ID, USER1_ID);
+ verify(listener, times(2)).onUserChanged(USER2_ID, UserListener.CURRENT_USER_CHANGED);
+ verify(listener, times(2)).onUserChanged(USER2_MANAGED_ID,
+ UserListener.CURRENT_USER_CHANGED);
+ verify(listener, times(2)).onUserChanged(USER1_ID, UserListener.CURRENT_USER_CHANGED);
+ verify(listener, times(2)).onUserChanged(USER1_MANAGED_ID,
+ UserListener.CURRENT_USER_CHANGED);
}
@Test
@@ -157,11 +114,11 @@ public class UserInfoHelperTest {
UserListener listener = mock(UserListener.class);
mHelper.addListener(listener);
- startUser(USER1_ID);
+ mHelper.dispatchOnUserStarted(USER1_ID);
verify(listener).onUserChanged(USER1_ID, UserListener.USER_STARTED);
- startUser(USER2_ID);
- verify(listener).onUserChanged(USER2_ID, UserListener.USER_STARTED);
+ mHelper.dispatchOnUserStarted(USER1_MANAGED_ID);
+ verify(listener).onUserChanged(USER1_MANAGED_ID, UserListener.USER_STARTED);
}
@Test
@@ -169,24 +126,22 @@ public class UserInfoHelperTest {
UserListener listener = mock(UserListener.class);
mHelper.addListener(listener);
- stopUser(USER1_ID);
- verify(listener).onUserChanged(USER1_ID, UserListener.USER_STOPPED);
-
- stopUser(USER2_ID);
+ mHelper.dispatchOnUserStopped(USER2_ID);
verify(listener).onUserChanged(USER2_ID, UserListener.USER_STOPPED);
+
+ mHelper.dispatchOnUserStopped(USER2_MANAGED_ID);
+ verify(listener).onUserChanged(USER2_MANAGED_ID, UserListener.USER_STOPPED);
}
@Test
public void testCurrentUserIds() {
assertThat(mHelper.getCurrentUserIds()).isEqualTo(USER1_PROFILES);
- switchUser(USER2_ID);
+ doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER2_ID);
+ doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER2_MANAGED_ID);
+ doReturn(USER2_PROFILES).when(mActivityManagerInternal).getCurrentProfileIds();
assertThat(mHelper.getCurrentUserIds()).isEqualTo(USER2_PROFILES);
-
- switchUser(USER1_ID);
-
- assertThat(mHelper.getCurrentUserIds()).isEqualTo(USER1_PROFILES);
}
@Test
@@ -196,7 +151,11 @@ public class UserInfoHelperTest {
assertThat(mHelper.isCurrentUserId(USER2_ID)).isFalse();
assertThat(mHelper.isCurrentUserId(USER2_MANAGED_ID)).isFalse();
- switchUser(USER2_ID);
+ doReturn(false).when(mActivityManagerInternal).isCurrentProfile(USER1_ID);
+ doReturn(false).when(mActivityManagerInternal).isCurrentProfile(USER1_MANAGED_ID);
+ doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER2_ID);
+ doReturn(true).when(mActivityManagerInternal).isCurrentProfile(USER2_MANAGED_ID);
+ doReturn(USER2_PROFILES).when(mActivityManagerInternal).getCurrentProfileIds();
assertThat(mHelper.isCurrentUserId(USER1_ID)).isFalse();
assertThat(mHelper.isCurrentUserId(USER2_ID)).isTrue();
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 145e1ec56e4a..949bcfe53a20 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -184,6 +184,32 @@ public class HdmiCecLocalDevicePlaybackTest {
}
@Test
+ public void handleOnStandby_ScreenOff_NotActiveSource() {
+ mHdmiCecLocalDevicePlayback.setIsActiveSource(false);
+ mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
+ mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+
+ assertThat(mNativeWrapper.getResultMessages()).doesNotContain(standbyMessage);
+ }
+
+ @Test
+ public void handleOnStandby_ScreenOff_ActiveSource() {
+ mHdmiCecLocalDevicePlayback.setIsActiveSource(true);
+ mHdmiCecLocalDevicePlayback.setAutoDeviceOff(true);
+ mHdmiCecLocalDevicePlayback.onStandby(false, HdmiControlService.STANDBY_SCREEN_OFF);
+ mTestLooper.dispatchAll();
+
+ HdmiCecMessage standbyMessage = HdmiCecMessageBuilder.buildStandby(
+ mHdmiCecLocalDevicePlayback.mAddress, ADDR_TV);
+
+ assertThat(mNativeWrapper.getResultMessages()).contains(standbyMessage);
+ }
+
+ @Test
public void sendVolumeKeyEvent_up_volumeEnabled() {
mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 7af7a23b1ef6..c34b8e19a41d 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -33,6 +33,7 @@ import android.content.Context;
import android.content.ContextWrapper;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiPortInfo;
+import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener;
import android.os.IPowerManager;
import android.os.IThermalService;
import android.os.Looper;
@@ -261,4 +262,89 @@ public class HdmiControlServiceTest {
mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
assertThat(mHdmiControlService.isHdmiCecVolumeControlEnabled()).isTrue();
}
+
+ @Test
+ public void addHdmiCecVolumeControlFeatureListener_emitsCurrentState_enabled() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback();
+
+ mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback);
+ mTestLooper.dispatchAll();
+
+ assertThat(callback.mCallbackReceived).isTrue();
+ assertThat(callback.mVolumeControlEnabled).isTrue();
+ }
+
+ @Test
+ public void addHdmiCecVolumeControlFeatureListener_emitsCurrentState_disabled() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
+ VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback();
+
+ mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback);
+ mTestLooper.dispatchAll();
+
+ assertThat(callback.mCallbackReceived).isTrue();
+ assertThat(callback.mVolumeControlEnabled).isFalse();
+ }
+
+ @Test
+ public void addHdmiCecVolumeControlFeatureListener_notifiesStateUpdate() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
+ VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback();
+
+ mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback);
+
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mTestLooper.dispatchAll();
+
+ assertThat(callback.mCallbackReceived).isTrue();
+ assertThat(callback.mVolumeControlEnabled).isTrue();
+ }
+
+ @Test
+ public void addHdmiCecVolumeControlFeatureListener_honorsUnregistration() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
+ VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback();
+
+ mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback);
+ mTestLooper.dispatchAll();
+
+ mHdmiControlService.removeHdmiControlVolumeControlStatusChangeListener(callback);
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mTestLooper.dispatchAll();
+
+ assertThat(callback.mCallbackReceived).isTrue();
+ assertThat(callback.mVolumeControlEnabled).isFalse();
+ }
+
+ @Test
+ public void addHdmiCecVolumeControlFeatureListener_notifiesStateUpdate_multiple() {
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(false);
+ VolumeControlFeatureCallback callback1 = new VolumeControlFeatureCallback();
+ VolumeControlFeatureCallback callback2 = new VolumeControlFeatureCallback();
+
+ mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback1);
+ mHdmiControlService.addHdmiCecVolumeControlFeatureListener(callback2);
+
+
+ mHdmiControlService.setHdmiCecVolumeControlEnabled(true);
+ mTestLooper.dispatchAll();
+
+ assertThat(callback1.mCallbackReceived).isTrue();
+ assertThat(callback2.mCallbackReceived).isTrue();
+ assertThat(callback1.mVolumeControlEnabled).isTrue();
+ assertThat(callback2.mVolumeControlEnabled).isTrue();
+ }
+
+ private static class VolumeControlFeatureCallback extends
+ IHdmiCecVolumeControlFeatureListener.Stub {
+ boolean mCallbackReceived = false;
+ boolean mVolumeControlEnabled = false;
+
+ @Override
+ public void onHdmiCecVolumeControlFeature(boolean enabled) throws RemoteException {
+ this.mCallbackReceived = true;
+ this.mVolumeControlEnabled = enabled;
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
index 8774ab020202..f4c5506c7001 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
@@ -26,7 +26,6 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.content.om.OverlayInfo;
-import android.os.OverlayablePolicy;
import androidx.test.runner.AndroidJUnit4;
@@ -205,138 +204,4 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
impl.setEnabled(OVERLAY, true, USER);
assertEquals(0, listener.count);
}
-
- @Test
- public void testConfigurator() {
- mOverlayableConfigurator = "actor";
- mOverlayableConfiguratorTargets = new String[]{TARGET};
- reinitializeImpl();
-
- installNewPackage(target("actor").setCertificate("one"), USER);
- installNewPackage(target(TARGET).addOverlayable("TestResources").setCertificate("two"),
- USER);
-
- DummyDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET, "TestResources")
- .setCertificate("one");
- installNewPackage(overlay, USER);
-
- DummyIdmapDaemon.IdmapHeader idmap = getIdmapDaemon().getIdmap(overlay.build().apkPath);
- assertNotNull(idmap);
- assertEquals(OverlayablePolicy.ACTOR_SIGNATURE,
- idmap.policies & OverlayablePolicy.ACTOR_SIGNATURE);
- }
-
- @Test
- public void testConfiguratorWithoutOverlayable() {
- mOverlayableConfigurator = "actor";
- mOverlayableConfiguratorTargets = new String[]{TARGET};
- reinitializeImpl();
-
- installNewPackage(target("actor").setCertificate("one"), USER);
- installNewPackage(target(TARGET).setCertificate("two"), USER);
-
- DummyDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET).setCertificate("one");
- installNewPackage(overlay, USER);
-
- DummyIdmapDaemon.IdmapHeader idmap = getIdmapDaemon().getIdmap(overlay.build().apkPath);
- assertNotNull(idmap);
- assertEquals(OverlayablePolicy.ACTOR_SIGNATURE,
- idmap.policies & OverlayablePolicy.ACTOR_SIGNATURE);
- }
-
- @Test
- public void testConfiguratorDifferentTargets() {
- // The target package is not listed in the configurator target list, so the actor policy
- // should not be granted.
- mOverlayableConfigurator = "actor";
- mOverlayableConfiguratorTargets = new String[]{"somethingElse"};
- reinitializeImpl();
-
- installNewPackage(target("actor").setCertificate("one"), USER);
- installNewPackage(target(TARGET).setCertificate("two"), USER);
-
- DummyDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET).setCertificate("one");
- installNewPackage(overlay, USER);
-
- DummyIdmapDaemon.IdmapHeader idmap = getIdmapDaemon().getIdmap(overlay.build().apkPath);
- assertNotNull(idmap);
- assertEquals(0, idmap.policies & OverlayablePolicy.ACTOR_SIGNATURE);
- }
-
- @Test
- public void testConfiguratorDifferentSignatures() {
- mOverlayableConfigurator = "actor";
- mOverlayableConfiguratorTargets = new String[]{TARGET};
- reinitializeImpl();
-
- installNewPackage(target("actor").setCertificate("one"), USER);
- installNewPackage(target(TARGET).addOverlayable("TestResources").setCertificate("two"),
- USER);
-
- DummyDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET, "TestResources")
- .setCertificate("two");
- installNewPackage(overlay, USER);
-
- DummyIdmapDaemon.IdmapHeader idmap = getIdmapDaemon().getIdmap(overlay.build().apkPath);
- assertNotNull(idmap);
- assertEquals(0, idmap.policies & OverlayablePolicy.ACTOR_SIGNATURE);
- }
-
- @Test
- public void testConfiguratorWithoutOverlayableDifferentSignatures() {
- mOverlayableConfigurator = "actor";
- mOverlayableConfiguratorTargets = new String[]{TARGET};
- reinitializeImpl();
-
- installNewPackage(target("actor").setCertificate("one"), USER);
- installNewPackage(target(TARGET).setCertificate("two"), USER);
-
- DummyDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET).setCertificate("two");
- installNewPackage(overlay, USER);
-
- DummyIdmapDaemon.IdmapHeader idmap = getIdmapDaemon().getIdmap(overlay.build().apkPath);
- assertNotNull(idmap);
- assertEquals(0, idmap.policies & OverlayablePolicy.ACTOR_SIGNATURE);
- }
-
- @Test
- public void testConfiguratorChanges() {
- mOverlayableConfigurator = "actor";
- mOverlayableConfiguratorTargets = new String[]{TARGET};
- reinitializeImpl();
-
- installNewPackage(target("actor").setCertificate("one"), USER);
- installNewPackage(target(TARGET).addOverlayable("TestResources").setCertificate("two"),
- USER);
-
- DummyDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET, "TestResources")
- .setCertificate("one");
- installNewPackage(overlay, USER);
-
- DummyIdmapDaemon.IdmapHeader idmap = getIdmapDaemon().getIdmap(overlay.build().apkPath);
- assertNotNull(idmap);
- assertEquals(OverlayablePolicy.ACTOR_SIGNATURE,
- idmap.policies & OverlayablePolicy.ACTOR_SIGNATURE);
-
- // Change the configurator to a different package. The overlay should still be granted the
- // actor policy.
- mOverlayableConfigurator = "differentActor";
- OverlayManagerServiceImpl impl = reinitializeImpl();
- impl.updateOverlaysForUser(USER);
-
- idmap = getIdmapDaemon().getIdmap(overlay.build().apkPath);
- assertNotNull(idmap);
- assertEquals(OverlayablePolicy.ACTOR_SIGNATURE,
- idmap.policies & OverlayablePolicy.ACTOR_SIGNATURE);
-
- // Reset the setting persisting that the overlay once fulfilled the actor policy implicitly
- // through the configurator. The overlay should lose the actor policy.
- impl = reinitializeImpl();
- getSettings().setHasConfiguratorActorPolicy(OVERLAY, USER, false);
- impl.updateOverlaysForUser(USER);
-
- idmap = getIdmapDaemon().getIdmap(overlay.build().apkPath);
- assertNotNull(idmap);
- assertEquals(0, idmap.policies & OverlayablePolicy.ACTOR_SIGNATURE);
- }
}
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
index 52a58907ea5a..733310b2508a 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
@@ -52,9 +52,6 @@ class OverlayManagerServiceImplTestsBase {
private DummyPackageManagerHelper mPackageManager;
private DummyIdmapDaemon mIdmapDaemon;
private OverlayConfig mOverlayConfig;
- private OverlayManagerSettings mSettings;
- String mOverlayableConfigurator;
- String[] mOverlayableConfiguratorTargets;
@Before
public void setUp() {
@@ -62,26 +59,20 @@ class OverlayManagerServiceImplTestsBase {
mListener = new DummyListener();
mPackageManager = new DummyPackageManagerHelper(mState);
mIdmapDaemon = new DummyIdmapDaemon(mState);
- mSettings = new OverlayManagerSettings();
mOverlayConfig = mock(OverlayConfig.class);
when(mOverlayConfig.getPriority(any())).thenReturn(OverlayConfig.DEFAULT_PRIORITY);
when(mOverlayConfig.isEnabled(any())).thenReturn(false);
when(mOverlayConfig.isMutable(any())).thenReturn(true);
- mOverlayableConfigurator = null;
- mOverlayableConfiguratorTargets = null;
reinitializeImpl();
}
- OverlayManagerServiceImpl reinitializeImpl() {
+ void reinitializeImpl() {
mImpl = new OverlayManagerServiceImpl(mPackageManager,
new IdmapManager(mIdmapDaemon, mPackageManager),
- mSettings,
+ new OverlayManagerSettings(),
mOverlayConfig,
new String[0],
- mListener,
- mOverlayableConfigurator,
- mOverlayableConfiguratorTargets);
- return mImpl;
+ mListener);
}
OverlayManagerServiceImpl getImpl() {
@@ -92,14 +83,6 @@ class OverlayManagerServiceImplTestsBase {
return mListener;
}
- DummyIdmapDaemon getIdmapDaemon() {
- return mIdmapDaemon;
- }
-
- OverlayManagerSettings getSettings() {
- return mSettings;
- }
-
void assertState(@State int expected, final String overlayPackageName, int userId) {
final OverlayInfo info = mImpl.getOverlayInfo(overlayPackageName, userId);
if (info == null) {
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
index e2cedb5e1a62..146f60aff724 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
@@ -367,8 +367,7 @@ public class OverlayManagerSettingsTests {
+ " isEnabled='false'\n"
+ " category='dummy-category'\n"
+ " isStatic='false'\n"
- + " priority='0'"
- + " hasConfiguratorActorPolicy='true' />\n"
+ + " priority='0' />\n"
+ "</overlays>\n";
ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes("utf-8"));
@@ -381,7 +380,6 @@ public class OverlayManagerSettingsTests {
assertEquals(1234, oi.userId);
assertEquals(STATE_DISABLED, oi.state);
assertFalse(mSettings.getEnabled("com.dummy.overlay", 1234));
- assertTrue(mSettings.hasConfiguratorActorPolicy("com.dummy.overlay", 1234));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java b/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
index 30ff1196cec0..e9686071409e 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java
@@ -18,6 +18,8 @@ package com.android.server.people.data;
import static com.android.server.people.data.TestUtils.timestamp;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -235,6 +237,19 @@ public final class UsageStatsQueryHelperTest {
assertEquals(5, (long) appLaunchChooserCountCounts.get(PKG_NAME_1).getLaunchCount());
}
+ @Test
+ public void testQueryAppUsageStats_nullUsageStats() {
+ when(mUsageStatsManagerInternal.queryUsageStatsForUser(anyInt(), anyInt(), anyLong(),
+ anyLong(), anyBoolean())).thenReturn(null);
+
+ Map<String, AppUsageStatsData> appLaunchChooserCountCounts =
+ mHelper.queryAppUsageStats(USER_ID_PRIMARY, 90_000L,
+ 200_000L,
+ Set.of(PKG_NAME_1));
+
+ assertThat(appLaunchChooserCountCounts).isEmpty();
+ }
+
private void addUsageEvents(UsageEvents.Event... events) {
UsageEvents usageEvents = new UsageEvents(Arrays.asList(events), new String[]{});
when(mUsageStatsManagerInternal.queryEventsForUser(anyInt(), anyLong(), anyLong(),
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
index 5412bb5106ff..74b4d122cbc0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
@@ -18,8 +18,8 @@ package com.android.server.pm.parsing
import android.content.pm.PackageManager
import android.platform.test.annotations.Presubmit
+import androidx.test.filters.LargeTest
import com.google.common.truth.Expect
-import com.google.common.truth.Truth.assertWithMessage
import org.junit.Rule
import org.junit.Test
@@ -52,6 +52,7 @@ class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() {
}
}
+ @LargeTest
@Test
fun packageInfoEquality() {
val flags = PackageManager.GET_ACTIVITIES or
@@ -65,7 +66,9 @@ class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() {
PackageManager.GET_SERVICES or
PackageManager.GET_SHARED_LIBRARY_FILES or
PackageManager.GET_SIGNATURES or
- PackageManager.GET_SIGNING_CERTIFICATES
+ PackageManager.GET_SIGNING_CERTIFICATES or
+ PackageManager.MATCH_DIRECT_BOOT_UNAWARE or
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
val oldPackageInfo = oldPackages.asSequence().map { oldPackageInfo(it, flags) }
val newPackageInfo = newPackages.asSequence().map { newPackageInfo(it, flags) }
@@ -77,11 +80,79 @@ class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() {
} else {
"$firstName | $secondName"
}
- expect.withMessage("${it.first?.applicationInfo?.sourceDir} $packageName")
- .that(it.first?.dumpToString())
- .isEqualTo(it.second?.dumpToString())
+
+ // Main components are asserted independently to separate the failures. Otherwise the
+ // comparison would include every component in one massive string.
+
+ val prefix = "${it.first?.applicationInfo?.sourceDir} $packageName"
+
+ expect.withMessage("$prefix PackageInfo")
+ .that(it.second?.dumpToString())
+ .isEqualTo(it.first?.dumpToString())
+
+ expect.withMessage("$prefix ApplicationInfo")
+ .that(it.second?.applicationInfo?.dumpToString())
+ .isEqualTo(it.first?.applicationInfo?.dumpToString())
+
+ val firstActivityNames = it.first?.activities?.map { it.name } ?: emptyList()
+ val secondActivityNames = it.second?.activities?.map { it.name } ?: emptyList()
+ expect.withMessage("$prefix activities")
+ .that(secondActivityNames)
+ .containsExactlyElementsIn(firstActivityNames)
+ .inOrder()
+
+ if (!it.first?.activities.isNullOrEmpty() && !it.second?.activities.isNullOrEmpty()) {
+ it.first?.activities?.zip(it.second?.activities!!)?.forEach {
+ expect.withMessage("$prefix ${it.first.name}")
+ .that(it.second.dumpToString())
+ .isEqualTo(it.first.dumpToString())
+ }
+ }
+
+ val firstReceiverNames = it.first?.receivers?.map { it.name } ?: emptyList()
+ val secondReceiverNames = it.second?.receivers?.map { it.name } ?: emptyList()
+ expect.withMessage("$prefix receivers")
+ .that(secondReceiverNames)
+ .containsExactlyElementsIn(firstReceiverNames)
+ .inOrder()
+
+ if (!it.first?.receivers.isNullOrEmpty() && !it.second?.receivers.isNullOrEmpty()) {
+ it.first?.receivers?.zip(it.second?.receivers!!)?.forEach {
+ expect.withMessage("$prefix ${it.first.name}")
+ .that(it.second.dumpToString())
+ .isEqualTo(it.first.dumpToString())
+ }
+ }
+
+ val firstProviderNames = it.first?.providers?.map { it.name } ?: emptyList()
+ val secondProviderNames = it.second?.providers?.map { it.name } ?: emptyList()
+ expect.withMessage("$prefix providers")
+ .that(secondProviderNames)
+ .containsExactlyElementsIn(firstProviderNames)
+ .inOrder()
+
+ if (!it.first?.providers.isNullOrEmpty() && !it.second?.providers.isNullOrEmpty()) {
+ it.first?.providers?.zip(it.second?.providers!!)?.forEach {
+ expect.withMessage("$prefix ${it.first.name}")
+ .that(it.second.dumpToString())
+ .isEqualTo(it.first.dumpToString())
+ }
+ }
+
+ val firstServiceNames = it.first?.services?.map { it.name } ?: emptyList()
+ val secondServiceNames = it.second?.services?.map { it.name } ?: emptyList()
+ expect.withMessage("$prefix services")
+ .that(secondServiceNames)
+ .containsExactlyElementsIn(firstServiceNames)
+ .inOrder()
+
+ if (!it.first?.services.isNullOrEmpty() && !it.second?.services.isNullOrEmpty()) {
+ it.first?.services?.zip(it.second?.services!!)?.forEach {
+ expect.withMessage("$prefix ${it.first.name}")
+ .that(it.second.dumpToString())
+ .isEqualTo(it.first.dumpToString())
+ }
+ }
}
}
}
-
-
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
index 0f028f05d514..420ff19aab74 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
@@ -19,6 +19,7 @@ package com.android.server.pm.parsing
import android.content.Context
import android.content.pm.ActivityInfo
import android.content.pm.ApplicationInfo
+import android.content.pm.ComponentInfo
import android.content.pm.ConfigurationInfo
import android.content.pm.FeatureInfo
import android.content.pm.InstrumentationInfo
@@ -27,6 +28,8 @@ import android.content.pm.PackageParser
import android.content.pm.PackageUserState
import android.content.pm.PermissionInfo
import android.content.pm.ProviderInfo
+import android.content.pm.ServiceInfo
+import android.os.Bundle
import android.os.Debug
import android.os.Environment
import android.util.SparseArray
@@ -38,8 +41,10 @@ import com.android.server.pm.pkg.PackageStateUnserialized
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
import org.junit.BeforeClass
-import org.mockito.Mockito
+import org.mockito.Mockito.any
+import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.anyString
import org.mockito.Mockito.mock
import java.io.File
@@ -47,7 +52,7 @@ open class AndroidPackageParsingTestBase {
companion object {
- private const val VERIFY_ALL_APKS = false
+ private const val VERIFY_ALL_APKS = true
/** For auditing memory usage differences */
private const val DUMP_HPROF_TO_EXTERNAL = false
@@ -81,10 +86,14 @@ open class AndroidPackageParsingTestBase {
.filter { file -> file.name.endsWith(".apk") }
.toList()
}
+ .distinct()
private val dummyUserState = mock(PackageUserState::class.java).apply {
installed = true
- Mockito.`when`(isAvailable(anyInt())).thenReturn(true)
+ whenever(isAvailable(anyInt())) { true }
+ whenever(isMatch(any<ComponentInfo>(), anyInt())) { true }
+ whenever(isMatch(anyBoolean(), anyBoolean(), anyBoolean(), anyBoolean(),
+ anyString(), anyInt())) { true }
}
lateinit var oldPackages: List<PackageParser.Package>
@@ -145,6 +154,7 @@ open class AndroidPackageParsingTestBase {
private fun mockPkgSetting(aPkg: AndroidPackage) = mockThrowOnUnmocked<PackageSetting> {
this.pkg = aPkg
whenever(pkgState) { PackageStateUnserialized() }
+ whenever(readUserState(anyInt())) { dummyUserState }
}
}
@@ -156,19 +166,10 @@ open class AndroidPackageParsingTestBase {
// The following methods prepend "this." because @hide APIs can cause an IDE to auto-import
// the R.attr constant instead of referencing the field in an attempt to fix the error.
- /**
- * Known exclusions:
- * - [ApplicationInfo.credentialProtectedDataDir]
- * - [ApplicationInfo.dataDir]
- * - [ApplicationInfo.deviceProtectedDataDir]
- * - [ApplicationInfo.processName]
- * - [ApplicationInfo.publicSourceDir]
- * - [ApplicationInfo.scanPublicSourceDir]
- * - [ApplicationInfo.scanSourceDir]
- * - [ApplicationInfo.sourceDir]
- * These attributes used to be assigned post-package-parsing as part of another component,
- * but are now adjusted directly inside [PackageImpl].
- */
+ // It's difficult to comment out a line in a triple quoted string, so this is used instead
+ // to ignore specific fields. A comment is required to explain why a field was ignored.
+ private fun Any?.ignored(comment: String): String = "IGNORED"
+
protected fun ApplicationInfo.dumpToString() = """
appComponentFactory=${this.appComponentFactory}
backupAgentName=${this.backupAgentName}
@@ -179,22 +180,31 @@ open class AndroidPackageParsingTestBase {
compatibleWidthLimitDp=${this.compatibleWidthLimitDp}
compileSdkVersion=${this.compileSdkVersion}
compileSdkVersionCodename=${this.compileSdkVersionCodename}
+ credentialProtectedDataDir=${this.credentialProtectedDataDir
+ .ignored("Deferred pre-R, but assigned immediately in R")}
+ crossProfile=${this.crossProfile.ignored("Added in R")}
+ dataDir=${this.dataDir.ignored("Deferred pre-R, but assigned immediately in R")}
descriptionRes=${this.descriptionRes}
+ deviceProtectedDataDir=${this.deviceProtectedDataDir
+ .ignored("Deferred pre-R, but assigned immediately in R")}
enabled=${this.enabled}
enabledSetting=${this.enabledSetting}
flags=${Integer.toBinaryString(this.flags)}
fullBackupContent=${this.fullBackupContent}
+ gwpAsanMode=${this.gwpAsanMode.ignored("Added in R")}
hiddenUntilInstalled=${this.hiddenUntilInstalled}
icon=${this.icon}
iconRes=${this.iconRes}
installLocation=${this.installLocation}
+ labelRes=${this.labelRes}
largestWidthLimitDp=${this.largestWidthLimitDp}
logo=${this.logo}
longVersionCode=${this.longVersionCode}
+ ${"".ignored("mHiddenApiPolicy is a private field")}
manageSpaceActivityName=${this.manageSpaceActivityName}
- maxAspectRatio.compareTo(that.maxAspectRatio)=${this.maxAspectRatio}
- metaData=${this.metaData}
- minAspectRatio.compareTo(that.minAspectRatio)=${this.minAspectRatio}
+ maxAspectRatio=${this.maxAspectRatio}
+ metaData=${this.metaData.dumpToString()}
+ minAspectRatio=${this.minAspectRatio}
minSdkVersion=${this.minSdkVersion}
name=${this.name}
nativeLibraryDir=${this.nativeLibraryDir}
@@ -206,18 +216,27 @@ open class AndroidPackageParsingTestBase {
permission=${this.permission}
primaryCpuAbi=${this.primaryCpuAbi}
privateFlags=${Integer.toBinaryString(this.privateFlags)}
+ processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")}
+ publicSourceDir=${this.publicSourceDir
+ .ignored("Deferred pre-R, but assigned immediately in R")}
requiresSmallestWidthDp=${this.requiresSmallestWidthDp}
resourceDirs=${this.resourceDirs?.contentToString()}
roundIconRes=${this.roundIconRes}
- secondaryCpuAbi=${this.secondaryCpuAbi}
- secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir}
+ scanPublicSourceDir=${this.scanPublicSourceDir
+ .ignored("Deferred pre-R, but assigned immediately in R")}
+ scanSourceDir=${this.scanSourceDir
+ .ignored("Deferred pre-R, but assigned immediately in R")}
seInfo=${this.seInfo}
seInfoUser=${this.seInfoUser}
+ secondaryCpuAbi=${this.secondaryCpuAbi}
+ secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir}
sharedLibraryFiles=${this.sharedLibraryFiles?.contentToString()}
sharedLibraryInfos=${this.sharedLibraryInfos}
showUserIcon=${this.showUserIcon}
+ sourceDir=${this.sourceDir
+ .ignored("Deferred pre-R, but assigned immediately in R")}
splitClassLoaderNames=${this.splitClassLoaderNames?.contentToString()}
- splitDependencies=${this.splitDependencies}
+ splitDependencies=${this.splitDependencies.dumpToString()}
splitNames=${this.splitNames?.contentToString()}
splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()}
splitSourceDirs=${this.splitSourceDirs?.contentToString()}
@@ -226,8 +245,8 @@ open class AndroidPackageParsingTestBase {
targetSdkVersion=${this.targetSdkVersion}
taskAffinity=${this.taskAffinity}
theme=${this.theme}
- uid=${this.uid}
uiOptions=${this.uiOptions}
+ uid=${this.uid}
versionCode=${this.versionCode}
volumeUuid=${this.volumeUuid}
zygotePreloadName=${this.zygotePreloadName}
@@ -241,19 +260,27 @@ open class AndroidPackageParsingTestBase {
""".trimIndent()
protected fun InstrumentationInfo.dumpToString() = """
+ banner=${this.banner}
credentialProtectedDataDir=${this.credentialProtectedDataDir}
dataDir=${this.dataDir}
deviceProtectedDataDir=${this.deviceProtectedDataDir}
functionalTest=${this.functionalTest}
handleProfiling=${this.handleProfiling}
+ icon=${this.icon}
+ labelRes=${this.labelRes}
+ logo=${this.logo}
+ metaData=${this.metaData}
+ name=${this.name}
nativeLibraryDir=${this.nativeLibraryDir}
+ nonLocalizedLabel=${this.nonLocalizedLabel}
+ packageName=${this.packageName}
primaryCpuAbi=${this.primaryCpuAbi}
publicSourceDir=${this.publicSourceDir}
secondaryCpuAbi=${this.secondaryCpuAbi}
secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir}
+ showUserIcon=${this.showUserIcon}
sourceDir=${this.sourceDir}
- splitDependencies=${this.splitDependencies.sequence()
- .map { it.first to it.second?.contentToString() }.joinToString()}
+ splitDependencies=${this.splitDependencies.dumpToString()}
splitNames=${this.splitNames?.contentToString()}
splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()}
splitSourceDirs=${this.splitSourceDirs?.contentToString()}
@@ -262,25 +289,40 @@ open class AndroidPackageParsingTestBase {
""".trimIndent()
protected fun ActivityInfo.dumpToString() = """
+ banner=${this.banner}
colorMode=${this.colorMode}
configChanges=${this.configChanges}
+ descriptionRes=${this.descriptionRes}
+ directBootAware=${this.directBootAware}
documentLaunchMode=${this.documentLaunchMode}
+ enabled=${this.enabled}
+ exported=${this.exported}
flags=${Integer.toBinaryString(this.flags)}
+ icon=${this.icon}
+ labelRes=${this.labelRes}
launchMode=${this.launchMode}
launchToken=${this.launchToken}
lockTaskLaunchMode=${this.lockTaskLaunchMode}
+ logo=${this.logo}
maxAspectRatio=${this.maxAspectRatio}
maxRecents=${this.maxRecents}
+ metaData=${this.metaData.dumpToString()}
minAspectRatio=${this.minAspectRatio}
+ name=${this.name}
+ nonLocalizedLabel=${this.nonLocalizedLabel}
+ packageName=${this.packageName}
parentActivityName=${this.parentActivityName}
permission=${this.permission}
- persistableMode=${this.persistableMode}
- privateFlags=${Integer.toBinaryString(this.privateFlags)}
+ persistableMode=${this.persistableMode.ignored("Could be dropped pre-R, fixed in R")}
+ privateFlags=${this.privateFlags}
+ processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")}
requestedVrComponent=${this.requestedVrComponent}
resizeMode=${this.resizeMode}
rotationAnimation=${this.rotationAnimation}
screenOrientation=${this.screenOrientation}
+ showUserIcon=${this.showUserIcon}
softInputMode=${this.softInputMode}
+ splitName=${this.splitName}
targetActivity=${this.targetActivity}
taskAffinity=${this.taskAffinity}
theme=${this.theme}
@@ -300,30 +342,77 @@ open class AndroidPackageParsingTestBase {
protected fun PermissionInfo.dumpToString() = """
backgroundPermission=${this.backgroundPermission}
+ banner=${this.banner}
descriptionRes=${this.descriptionRes}
flags=${Integer.toBinaryString(this.flags)}
group=${this.group}
+ icon=${this.icon}
+ labelRes=${this.labelRes}
+ logo=${this.logo}
+ metaData=${this.metaData.dumpToString()}
+ name=${this.name}
nonLocalizedDescription=${this.nonLocalizedDescription}
+ nonLocalizedLabel=${this.nonLocalizedLabel}
+ packageName=${this.packageName}
protectionLevel=${this.protectionLevel}
requestRes=${this.requestRes}
+ showUserIcon=${this.showUserIcon}
""".trimIndent()
protected fun ProviderInfo.dumpToString() = """
+ applicationInfo=${this.applicationInfo.ignored("Already checked")}
authority=${this.authority}
+ banner=${this.banner}
+ descriptionRes=${this.descriptionRes}
+ directBootAware=${this.directBootAware}
+ enabled=${this.enabled}
+ exported=${this.exported}
flags=${Integer.toBinaryString(this.flags)}
forceUriPermissions=${this.forceUriPermissions}
grantUriPermissions=${this.grantUriPermissions}
+ icon=${this.icon}
initOrder=${this.initOrder}
isSyncable=${this.isSyncable}
+ labelRes=${this.labelRes}
+ logo=${this.logo}
+ metaData=${this.metaData.dumpToString()}
multiprocess=${this.multiprocess}
+ name=${this.name}
+ nonLocalizedLabel=${this.nonLocalizedLabel}
+ packageName=${this.packageName}
pathPermissions=${this.pathPermissions?.joinToString {
"readPermission=${it.readPermission}\nwritePermission=${it.writePermission}"
}}
+ processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")}
readPermission=${this.readPermission}
+ showUserIcon=${this.showUserIcon}
+ splitName=${this.splitName}
uriPermissionPatterns=${this.uriPermissionPatterns?.contentToString()}
writePermission=${this.writePermission}
""".trimIndent()
+ protected fun ServiceInfo.dumpToString() = """
+ applicationInfo=${this.applicationInfo.ignored("Already checked")}
+ banner=${this.banner}
+ descriptionRes=${this.descriptionRes}
+ directBootAware=${this.directBootAware}
+ enabled=${this.enabled}
+ exported=${this.exported}
+ flags=${Integer.toBinaryString(this.flags)}
+ icon=${this.icon}
+ labelRes=${this.labelRes}
+ logo=${this.logo}
+ mForegroundServiceType"${this.mForegroundServiceType}
+ metaData=${this.metaData.dumpToString()}
+ name=${this.name}
+ nonLocalizedLabel=${this.nonLocalizedLabel}
+ packageName=${this.packageName}
+ permission=${this.permission}
+ processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")}
+ showUserIcon=${this.showUserIcon}
+ splitName=${this.splitName}
+ """.trimIndent()
+
protected fun ConfigurationInfo.dumpToString() = """
reqGlEsVersion=${this.reqGlEsVersion}
reqInputFeatures=${this.reqInputFeatures}
@@ -333,8 +422,10 @@ open class AndroidPackageParsingTestBase {
""".trimIndent()
protected fun PackageInfo.dumpToString() = """
- activities=${this.activities?.joinToString { it.dumpToString() }}
- applicationInfo=${this.applicationInfo.dumpToString()}
+ activities=${this.activities?.joinToString { it.dumpToString() }
+ .ignored("Checked separately in test")}
+ applicationInfo=${this.applicationInfo.dumpToString()
+ .ignored("Checked separately in test")}
baseRevisionCode=${this.baseRevisionCode}
compileSdkVersion=${this.compileSdkVersion}
compileSdkVersionCodename=${this.compileSdkVersionCodename}
@@ -356,15 +447,18 @@ open class AndroidPackageParsingTestBase {
overlayTarget=${this.overlayTarget}
packageName=${this.packageName}
permissions=${this.permissions?.joinToString { it.dumpToString() }}
- providers=${this.providers?.joinToString { it.dumpToString() }}
- receivers=${this.receivers?.joinToString { it.dumpToString() }}
+ providers=${this.providers?.joinToString { it.dumpToString() }
+ .ignored("Checked separately in test")}
+ receivers=${this.receivers?.joinToString { it.dumpToString() }
+ .ignored("Checked separately in test")}
reqFeatures=${this.reqFeatures?.joinToString { it.dumpToString() }}
requestedPermissions=${this.requestedPermissions?.contentToString()}
requestedPermissionsFlags=${this.requestedPermissionsFlags?.contentToString()}
requiredAccountType=${this.requiredAccountType}
requiredForAllUsers=${this.requiredForAllUsers}
restrictedAccountType=${this.restrictedAccountType}
- services=${this.services?.contentToString()}
+ services=${this.services?.joinToString { it.dumpToString() }
+ .ignored("Checked separately in test")}
sharedUserId=${this.sharedUserId}
sharedUserLabel=${this.sharedUserLabel}
signatures=${this.signatures?.joinToString { it.toCharsString() }}
@@ -378,11 +472,17 @@ open class AndroidPackageParsingTestBase {
versionName=${this.versionName}
""".trimIndent()
- @Suppress("unused")
- private fun <T> SparseArray<T>.sequence(): Sequence<Pair<Int, T>> {
- var index = 0
- return generateSequence {
- index++.takeIf { it < size() }?.let { keyAt(it) to valueAt(index) }
+ private fun Bundle?.dumpToString() = this?.keySet()?.associateWith { get(it) }?.toString()
+
+ private fun <T> SparseArray<T>?.dumpToString(): String {
+ if (this == null) {
+ return "EMPTY"
+ }
+
+ val list = mutableListOf<Pair<Int, T>>()
+ for (index in (0 until size())) {
+ list += keyAt(index) to valueAt(index)
}
+ return list.toString()
}
}
diff --git a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
index e86399e1a631..62b6a65cc6cb 100644
--- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
@@ -60,14 +60,12 @@ import java.util.Set;
public class UriGrantsManagerServiceTest {
private UriGrantsMockContext mContext;
- private UriGrantsManagerService mService;
- private UriGrantsManagerInternal mLocalService;
+ private UriGrantsManagerInternal mService;
@Before
public void setUp() throws Exception {
mContext = new UriGrantsMockContext(InstrumentationRegistry.getContext());
- mService = UriGrantsManagerService.createForTest(mContext.getFilesDir());
- mLocalService = mService.getLocalService();
+ mService = UriGrantsManagerService.createForTest(mContext.getFilesDir()).getLocalService();
}
/**
@@ -80,8 +78,7 @@ public class UriGrantsManagerServiceTest {
final GrantUri expectedGrant = new GrantUri(USER_PRIMARY, URI_PHOTO_1, FLAG_READ);
final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_CAMERA, PKG_SOCIAL, intent, intent.getFlags(), null,
- USER_PRIMARY);
+ intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_PRIMARY);
assertEquals(PKG_SOCIAL, needed.targetPkg);
assertEquals(UID_PRIMARY_SOCIAL, needed.targetUid);
assertEquals(FLAG_READ, needed.flags);
@@ -98,8 +95,7 @@ public class UriGrantsManagerServiceTest {
final GrantUri expectedGrant = new GrantUri(USER_PRIMARY, URI_PHOTO_1, FLAG_READ);
final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_CAMERA, PKG_SOCIAL, intent, intent.getFlags(), null,
- USER_SECONDARY);
+ intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_SECONDARY);
assertEquals(PKG_SOCIAL, needed.targetPkg);
assertEquals(UID_SECONDARY_SOCIAL, needed.targetUid);
assertEquals(FLAG_READ, needed.flags);
@@ -113,8 +109,7 @@ public class UriGrantsManagerServiceTest {
public void testNeeded_public() {
final Intent intent = new Intent(Intent.ACTION_VIEW, URI_PUBLIC).addFlags(FLAG_READ);
final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_PUBLIC, PKG_SOCIAL, intent, intent.getFlags(), null,
- USER_PRIMARY);
+ intent, UID_PRIMARY_PUBLIC, PKG_SOCIAL, USER_PRIMARY);
assertNull(needed);
}
@@ -128,7 +123,7 @@ public class UriGrantsManagerServiceTest {
final GrantUri expectedGrant = new GrantUri(USER_PRIMARY, URI_PUBLIC, FLAG_READ);
final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_PUBLIC, PKG_SOCIAL, intent, intent.getFlags(), null, USER_SECONDARY);
+ intent, UID_PRIMARY_PUBLIC, PKG_SOCIAL, USER_SECONDARY);
assertEquals(PKG_SOCIAL, needed.targetPkg);
assertEquals(UID_SECONDARY_SOCIAL, needed.targetUid);
assertEquals(FLAG_READ, needed.flags);
@@ -143,7 +138,7 @@ public class UriGrantsManagerServiceTest {
final Intent intent = new Intent(Intent.ACTION_VIEW, URI_PRIVATE).addFlags(FLAG_READ);
try {
mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_PRIVATE, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY);
+ intent, UID_PRIMARY_PRIVATE, PKG_SOCIAL, USER_PRIMARY);
fail();
} catch (SecurityException expected) {
}
@@ -158,7 +153,7 @@ public class UriGrantsManagerServiceTest {
final Intent intent = new Intent(Intent.ACTION_VIEW, URI_FORCE)
.addFlags(FLAG_READ);
final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_FORCE, PKG_FORCE, intent, intent.getFlags(), null, USER_PRIMARY);
+ intent, UID_PRIMARY_FORCE, PKG_FORCE, USER_PRIMARY);
assertEquals(asSet(new GrantUri(USER_PRIMARY, URI_FORCE, 0)), needed.uris);
}
@@ -172,15 +167,15 @@ public class UriGrantsManagerServiceTest {
{
final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
.addFlags(FLAG_READ | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- assertNull(mService.checkGrantUriPermissionFromIntent(UID_PRIMARY_COMPLEX, PKG_SOCIAL,
- intent, intent.getFlags(), null, USER_PRIMARY));
+ assertNull(mService.checkGrantUriPermissionFromIntent(
+ intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY));
}
{
final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
.addFlags(FLAG_READ | FLAG_PREFIX);
try {
- mService.checkGrantUriPermissionFromIntent(UID_PRIMARY_COMPLEX, PKG_SOCIAL,
- intent, intent.getFlags(), null, USER_PRIMARY);
+ mService.checkGrantUriPermissionFromIntent(
+ intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY);
fail();
} catch (SecurityException expected) {
}
@@ -189,8 +184,8 @@ public class UriGrantsManagerServiceTest {
final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
.addFlags(FLAG_READ | FLAG_PERSISTABLE);
try {
- mService.checkGrantUriPermissionFromIntent(UID_PRIMARY_COMPLEX, PKG_SOCIAL,
- intent, intent.getFlags(), null, USER_PRIMARY);
+ mService.checkGrantUriPermissionFromIntent(
+ intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY);
fail();
} catch (SecurityException expected) {
}
@@ -209,8 +204,7 @@ public class UriGrantsManagerServiceTest {
final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
.addFlags(FLAG_READ);
final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_COMPLEX, PKG_SOCIAL, intent, intent.getFlags(), null,
- USER_SECONDARY);
+ intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_SECONDARY);
assertEquals(FLAG_READ, needed.flags);
}
{
@@ -218,8 +212,7 @@ public class UriGrantsManagerServiceTest {
.addFlags(FLAG_READ | FLAG_PREFIX);
try {
mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_COMPLEX, PKG_SOCIAL, intent, intent.getFlags(), null,
- USER_SECONDARY);
+ intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_SECONDARY);
fail();
} catch (SecurityException expected) {
}
@@ -229,8 +222,7 @@ public class UriGrantsManagerServiceTest {
.addFlags(FLAG_READ | FLAG_PERSISTABLE);
try {
mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_COMPLEX, PKG_SOCIAL, intent, intent.getFlags(), null,
- USER_SECONDARY);
+ intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_SECONDARY);
fail();
} catch (SecurityException expected) {
}
@@ -248,21 +240,21 @@ public class UriGrantsManagerServiceTest {
final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
.addFlags(FLAG_READ);
final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_COMPLEX, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY);
+ intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY);
assertEquals(asSet(new GrantUri(USER_PRIMARY, uri, 0)), needed.uris);
}
{
final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
.addFlags(FLAG_READ | FLAG_PREFIX);
final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_COMPLEX, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY);
+ intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY);
assertEquals(asSet(new GrantUri(USER_PRIMARY, uri, FLAG_PREFIX)), needed.uris);
}
{
final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
.addFlags(FLAG_READ | FLAG_PERSISTABLE);
final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_COMPLEX, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY);
+ intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY);
assertEquals(asSet(new GrantUri(USER_PRIMARY, uri, 0)), needed.uris);
}
}
@@ -284,8 +276,8 @@ public class UriGrantsManagerServiceTest {
// When granting towards primary, persistable can't be honored so
// the entire grant fails
try {
- mService.checkGrantUriPermissionFromIntent(UID_PRIMARY_CAMERA, PKG_SOCIAL, intent,
- intent.getFlags(), null, USER_PRIMARY);
+ mService.checkGrantUriPermissionFromIntent(
+ intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_PRIMARY);
fail();
} catch (SecurityException expected) {
}
@@ -294,8 +286,8 @@ public class UriGrantsManagerServiceTest {
// When granting towards secondary, persistable can't be honored so
// the entire grant fails
try {
- mService.checkGrantUriPermissionFromIntent(UID_PRIMARY_CAMERA, PKG_SOCIAL, intent,
- intent.getFlags(), null, USER_SECONDARY);
+ mService.checkGrantUriPermissionFromIntent(
+ intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_SECONDARY);
fail();
} catch (SecurityException expected) {
}
@@ -310,18 +302,16 @@ public class UriGrantsManagerServiceTest {
public void testGrant_overlap() {
final Intent intent = new Intent(Intent.ACTION_VIEW, URI_PHOTO_1).addFlags(FLAG_READ);
- final UriPermissionOwner activity = new UriPermissionOwner(mLocalService, "activity");
- final UriPermissionOwner service = new UriPermissionOwner(mLocalService, "service");
+ final UriPermissionOwner activity = new UriPermissionOwner(mService, "activity");
+ final UriPermissionOwner service = new UriPermissionOwner(mService, "service");
final GrantUri expectedGrant = new GrantUri(USER_PRIMARY, URI_PHOTO_1, FLAG_READ);
// Grant read via activity and write via service
mService.grantUriPermissionUncheckedFromIntent(mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_CAMERA, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY),
- activity);
+ intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_PRIMARY), activity);
mService.grantUriPermissionUncheckedFromIntent(mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_CAMERA, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY),
- service);
+ intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_PRIMARY), service);
// Verify that everything is good with the world
assertTrue(mService.checkUriPermission(expectedGrant, UID_PRIMARY_SOCIAL, FLAG_READ));
@@ -338,7 +328,7 @@ public class UriGrantsManagerServiceTest {
@Test
public void testCheckAuthorityGrants() {
final Intent intent = new Intent(Intent.ACTION_VIEW, URI_PHOTO_1).addFlags(FLAG_READ);
- final UriPermissionOwner owner = new UriPermissionOwner(mLocalService, "primary");
+ final UriPermissionOwner owner = new UriPermissionOwner(mService, "primary");
final ProviderInfo cameraInfo = mContext.mPmInternal.resolveContentProvider(
PKG_CAMERA, 0, USER_PRIMARY);
@@ -355,8 +345,7 @@ public class UriGrantsManagerServiceTest {
// Granting primary camera to primary social
mService.grantUriPermissionUncheckedFromIntent(mService.checkGrantUriPermissionFromIntent(
- UID_PRIMARY_CAMERA, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY),
- owner);
+ intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_PRIMARY), owner);
assertTrue(mService.checkAuthorityGrants(UID_PRIMARY_SOCIAL,
cameraInfo, USER_PRIMARY, true));
assertFalse(mService.checkAuthorityGrants(UID_PRIMARY_SOCIAL,
@@ -368,8 +357,7 @@ public class UriGrantsManagerServiceTest {
// Granting secondary camera to primary social
mService.grantUriPermissionUncheckedFromIntent(mService.checkGrantUriPermissionFromIntent(
- UID_SECONDARY_CAMERA, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY),
- owner);
+ intent, UID_SECONDARY_CAMERA, PKG_SOCIAL, USER_PRIMARY), owner);
assertTrue(mService.checkAuthorityGrants(UID_PRIMARY_SOCIAL,
cameraInfo, USER_PRIMARY, true));
assertTrue(mService.checkAuthorityGrants(UID_PRIMARY_SOCIAL,
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index b7199f7cdd5a..4439f998a527 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -21,6 +21,7 @@ android_test {
"mockito-target-inline-minus-junit4",
"platform-test-annotations",
"platformprotosnano",
+ "statsdprotolite",
"hamcrest-library",
"testables",
"truth-prebuilt",
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java
index e1f39137e618..c9c31bfcde08 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BadgeExtractorTest.java
@@ -29,6 +29,10 @@ import android.app.ActivityManager;
import android.app.Notification;
import android.app.Notification.Builder;
import android.app.NotificationChannel;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.graphics.drawable.Icon;
+
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;
@@ -79,6 +83,37 @@ public class BadgeExtractorTest extends UiServiceTestCase {
return r;
}
+ private NotificationRecord getNotificationRecordWithBubble(boolean suppressNotif) {
+ NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_UNSPECIFIED);
+ channel.setShowBadge(/* showBadge */ true);
+ when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
+
+ Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder(
+ PendingIntent.getActivity(mContext, 0, new Intent(), 0),
+ Icon.createWithResource("", 0)).build();
+
+ int flags = metadata.getFlags();
+ if (suppressNotif) {
+ flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
+ } else {
+ flags &= ~Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
+ }
+ metadata.setFlags(flags);
+
+ final Builder builder = new Builder(getContext())
+ .setContentTitle("foo")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .setPriority(Notification.PRIORITY_HIGH)
+ .setDefaults(Notification.DEFAULT_SOUND)
+ .setBubbleMetadata(metadata);
+
+ Notification n = builder.build();
+ StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, mId, mTag, mUid,
+ mPid, n, mUser, null, System.currentTimeMillis());
+ NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
+ return r;
+ }
+
//
// Tests
//
@@ -154,6 +189,20 @@ public class BadgeExtractorTest extends UiServiceTestCase {
}
@Test
+ public void testHideNotifOverridesYes() throws Exception {
+ BadgeExtractor extractor = new BadgeExtractor();
+ extractor.setConfig(mConfig);
+
+ when(mConfig.badgingEnabled(mUser)).thenReturn(true);
+ when(mConfig.canShowBadge(mPkg, mUid)).thenReturn(true);
+ NotificationRecord r = getNotificationRecordWithBubble(/* suppressNotif */ true);
+
+ extractor.process(r);
+
+ assertFalse(r.canShowBadge());
+ }
+
+ @Test
public void testDndOverridesYes() {
BadgeExtractor extractor = new BadgeExtractor();
extractor.setConfig(mConfig);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 1d6f8233b7b4..622a203c5242 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -29,6 +29,16 @@ import static android.app.NotificationManager.IMPORTANCE_MAX;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+import static com.android.internal.util.FrameworkStatsLog.ANNOTATION_ID_IS_UID;
+import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES;
+import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.CHANNEL_ID_FIELD_NUMBER;
+import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.CHANNEL_NAME_FIELD_NUMBER;
+import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IMPORTANCE_FIELD_NUMBER;
+import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IS_CONVERSATION_FIELD_NUMBER;
+import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IS_DELETED_FIELD_NUMBER;
+import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IS_DEMOTED_CONVERSATION_FIELD_NUMBER;
+import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.IS_IMPORTANT_CONVERSATION_FIELD_NUMBER;
+import static com.android.os.AtomsProto.PackageNotificationChannelPreferences.UID_FIELD_NUMBER;
import static com.android.server.notification.PreferencesHelper.DEFAULT_BUBBLE_PREFERENCE;
import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_COUNT_LIMIT;
import static com.android.server.notification.PreferencesHelper.UNKNOWN_UID;
@@ -91,7 +101,6 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.util.FastXmlSerializer;
import com.android.server.UiServiceTestCase;
-
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Before;
@@ -110,6 +119,7 @@ import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -146,6 +156,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
private PreferencesHelper mHelper;
private AudioAttributes mAudioAttributes;
private NotificationChannelLoggerFake mLogger = new NotificationChannelLoggerFake();
+ private WrappedSysUiStatsEvent.WrappedBuilderFactory mStatsEventBuilderFactory;
@Before
public void setUp() throws Exception {
@@ -197,8 +208,11 @@ public class PreferencesHelperTest extends UiServiceTestCase {
when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
when(mAppOpsManager.noteOpNoThrow(anyInt(), anyInt(),
anyString(), eq(null), anyString())).thenReturn(MODE_DEFAULT);
+
+ mStatsEventBuilderFactory = new WrappedSysUiStatsEvent.WrappedBuilderFactory();
+
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
- mAppOpsManager);
+ mAppOpsManager, mStatsEventBuilderFactory);
resetZenModeHelper();
mAudioAttributes = new AudioAttributes.Builder()
@@ -1483,7 +1497,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
- mAppOpsManager);
+ mAppOpsManager, mStatsEventBuilderFactory);
assertFalse(mHelper.areChannelsBypassingDnd());
verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any());
resetZenModeHelper();
@@ -1495,7 +1509,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, 0, 0);
when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
- mAppOpsManager);
+ mAppOpsManager, mStatsEventBuilderFactory);
assertFalse(mHelper.areChannelsBypassingDnd());
verify(mMockZenModeHelper, never()).setNotificationPolicy(any());
resetZenModeHelper();
@@ -2262,7 +2276,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
+ "</package>\n"
+ "</ranking>\n";
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
- mAppOpsManager);
+ mAppOpsManager, mStatsEventBuilderFactory);
loadByteArrayXml(preQXml.getBytes(), true, UserHandle.USER_SYSTEM);
assertEquals(PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS,
@@ -2275,7 +2289,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
- mAppOpsManager);
+ mAppOpsManager, mStatsEventBuilderFactory);
loadStreamXml(baos, false, UserHandle.USER_ALL);
assertEquals(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS,
@@ -2372,7 +2386,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
- mAppOpsManager);
+ mAppOpsManager, mStatsEventBuilderFactory);
loadStreamXml(baos, false, UserHandle.USER_ALL);
assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
@@ -2384,7 +2398,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
- mAppOpsManager);
+ mAppOpsManager, mStatsEventBuilderFactory);
loadStreamXml(baos, false, UserHandle.USER_ALL);
assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
@@ -2397,7 +2411,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
- mAppOpsManager);
+ mAppOpsManager, mStatsEventBuilderFactory);
loadStreamXml(baos, false, UserHandle.USER_ALL);
assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
@@ -2410,7 +2424,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
- mAppOpsManager);
+ mAppOpsManager, mStatsEventBuilderFactory);
loadStreamXml(baos, false, UserHandle.USER_ALL);
// appears disabled
@@ -2429,7 +2443,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
- mAppOpsManager);
+ mAppOpsManager, mStatsEventBuilderFactory);
loadStreamXml(baos, false, UserHandle.USER_ALL);
// appears disabled
@@ -2448,7 +2462,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
- mAppOpsManager);
+ mAppOpsManager, mStatsEventBuilderFactory);
loadStreamXml(baos, false, UserHandle.USER_ALL);
assertEquals(BUBBLE_PREFERENCE_NONE, mHelper.getBubblePreference(PKG_O, UID_O));
@@ -2503,7 +2517,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
- mAppOpsManager);
+ mAppOpsManager, mStatsEventBuilderFactory);
loadStreamXml(baos, false, UserHandle.USER_ALL);
assertEquals(BUBBLE_PREFERENCE_SELECTED, mHelper.getBubblePreference(PKG_O, UID_O));
@@ -2540,7 +2554,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
- mAppOpsManager);
+ mAppOpsManager, mStatsEventBuilderFactory);
loadStreamXml(baos, false, UserHandle.USER_ALL);
assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE);
@@ -3019,31 +3033,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
PKG_O, UID_O, parent.getId(), conversationId, false, false), conversationId);
}
-
- @Test
- public void testPullConversationNotificationChannel() {
- String conversationId = "friend";
-
- NotificationChannel parent =
- new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT);
- mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false);
-
- String channelId = String.format(
- CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), conversationId);
- NotificationChannel friend = new NotificationChannel(channelId,
- "messages", IMPORTANCE_DEFAULT);
- friend.setConversationId(parent.getId(), conversationId);
- mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false);
- ArrayList<StatsEvent> events = new ArrayList<>();
- mHelper.pullPackageChannelPreferencesStats(events);
- boolean found = false;
- for (StatsEvent event : events) {
- // TODO(b/153195691): inspect the content once it is possible to do so
- found = true;
- }
- assertTrue("conversation was not in the pull", found);
- }
-
@Test
public void testGetNotificationChannel_conversationProvidedByNotCustomizedYet() {
String conversationId = "friend";
@@ -3077,7 +3066,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testPlaceholderConversationId_shortcutRequired() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
- mAppOpsManager);
+ mAppOpsManager, mStatsEventBuilderFactory);
final String xml = "<ranking version=\"1\">\n"
+ "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
@@ -3096,7 +3085,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testNormalConversationId_shortcutRequired() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
- mAppOpsManager);
+ mAppOpsManager, mStatsEventBuilderFactory);
final String xml = "<ranking version=\"1\">\n"
+ "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
@@ -3115,7 +3104,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testNoConversationId_shortcutRequired() throws Exception {
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger,
- mAppOpsManager);
+ mAppOpsManager, mStatsEventBuilderFactory);
final String xml = "<ranking version=\"1\">\n"
+ "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
@@ -3477,4 +3466,151 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.setValidMessageSent(PKG_P, UID_P);
assertFalse(mHelper.hasUserDemotedInvalidMsgApp(PKG_P, UID_P));
}
+
+ @Test
+ public void testPullPackageChannelPreferencesStats() {
+ String channelId = "parent";
+ String name = "messages";
+ NotificationChannel fodderA = new NotificationChannel("a", "a", IMPORTANCE_LOW);
+ mHelper.createNotificationChannel(PKG_O, UID_O, fodderA, true, false);
+ NotificationChannel channel =
+ new NotificationChannel(channelId, name, IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
+ NotificationChannel fodderB = new NotificationChannel("b", "b", IMPORTANCE_HIGH);
+ mHelper.createNotificationChannel(PKG_O, UID_O, fodderB, true, false);
+
+ ArrayList<StatsEvent> events = new ArrayList<>();
+ mHelper.pullPackageChannelPreferencesStats(events);
+
+ int found = 0;
+ for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
+ if (builder.getAtomId() == PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES
+ && channelId.equals(builder.getValue(CHANNEL_ID_FIELD_NUMBER))) {
+ ++found;
+ assertEquals("uid", UID_O, builder.getValue(UID_FIELD_NUMBER));
+ assertTrue("uid annotation", builder.getBooleanAnnotation(
+ UID_FIELD_NUMBER, ANNOTATION_ID_IS_UID));
+ assertEquals("importance", IMPORTANCE_DEFAULT, builder.getValue(
+ IMPORTANCE_FIELD_NUMBER));
+ assertEquals("name", name, builder.getValue(CHANNEL_NAME_FIELD_NUMBER));
+ assertFalse("isconv", builder.getBoolean(IS_CONVERSATION_FIELD_NUMBER));
+ assertFalse("deleted", builder.getBoolean(IS_DELETED_FIELD_NUMBER));
+ }
+ }
+ }
+
+ @Test
+ public void testPullPackageChannelPreferencesStats_one_to_one() {
+ NotificationChannel channelA = new NotificationChannel("a", "a", IMPORTANCE_LOW);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channelA, true, false);
+ NotificationChannel channelB = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channelB, true, false);
+ NotificationChannel channelC = new NotificationChannel("c", "c", IMPORTANCE_HIGH);
+ mHelper.createNotificationChannel(PKG_O, UID_O, channelC, true, false);
+
+ List<String> channels = new LinkedList<>(Arrays.asList("a", "b", "c"));
+
+ ArrayList<StatsEvent> events = new ArrayList<>();
+ mHelper.pullPackageChannelPreferencesStats(events);
+
+ int found = 0;
+ for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
+ if (builder.getAtomId() == PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES) {
+ Object id = builder.getValue(CHANNEL_ID_FIELD_NUMBER);
+ assertTrue("missing channel in the output", channels.contains(id));
+ channels.remove(id);
+ }
+ }
+ assertTrue("unexpected channel in output", channels.isEmpty());
+ }
+
+ @Test
+ public void testPullPackageChannelPreferencesStats_conversation() {
+ String conversationId = "friend";
+
+ NotificationChannel parent =
+ new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false);
+
+ String channelId = String.format(
+ CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), conversationId);
+ String name = "conversation";
+ NotificationChannel friend = new NotificationChannel(channelId,
+ name, IMPORTANCE_DEFAULT);
+ friend.setConversationId(parent.getId(), conversationId);
+ mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false);
+
+ ArrayList<StatsEvent> events = new ArrayList<>();
+ mHelper.pullPackageChannelPreferencesStats(events);
+
+ for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
+ if (builder.getAtomId() == PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES
+ && channelId.equals(builder.getValue(CHANNEL_ID_FIELD_NUMBER))) {
+ assertTrue("isConveration should be true", builder.getBoolean(
+ IS_CONVERSATION_FIELD_NUMBER));
+ assertFalse("not demoted", builder.getBoolean(
+ IS_DEMOTED_CONVERSATION_FIELD_NUMBER));
+ assertFalse("not important", builder.getBoolean(
+ IS_IMPORTANT_CONVERSATION_FIELD_NUMBER));
+ }
+ }
+ }
+
+ @Test
+ public void testPullPackageChannelPreferencesStats_conversation_demoted() {
+ NotificationChannel parent =
+ new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false);
+ String channelId = String.format(
+ CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), "friend");
+ NotificationChannel friend = new NotificationChannel(channelId,
+ "conversation", IMPORTANCE_DEFAULT);
+ friend.setConversationId(parent.getId(), "friend");
+ friend.setDemoted(true);
+ mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false);
+
+ ArrayList<StatsEvent> events = new ArrayList<>();
+ mHelper.pullPackageChannelPreferencesStats(events);
+
+ for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
+ if (builder.getAtomId() == PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES
+ && channelId.equals(builder.getValue(CHANNEL_ID_FIELD_NUMBER))) {
+ assertTrue("isConveration should be true", builder.getBoolean(
+ IS_CONVERSATION_FIELD_NUMBER));
+ assertTrue("is demoted", builder.getBoolean(
+ IS_DEMOTED_CONVERSATION_FIELD_NUMBER));
+ assertFalse("not important", builder.getBoolean(
+ IS_IMPORTANT_CONVERSATION_FIELD_NUMBER));
+ }
+ }
+ }
+
+ @Test
+ public void testPullPackageChannelPreferencesStats_conversation_priority() {
+ NotificationChannel parent =
+ new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false);
+ String channelId = String.format(
+ CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), "friend");
+ NotificationChannel friend = new NotificationChannel(channelId,
+ "conversation", IMPORTANCE_DEFAULT);
+ friend.setConversationId(parent.getId(), "friend");
+ friend.setImportantConversation(true);
+ mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false);
+
+ ArrayList<StatsEvent> events = new ArrayList<>();
+ mHelper.pullPackageChannelPreferencesStats(events);
+
+ for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
+ if (builder.getAtomId() == PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES
+ && channelId.equals(builder.getValue(CHANNEL_ID_FIELD_NUMBER))) {
+ assertTrue("isConveration should be true", builder.getBoolean(
+ IS_CONVERSATION_FIELD_NUMBER));
+ assertFalse("not demoted", builder.getBoolean(
+ IS_DEMOTED_CONVERSATION_FIELD_NUMBER));
+ assertTrue("is important", builder.getBoolean(
+ IS_IMPORTANT_CONVERSATION_FIELD_NUMBER));
+ }
+ }
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java b/services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java
new file mode 100644
index 000000000000..f4f64d779d30
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+import android.util.StatsEvent;
+
+import com.android.server.notification.SysUiStatsEvent.Builder;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Wrapper for SysUiStatsEvent that implements validation.
+ */
+public class WrappedSysUiStatsEvent {
+
+ static class WrappedBuilder extends Builder {
+ private ArrayList<Object> mValues;
+ private HashMap<Integer, HashMap<Byte, Object>> mAnnotations;
+ private int mAtomId;
+ private int mLastIndex;
+ private boolean mBuilt;
+
+ WrappedBuilder(StatsEvent.Builder builder) {
+ super(builder);
+ mValues = new ArrayList<>();
+ mAnnotations = new HashMap<>();
+ mValues.add(0); // proto fields are 1-based
+ }
+
+ @Override
+ public Builder setAtomId(int atomId) {
+ mAtomId = atomId;
+ super.setAtomId(atomId);
+ return this;
+ }
+
+ @Override
+ public Builder writeInt(int value) {
+ addValue(Integer.valueOf(value));
+ super.writeInt(value);
+ return this;
+ }
+
+ @Override
+ public Builder addBooleanAnnotation(byte annotation, boolean value) {
+ addAnnotation(annotation, Boolean.valueOf(value));
+ super.addBooleanAnnotation(annotation, value);
+ return this;
+ }
+
+ @Override
+ public Builder writeString(String value) {
+ addValue(value);
+ super.writeString(value);
+ return this;
+ }
+
+ @Override
+ public Builder writeBoolean(boolean value) {
+ addValue(Boolean.valueOf(value));
+ super.writeBoolean(value);
+ return this;
+ }
+
+ @Override
+ public StatsEvent build() {
+ mBuilt = true;
+ return super.build();
+ }
+
+ public Object getValue(int index) {
+ return index < mValues.size() ? mValues.get(index) : null;
+ }
+
+ /** useful to make assertTrue() statemetns more readable. */
+ public boolean getBoolean(int index) {
+ return (Boolean) mValues.get(index);
+ }
+
+ private void addValue(Object value) {
+ mLastIndex = mValues.size();
+ mValues.add(value);
+ }
+
+ private void addAnnotation(byte annotation, Object value) {
+ Integer key = Integer.valueOf(mLastIndex);
+ if (!mAnnotations.containsKey(key)) {
+ mAnnotations.put(key, new HashMap<>());
+ }
+ mAnnotations.get(key).put(Byte.valueOf(annotation), value);
+ }
+
+ public boolean getBooleanAnnotation(int i, byte a) {
+ return ((Boolean) mAnnotations.get(Integer.valueOf(i)).get(Byte.valueOf(a)))
+ .booleanValue();
+ }
+
+ public int getAtomId() {
+ return mAtomId;
+ }
+ }
+
+ static class WrappedBuilderFactory extends SysUiStatsEvent.BuilderFactory {
+ public List<WrappedBuilder> builders;
+
+ WrappedBuilderFactory() {
+ builders = new ArrayList<>();
+ }
+
+ @Override
+ Builder newBuilder() {
+ WrappedBuilder b = new WrappedBuilder(StatsEvent.newBuilder());
+ builders.add(b);
+ return b;
+ }
+ }
+}
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index f382fbae9280..30df0d4b4ad9 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -62,6 +62,7 @@
android:resumeWhilePausing="true"/>
<activity android:name="com.android.server.wm.ScreenDecorWindowTests$TestActivity"
android:showWhenLocked="true" android:allowEmbedded="true"/>
+ <activity android:name="com.android.server.wm.ActivityLeakTests$DetectLeakActivity" />
</application>
<instrumentation
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityLeakTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityLeakTests.java
new file mode 100644
index 000000000000..bd6ac58c2445
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityLeakTests.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static org.junit.Assert.assertFalse;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Debug;
+import android.os.StrictMode;
+import android.os.strictmode.InstanceCountViolation;
+import android.util.Log;
+
+import org.junit.After;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for Activity leaks.
+ *
+ * Build/Install/Run:
+ * atest WmTests:ActivityLeakTests
+ */
+public class ActivityLeakTests {
+
+ private final Instrumentation mInstrumentation = getInstrumentation();
+ private final Context mContext = mInstrumentation.getTargetContext();
+ private final List<Activity> mStartedActivityList = new ArrayList<>();
+
+ @After
+ public void tearDown() {
+ mInstrumentation.runOnMainSync(() -> {
+ // Reset strict mode.
+ StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().build());
+ });
+ for (Activity activity : mStartedActivityList) {
+ if (!activity.isDestroyed()) {
+ activity.finish();
+ }
+ }
+ mStartedActivityList.clear();
+ }
+
+ @Test
+ public void testActivityLeak() {
+ final Bundle intentExtras = new Bundle();
+ intentExtras.putBoolean(DetectLeakActivity.ENABLE_STRICT_MODE, true);
+ final DetectLeakActivity activity = (DetectLeakActivity) startActivity(
+ DetectLeakActivity.class, 0 /* flags */, intentExtras);
+ mStartedActivityList.add(activity);
+
+ activity.finish();
+
+ assertFalse("Leak found on activity", activity.isLeakedAfterDestroy());
+ }
+
+ @Test
+ public void testActivityLeakForTwoInstances() {
+ final Bundle intentExtras = new Bundle();
+
+ // Launch an activity, then enable strict mode
+ intentExtras.putBoolean(DetectLeakActivity.ENABLE_STRICT_MODE, true);
+ final DetectLeakActivity activity1 = (DetectLeakActivity) startActivity(
+ DetectLeakActivity.class, 0 /* flags */, intentExtras);
+ mStartedActivityList.add(activity1);
+
+ // Launch second activity instance.
+ intentExtras.putBoolean(DetectLeakActivity.ENABLE_STRICT_MODE, false);
+ final DetectLeakActivity activity2 = (DetectLeakActivity) startActivity(
+ DetectLeakActivity.class,
+ FLAG_ACTIVITY_MULTIPLE_TASK | FLAG_ACTIVITY_NEW_DOCUMENT, intentExtras);
+ mStartedActivityList.add(activity2);
+
+ // Destroy the activity
+ activity1.finish();
+ assertFalse("Leak found on activity 1", activity1.isLeakedAfterDestroy());
+
+ activity2.finish();
+ assertFalse("Leak found on activity 2", activity2.isLeakedAfterDestroy());
+ }
+
+ private Activity startActivity(Class<?> cls, int flags, Bundle extras) {
+ final Intent intent = new Intent(mContext, cls);
+ intent.addFlags(flags | FLAG_ACTIVITY_NEW_TASK);
+ if (extras != null) {
+ intent.putExtras(extras);
+ }
+ return mInstrumentation.startActivitySync(intent);
+ }
+
+ public static class DetectLeakActivity extends Activity {
+
+ private static final String TAG = "DetectLeakActivity";
+
+ public static final String ENABLE_STRICT_MODE = "enable_strict_mode";
+
+ private volatile boolean mWasDestroyed;
+ private volatile boolean mIsLeaked;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getIntent().getBooleanExtra(ENABLE_STRICT_MODE, false)) {
+ enableStrictMode();
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ getWindow().getDecorView().post(() -> {
+ synchronized (this) {
+ mWasDestroyed = true;
+ notifyAll();
+ }
+ });
+ }
+
+ public boolean isLeakedAfterDestroy() {
+ synchronized (this) {
+ while (!mWasDestroyed && !mIsLeaked) {
+ try {
+ wait(5000 /* timeoutMs */);
+ } catch (InterruptedException ignored) {
+ }
+ }
+ }
+ return mIsLeaked;
+ }
+
+ private void enableStrictMode() {
+ StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
+ .detectActivityLeaks()
+ .penaltyLog()
+ .penaltyListener(Runnable::run, violation -> {
+ if (!(violation instanceof InstanceCountViolation)) {
+ return;
+ }
+ synchronized (this) {
+ mIsLeaked = true;
+ notifyAll();
+ }
+ Log.w(TAG, violation.toString() + ", " + dumpHprofData());
+ })
+ .build());
+ }
+
+ private String dumpHprofData() {
+ try {
+ final String fileName = getDataDir().getPath() + "/ActivityLeakHeapDump.hprof";
+ Debug.dumpHprofData(fileName);
+ return "memory dump filename: " + fileName;
+ } catch (Throwable e) {
+ Log.e(TAG, "dumpHprofData failed", e);
+ return "failed to save memory dump";
+ }
+ }
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 36d4888fa56e..02de408343c5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -295,6 +296,27 @@ public class AppWindowTokenTests extends WindowTestsBase {
}
@Test
+ public void testRespectTopFullscreenOrientation() {
+ final Configuration displayConfig = mActivity.mDisplayContent.getConfiguration();
+ final Configuration activityConfig = mActivity.getConfiguration();
+ mActivity.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
+
+ assertEquals(Configuration.ORIENTATION_PORTRAIT, displayConfig.orientation);
+ assertEquals(Configuration.ORIENTATION_PORTRAIT, activityConfig.orientation);
+
+ final ActivityRecord topActivity = WindowTestUtils.createTestActivityRecord(mStack);
+ topActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+
+ assertEquals(Configuration.ORIENTATION_LANDSCAPE, displayConfig.orientation);
+ // Although the activity requested portrait, it is not the top activity that determines
+ // the display orientation. So it should be able to inherit the orientation from parent.
+ // Otherwise its configuration will be inconsistent that its orientation is portrait but
+ // other screen configurations are in landscape, e.g. screenWidthDp, screenHeightDp, and
+ // window configuration.
+ assertEquals(Configuration.ORIENTATION_LANDSCAPE, activityConfig.orientation);
+ }
+
+ @Test
public void testReportOrientationChange() {
mActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
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 7197ce9c22aa..4ad7dff87072 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -16,7 +16,10 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -73,6 +76,8 @@ import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import android.annotation.SuppressLint;
@@ -1168,6 +1173,57 @@ public class DisplayContentTests extends WindowTestsBase {
}
@Test
+ public void testNoFixedRotationWithPip() {
+ mWm.mIsFixedRotationTransformEnabled = true;
+ // Make resume-top really update the activity state.
+ doReturn(false).when(mWm.mAtmService).isBooting();
+ doReturn(true).when(mWm.mAtmService).isBooted();
+ // Speed up the test by a few seconds.
+ mWm.mAtmService.deferWindowLayout();
+ doNothing().when(mWm).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt());
+
+ final DisplayContent displayContent = mWm.mRoot.getDefaultDisplay();
+ final Configuration displayConfig = displayContent.getConfiguration();
+ final ActivityRecord pinnedActivity = createActivityRecord(displayContent,
+ WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD);
+ final Task pinnedTask = pinnedActivity.getRootTask();
+ final ActivityRecord homeActivity = WindowTestUtils.createTestActivityRecord(
+ displayContent.getDefaultTaskDisplayArea().getOrCreateRootHomeTask());
+ if (displayConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
+ homeActivity.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
+ pinnedActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+ } else {
+ homeActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+ pinnedActivity.setOrientation(SCREEN_ORIENTATION_PORTRAIT);
+ }
+ final int homeConfigOrientation = homeActivity.getRequestedConfigurationOrientation();
+ final int pinnedConfigOrientation = pinnedActivity.getRequestedConfigurationOrientation();
+
+ assertEquals(homeConfigOrientation, displayConfig.orientation);
+
+ clearInvocations(mWm);
+ // Leave PiP to fullscreen. The orientation can be updated from
+ // ActivityRecord#reportDescendantOrientationChangeIfNeeded.
+ pinnedTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ homeActivity.setState(ActivityStack.ActivityState.STOPPED, "test");
+
+ assertFalse(displayContent.hasTopFixedRotationLaunchingApp());
+ verify(mWm, atLeastOnce()).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt());
+ assertEquals(pinnedConfigOrientation, displayConfig.orientation);
+ assertFalse(displayContent.getPinnedStackController().isPipActiveOrWindowingModeChanging());
+
+ clearInvocations(mWm);
+ // Enter PiP from fullscreen. The orientation can be updated from
+ // ensure-visibility/resume-focused-stack -> ActivityRecord#makeActiveIfNeeded -> resume.
+ pinnedTask.setWindowingMode(WINDOWING_MODE_PINNED);
+
+ assertFalse(displayContent.hasTopFixedRotationLaunchingApp());
+ verify(mWm, atLeastOnce()).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt());
+ assertEquals(homeConfigOrientation, displayConfig.orientation);
+ assertTrue(displayContent.getPinnedStackController().isPipActiveOrWindowingModeChanging());
+ }
+
+ @Test
public void testRemoteRotation() {
DisplayContent dc = createNewDisplay();
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 68bc58493f13..665cf83cd33c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -145,7 +145,8 @@ public class SizeCompatTests extends ActivityTestsBase {
final Rect appBounds = mActivity.getWindowConfiguration().getAppBounds();
// The parent configuration doesn't change since the first resolved configuration, so the
- // activity should fit in the parent naturally. (size=583x700).
+ // activity should fit in the parent naturally (size=583x700, appBounds=[9, 100 - 592, 800],
+ // horizontal offset = round((600 - 583) / 2) = 9)).
assertFitted();
final int offsetX = (int) ((1f + displayBounds.width() - appBounds.width()) / 2);
// The bounds must be horizontal centered.
@@ -160,7 +161,7 @@ public class SizeCompatTests extends ActivityTestsBase {
assertFitted();
// After the orientation of activity is changed, even display is not rotated, the aspect
- // ratio should be the same (appBounds=[9, 100 - 592, 800], x-offset=round((600-583)/2)=9).
+ // ratio should be the same (bounds=[0, 0 - 600, 600], appBounds=[0, 100 - 600, 600]).
assertEquals(appBounds.width(), appBounds.height() * aspectRatio, 0.5f /* delta */);
// The notch is still on top.
assertEquals(mActivity.getBounds().height(), appBounds.height() + notchHeight);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index cf07221917cc..9621f68f9d6c 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -73,6 +73,7 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IVoiceActionCheckCallback;
import com.android.internal.app.IVoiceInteractionManagerService;
import com.android.internal.app.IVoiceInteractionSessionListener;
@@ -230,6 +231,10 @@ public class VoiceInteractionManagerService extends SystemService {
private int mCurUser;
private boolean mCurUserUnlocked;
private boolean mCurUserSupported;
+
+ @GuardedBy("this")
+ private boolean mTemporarilyDisabled;
+
private final boolean mEnableService;
VoiceInteractionManagerServiceStub() {
@@ -316,8 +321,12 @@ public class VoiceInteractionManagerService extends SystemService {
Settings.Secure.VOICE_INTERACTION_SERVICE, userHandle);
ComponentName curRecognizer = getCurRecognizer(userHandle);
VoiceInteractionServiceInfo curInteractorInfo = null;
- if (DEBUG) Slog.d(TAG, "curInteractorStr=" + curInteractorStr
- + " curRecognizer=" + curRecognizer);
+ if (DEBUG) {
+ Slog.d(TAG, "curInteractorStr=" + curInteractorStr
+ + " curRecognizer=" + curRecognizer
+ + " mEnableService=" + mEnableService
+ + " mTemporarilyDisabled=" + mTemporarilyDisabled);
+ }
if (curInteractorStr == null && curRecognizer != null && mEnableService) {
// If there is no interactor setting, that means we are upgrading
// from an older platform version. If the current recognizer is not
@@ -472,10 +481,11 @@ public class VoiceInteractionManagerService extends SystemService {
}
void switchImplementationIfNeededLocked(boolean force) {
- if (!mCurUserSupported) {
+ if (!mCurUserSupported || mTemporarilyDisabled) {
if (DEBUG_USER) {
- Slog.d(TAG, "switchImplementationIfNeeded(): skipping on unsuported user "
- + mCurUser);
+ Slog.d(TAG, "switchImplementationIfNeeded(): skipping: force= " + force
+ + "mCurUserSupported=" + mCurUserSupported
+ + "mTemporarilyDisabled=" + mTemporarilyDisabled);
}
if (mImpl != null) {
mImpl.shutdownLocked();
@@ -928,6 +938,25 @@ public class VoiceInteractionManagerService extends SystemService {
}
}
+ @Override
+ public void setDisabled(boolean disabled) {
+ enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
+ synchronized (this) {
+ if (mTemporarilyDisabled == disabled) {
+ if (DEBUG) Slog.d(TAG, "setDisabled(): already " + disabled);
+ return;
+ }
+ Slog.i(TAG, "setDisabled(): changing to " + disabled);
+ final long caller = Binder.clearCallingIdentity();
+ try {
+ mTemporarilyDisabled = disabled;
+ switchImplementationIfNeeded(/* force= */ false);
+ } finally {
+ Binder.restoreCallingIdentity(caller);
+ }
+ }
+ }
+
//----------------- Model management APIs --------------------------------//
@Override
@@ -1378,6 +1407,7 @@ public class VoiceInteractionManagerService extends SystemService {
synchronized (this) {
pw.println("VOICE INTERACTION MANAGER (dumpsys voiceinteraction)");
pw.println(" mEnableService: " + mEnableService);
+ pw.println(" mTemporarilyDisabled: " + mTemporarilyDisabled);
pw.println(" mCurUser: " + mCurUser);
pw.println(" mCurUserUnlocked: " + mCurUserUnlocked);
pw.println(" mCurUserSupported: " + mCurUserSupported);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java
index 3f4ddb6846ab..6c355a3b4b30 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java
@@ -52,6 +52,8 @@ final class VoiceInteractionManagerServiceShellCommand extends ShellCommand {
return requestShow(pw);
case "hide":
return requestHide(pw);
+ case "disable":
+ return requestDisable(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -69,6 +71,8 @@ final class VoiceInteractionManagerServiceShellCommand extends ShellCommand {
pw.println("");
pw.println(" hide");
pw.println(" Hides the current session");
+ pw.println(" disable [true|false]");
+ pw.println(" Temporarily disable (when true) service");
pw.println("");
}
}
@@ -127,6 +131,17 @@ final class VoiceInteractionManagerServiceShellCommand extends ShellCommand {
return 0;
}
+ private int requestDisable(PrintWriter pw) {
+ boolean disabled = Boolean.parseBoolean(getNextArgRequired());
+ Slog.i(TAG, "requestDisable(): " + disabled);
+ try {
+ mService.setDisabled(disabled);
+ } catch (Exception e) {
+ return handleError(pw, "requestDisable()", e);
+ }
+ return 0;
+ }
+
private static int handleError(PrintWriter pw, String message, Exception e) {
Slog.e(TAG, "error calling " + message, e);
pw.printf("Error calling %s: %s\n", message, e);
diff --git a/telephony/java/android/telephony/SmsCbMessage.java b/telephony/java/android/telephony/SmsCbMessage.java
index 752707e5a5dc..d366efe0d979 100644
--- a/telephony/java/android/telephony/SmsCbMessage.java
+++ b/telephony/java/android/telephony/SmsCbMessage.java
@@ -594,6 +594,7 @@ public final class SmsCbMessage implements Parcelable {
SmsCbEtwsInfo etwsInfo = getEtwsWarningInfo();
if (etwsInfo != null) {
cv.put(CellBroadcasts.ETWS_WARNING_TYPE, etwsInfo.getWarningType());
+ cv.put(CellBroadcasts.ETWS_IS_PRIMARY, etwsInfo.isPrimary());
}
SmsCbCmasInfo cmasInfo = getCmasWarningInfo();
@@ -667,9 +668,12 @@ public final class SmsCbMessage implements Parcelable {
SmsCbEtwsInfo etwsInfo;
int etwsWarningTypeColumn = cursor.getColumnIndex(CellBroadcasts.ETWS_WARNING_TYPE);
- if (etwsWarningTypeColumn != -1 && !cursor.isNull(etwsWarningTypeColumn)) {
+ int etwsIsPrimaryColumn = cursor.getColumnIndex(CellBroadcasts.ETWS_IS_PRIMARY);
+ if (etwsWarningTypeColumn != -1 && !cursor.isNull(etwsWarningTypeColumn)
+ && etwsIsPrimaryColumn != -1 && !cursor.isNull(etwsIsPrimaryColumn)) {
int warningType = cursor.getInt(etwsWarningTypeColumn);
- etwsInfo = new SmsCbEtwsInfo(warningType, false, false, false, null);
+ boolean isPrimary = cursor.getInt(etwsIsPrimaryColumn) != 0;
+ etwsInfo = new SmsCbEtwsInfo(warningType, false, false, isPrimary, null);
} else {
etwsInfo = null;
}
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index d011dbbbe5db..ae93a81f274e 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -1113,6 +1113,7 @@ public class PackageWatchdogTest {
mTestLooper.dispatchAll();
List<Set> expectedSyncRequests = List.of(
+ Set.of(),
Set.of(APP_A),
Set.of(APP_A, APP_B),
Set.of(APP_A, APP_B, APP_C),
diff --git a/tests/RollbackTest/MultiUserRollbackTest.xml b/tests/RollbackTest/MultiUserRollbackTest.xml
index ba86c3ff6777..2f62af1856da 100644
--- a/tests/RollbackTest/MultiUserRollbackTest.xml
+++ b/tests/RollbackTest/MultiUserRollbackTest.xml
@@ -15,6 +15,12 @@
-->
<configuration description="Runs rollback tests for multiple users">
<option name="test-suite-tag" value="MultiUserRollbackTest" />
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
+ <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+ <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
+ <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+ </target_preparer>
<test class="com.android.tradefed.testtype.HostTest" >
<option name="class" value="com.android.tests.rollback.host.MultiUserRollbackTest" />
</test>
diff --git a/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
index a4c81d577522..42b886f0774f 100644
--- a/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
+++ b/tests/RollbackTest/MultiUserRollbackTest/src/com/android/tests/rollback/host/MultiUserRollbackTest.java
@@ -40,23 +40,18 @@ public class MultiUserRollbackTest extends BaseHostJUnit4Test {
private static final long SWITCH_USER_COMPLETED_NUMBER_OF_POLLS = 60;
private static final long SWITCH_USER_COMPLETED_POLL_INTERVAL_IN_MILLIS = 1000;
- private void cleanUp() throws Exception {
- getDevice().executeShellCommand("pm rollback-app com.android.cts.install.lib.testapp.A");
- getDevice().executeShellCommand("pm uninstall com.android.cts.install.lib.testapp.A");
- }
-
@After
public void tearDown() throws Exception {
- cleanUp();
removeSecondaryUserIfNecessary();
+ runPhaseForUsers("cleanUp", mOriginalUserId);
}
@Before
public void setup() throws Exception {
- cleanUp();
mOriginalUserId = getDevice().getCurrentUser();
createAndStartSecondaryUser();
installPackage("RollbackTest.apk", "--user all");
+ runPhaseForUsers("cleanUp", mOriginalUserId);
}
@Test
diff --git a/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java b/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
index 57c52f9c3021..61d7c763e8d7 100644
--- a/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
+++ b/tests/RollbackTest/NetworkStagedRollbackTest/src/com/android/tests/rollback/host/NetworkStagedRollbackTest.java
@@ -59,12 +59,14 @@ public class NetworkStagedRollbackTest extends BaseHostJUnit4Test {
@Before
public void setUp() throws Exception {
+ runPhase("cleanUp");
mLogger.start(getDevice());
}
@After
public void tearDown() throws Exception {
mLogger.stop();
+ runPhase("cleanUp");
}
/**
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
index 400bb04f0fab..8641f4d4013a 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/MultiUserRollbackTest.java
@@ -22,6 +22,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.Manifest;
import android.content.rollback.RollbackInfo;
+import android.content.rollback.RollbackManager;
import com.android.cts.install.lib.Install;
import com.android.cts.install.lib.InstallUtils;
@@ -54,6 +55,17 @@ public class MultiUserRollbackTest {
}
@Test
+ public void cleanUp() {
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ rm.getAvailableRollbacks().stream().flatMap(info -> info.getPackages().stream())
+ .map(info -> info.getPackageName()).forEach(rm::expireRollbackForPackage);
+ rm.getRecentlyCommittedRollbacks().stream().flatMap(info -> info.getPackages().stream())
+ .map(info -> info.getPackageName()).forEach(rm::expireRollbackForPackage);
+ assertThat(rm.getAvailableRollbacks()).isEmpty();
+ assertThat(rm.getRecentlyCommittedRollbacks()).isEmpty();
+ }
+
+ @Test
public void testBasic() throws Exception {
new RollbackTest().testBasic();
}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java
index 8fb59c7c3e2c..42b0c608822e 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/NetworkStagedRollbackTest.java
@@ -19,6 +19,8 @@ package com.android.tests.rollback;
import static com.android.cts.rollback.lib.RollbackInfoSubject.assertThat;
import static com.android.cts.rollback.lib.RollbackUtils.getUniqueRollbackInfoForPackage;
+import static com.google.common.truth.Truth.assertThat;
+
import android.Manifest;
import android.content.ComponentName;
import android.content.Intent;
@@ -91,14 +93,23 @@ public class NetworkStagedRollbackTest {
}
@Test
+ public void cleanUp() {
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ rm.getAvailableRollbacks().stream().flatMap(info -> info.getPackages().stream())
+ .map(info -> info.getPackageName()).forEach(rm::expireRollbackForPackage);
+ rm.getRecentlyCommittedRollbacks().stream().flatMap(info -> info.getPackages().stream())
+ .map(info -> info.getPackageName()).forEach(rm::expireRollbackForPackage);
+ assertThat(rm.getAvailableRollbacks()).isEmpty();
+ assertThat(rm.getRecentlyCommittedRollbacks()).isEmpty();
+ uninstallNetworkStackPackage();
+ }
+
+ @Test
public void testNetworkFailedRollback_Phase1() throws Exception {
// Remove available rollbacks and uninstall NetworkStack on /data/
RollbackManager rm = RollbackUtils.getRollbackManager();
String networkStack = getNetworkStackPackageName();
- rm.expireRollbackForPackage(networkStack);
- uninstallNetworkStackPackage();
-
assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
networkStack)).isNull();
@@ -153,9 +164,6 @@ public class NetworkStagedRollbackTest {
RollbackManager rm = RollbackUtils.getRollbackManager();
String networkStack = getNetworkStackPackageName();
- rm.expireRollbackForPackage(networkStack);
- uninstallNetworkStackPackage();
-
assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
networkStack)).isNull();
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 48b5bed609d1..dd08771b220d 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -48,6 +48,8 @@ import com.android.cts.rollback.lib.Rollback;
import com.android.cts.rollback.lib.RollbackBroadcastReceiver;
import com.android.cts.rollback.lib.RollbackUtils;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -81,6 +83,21 @@ public class RollbackTest {
pri -> packageName.equals(pri.getPackageName())));
}
+ @Before
+ @After
+ public void cleanUp() {
+ try {
+ InstallUtils.adoptShellPermissionIdentity(Manifest.permission.TEST_MANAGE_ROLLBACKS);
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ rm.getAvailableRollbacks().stream().flatMap(info -> info.getPackages().stream())
+ .map(info -> info.getPackageName()).forEach(rm::expireRollbackForPackage);
+ rm.getRecentlyCommittedRollbacks().stream().flatMap(info -> info.getPackages().stream())
+ .map(info -> info.getPackageName()).forEach(rm::expireRollbackForPackage);
+ } finally {
+ InstallUtils.dropShellPermissionIdentity();
+ }
+ }
+
/**
* Test basic rollbacks.
*/
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 6c9ffe2a7fac..00bd4cf388ce 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -360,7 +360,10 @@ public class StagedRollbackTest {
RollbackManager rm = RollbackUtils.getRollbackManager();
rm.getAvailableRollbacks().stream().flatMap(info -> info.getPackages().stream())
.map(info -> info.getPackageName()).forEach(rm::expireRollbackForPackage);
- assertThat(RollbackUtils.getRollbackManager().getAvailableRollbacks()).isEmpty();
+ rm.getRecentlyCommittedRollbacks().stream().flatMap(info -> info.getPackages().stream())
+ .map(info -> info.getPackageName()).forEach(rm::expireRollbackForPackage);
+ assertThat(rm.getAvailableRollbacks()).isEmpty();
+ assertThat(rm.getRecentlyCommittedRollbacks()).isEmpty();
}
private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test";
diff --git a/tests/RollbackTest/StagedRollbackTest.xml b/tests/RollbackTest/StagedRollbackTest.xml
index 2750d3765c20..83fef8e0a04b 100644
--- a/tests/RollbackTest/StagedRollbackTest.xml
+++ b/tests/RollbackTest/StagedRollbackTest.xml
@@ -19,6 +19,12 @@
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="RollbackTest.apk" />
</target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
+ <option name="run-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+ <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.A" />
+ <option name="teardown-command" value="pm uninstall com.android.cts.install.lib.testapp.B" />
+ </target_preparer>
<test class="com.android.tradefed.testtype.HostTest" >
<option name="class" value="com.android.tests.rollback.host.StagedRollbackTest" />
</test>
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 1eb7d95f381a..439f231193df 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -252,29 +252,6 @@ class ValueBodyPrinter : public ConstValueVisitor {
Printer* printer_;
};
-std::string OverlayablePoliciesToString(PolicyFlags policies) {
- std::string str;
-
- uint32_t remaining = policies;
- for (auto const& policy : kPolicyStringToFlag) {
- if ((policies & policy.second) != policy.second) {
- continue;
- }
- if (!str.empty()) {
- str.append("|");
- }
- str.append(policy.first.data());
- remaining &= ~policy.second;
- }
- if (remaining != 0) {
- if (!str.empty()) {
- str.append("|");
- }
- str.append(StringPrintf("0x%08x", remaining));
- }
- return !str.empty() ? str : "none";
-}
-
} // namespace
void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options,
@@ -575,7 +552,7 @@ void Debug::DumpOverlayable(const ResourceTable& table, text::Printer* printer)
overlayable_item.overlayable->name.c_str(),
overlayable_item.overlayable->actor.c_str());
const auto policy_subsection = StringPrintf(R"(policies="%s")",
- OverlayablePoliciesToString(overlayable_item.policies).c_str());
+ android::idmap2::policy::PoliciesToDebugString(overlayable_item.policies).c_str());
const auto value =
StringPrintf("%s/%s", to_string(type->type).data(), entry->name.c_str());
items.push_back(DumpOverlayableEntry{overlayable_section, policy_subsection, value});
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 0df578f2216b..9c5b7b66f2a3 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -111,11 +111,6 @@ java_sdk_library {
":framework-wifi-util-lib-aidls",
],
- // TODO(b/155480189) - Remove naming_scheme once references have been resolved.
- // Temporary java_sdk_library component naming scheme to use to ease the transition from separate
- // modules to java_sdk_library.
- naming_scheme: "framework-modules",
-
jarjar_rules: ":wifi-jarjar-rules",
installable: true,
@@ -140,7 +135,6 @@ java_sdk_library {
permitted_packages: [
"android.hardware.wifi",
"android.net.wifi",
- "android.x.net.wifi",
// Created by jarjar rules.
"com.android.wifi.x",
],
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 70c5e72e4e0c..b841921355e9 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -632,7 +632,6 @@ public class WifiInfo implements Parcelable {
/**
* @hide
- * TODO: makes real freq boundaries
*/
public boolean is24GHz() {
return ScanResult.is24GHz(mFrequency);
@@ -640,7 +639,6 @@ public class WifiInfo implements Parcelable {
/**
* @hide
- * TODO: makes real freq boundaries
*/
@UnsupportedAppUsage
public boolean is5GHz() {
@@ -648,6 +646,13 @@ public class WifiInfo implements Parcelable {
}
/**
+ * @hide
+ */
+ public boolean is6GHz() {
+ return ScanResult.is6GHz(mFrequency);
+ }
+
+ /**
* Record the MAC address of the WLAN interface
* @param macAddress the MAC address in {@code XX:XX:XX:XX:XX:XX} form
* @hide