summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java11
-rw-r--r--api/current.txt19
-rw-r--r--api/system-current.txt19
-rw-r--r--api/test-current.txt20
-rw-r--r--cmds/statsd/Android.mk106
-rw-r--r--cmds/statsd/src/LogEntryPrinter.cpp61
-rw-r--r--cmds/statsd/src/LogEntryPrinter.h54
-rw-r--r--cmds/statsd/src/LogReader.cpp143
-rw-r--r--cmds/statsd/src/LogReader.h81
-rw-r--r--cmds/statsd/src/StatsService.cpp76
-rw-r--r--cmds/statsd/src/StatsService.h44
-rw-r--r--cmds/statsd/src/main.cpp144
-rw-r--r--cmds/statsd/statsd.rc16
-rw-r--r--cmds/statsd/tests/LogReader_test.cpp24
-rw-r--r--core/java/android/app/ActivityManager.java205
-rw-r--r--core/java/android/app/ActivityManagerInternal.java6
-rw-r--r--core/java/android/app/IActivityManager.aidl1
-rw-r--r--core/java/android/app/INotificationManager.aidl3
-rw-r--r--core/java/android/app/Notification.java7
-rw-r--r--core/java/android/app/NotificationChannel.java38
-rw-r--r--core/java/android/app/NotificationChannelGroup.java121
-rw-r--r--core/java/android/app/NotificationManager.java5
-rw-r--r--core/java/android/app/ResourcesManager.java2
-rw-r--r--core/java/android/app/WallpaperManager.java5
-rw-r--r--core/java/android/app/WindowConfiguration.java76
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java75
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl3
-rw-r--r--core/java/android/app/usage/NetworkStats.java4
-rw-r--r--core/java/android/app/usage/NetworkStatsManager.java45
-rw-r--r--core/java/android/appwidget/AppWidgetHostView.java5
-rw-r--r--core/java/android/content/pm/ActivityInfo.java8
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java14
-rw-r--r--core/java/android/content/pm/ComponentInfo.java8
-rw-r--r--core/java/android/content/pm/ProviderInfo.java4
-rw-r--r--core/java/android/content/pm/ResolveInfo.java8
-rw-r--r--core/java/android/content/pm/ServiceInfo.java6
-rw-r--r--core/java/android/database/DatabaseUtils.java6
-rw-r--r--core/java/android/hardware/fingerprint/FingerprintManager.java7
-rw-r--r--core/java/android/net/INetworkStatsService.aidl2
-rw-r--r--core/java/android/net/NetworkStatsHistory.java19
-rw-r--r--core/java/android/net/NetworkTemplate.java4
-rw-r--r--core/java/android/os/Build.java5
-rw-r--r--core/java/android/os/IStatsManager.aidl28
-rw-r--r--core/java/android/os/StrictMode.java1241
-rw-r--r--core/java/android/os/SystemProperties.java80
-rw-r--r--core/java/android/os/VibrationEffect.java52
-rwxr-xr-xcore/java/android/provider/Settings.java43
-rw-r--r--core/java/android/service/autofill/AutofillServiceInfo.java9
-rw-r--r--core/java/android/service/autofill/FillEventHistory.java27
-rw-r--r--core/java/android/service/autofill/FillResponse.java2
-rw-r--r--core/java/android/text/StaticLayout.java6
-rw-r--r--core/java/android/util/ExceptionUtils.java8
-rw-r--r--core/java/android/util/IconDrawableFactory.java11
-rw-r--r--core/java/android/util/StatsLog.java76
-rw-r--r--core/java/android/view/View.java22
-rw-r--r--core/java/android/view/ViewGroup.java7
-rw-r--r--core/java/android/view/textclassifier/TextClassification.java27
-rw-r--r--core/java/android/view/textclassifier/TextClassifier.java7
-rw-r--r--core/java/android/view/textclassifier/TextClassifierImpl.java26
-rw-r--r--core/java/android/view/textclassifier/TextSelection.java27
-rw-r--r--core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java560
-rw-r--r--core/java/android/webkit/WebChromeClient.java4
-rw-r--r--core/java/android/webkit/WebView.java9
-rw-r--r--core/java/android/widget/ListView.java6
-rw-r--r--core/java/android/widget/RemoteViews.java187
-rw-r--r--core/java/android/widget/SelectionActionModeHelper.java3
-rw-r--r--core/java/android/widget/SmartSelectSprite.java252
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java20
-rw-r--r--core/java/com/android/internal/app/ResolverComparator.java8
-rw-r--r--core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java21
-rw-r--r--core/java/com/android/internal/os/PowerProfile.java10
-rw-r--r--core/java/com/android/internal/policy/DecorView.java2
-rw-r--r--core/java/com/android/internal/policy/PhoneWindow.java4
-rw-r--r--core/java/com/android/internal/view/TooltipPopup.java2
-rw-r--r--core/java/com/android/internal/widget/FloatingToolbar.java6
-rw-r--r--core/jni/Android.bp1
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/android/graphics/pdf/PdfEditor.cpp41
-rw-r--r--core/jni/android/graphics/pdf/PdfRenderer.cpp9
-rw-r--r--core/jni/android/graphics/pdf/PdfUtils.cpp24
-rw-r--r--core/jni/android/graphics/pdf/PdfUtils.h18
-rw-r--r--core/jni/android_os_SystemProperties.cpp269
-rw-r--r--core/jni/android_text_StaticLayout.cpp44
-rw-r--r--core/jni/android_util_StatsLog.cpp201
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp9
-rw-r--r--core/res/AndroidManifest.xml4
-rw-r--r--core/res/res/drawable/ic_corp_icon.xml11
-rw-r--r--core/res/res/values-ar/strings.xml10
-rw-r--r--core/res/res/values-bn/strings.xml14
-rw-r--r--core/res/res/values-bs/strings.xml2
-rw-r--r--core/res/res/values-ca/strings.xml2
-rw-r--r--core/res/res/values-es/strings.xml2
-rw-r--r--core/res/res/values-gl/strings.xml32
-rw-r--r--core/res/res/values-hi/strings.xml84
-rw-r--r--core/res/res/values-iw/strings.xml10
-rw-r--r--core/res/res/values-kn/strings.xml2
-rw-r--r--core/res/res/values-ky/strings.xml2
-rw-r--r--core/res/res/values-mcc302-mnc370-pa/strings.xml2
-rw-r--r--core/res/res/values-mcc302-mnc720-pa/strings.xml2
-rw-r--r--core/res/res/values-mk/strings.xml2
-rw-r--r--core/res/res/values-mr/strings.xml2
-rw-r--r--core/res/res/values-my/strings.xml22
-rw-r--r--core/res/res/values-pa/strings.xml98
-rw-r--r--core/res/res/values-te/strings.xml76
-rw-r--r--core/res/res/values/attrs.xml10
-rw-r--r--core/res/res/values/config.xml12
-rw-r--r--core/res/res/values/public.xml21
-rw-r--r--core/res/res/values/strings.xml5
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/res/res/xml/sms_short_codes.xml2
-rw-r--r--core/tests/coretests/src/android/database/DatabaseGeneralTest.java15
-rw-r--r--core/tests/coretests/src/android/provider/SettingsBackupTest.java2
-rwxr-xr-xcore/tests/systemproperties/run_core_systemproperties_test.sh2
-rw-r--r--core/tests/systemproperties/src/android/os/SystemPropertiesTest.java76
-rw-r--r--graphics/java/android/graphics/Color.java2
-rw-r--r--graphics/java/android/graphics/pdf/PdfEditor.java29
-rw-r--r--graphics/java/android/graphics/pdf/PdfRenderer.java41
-rw-r--r--libs/hwui/BakedOpRenderer.cpp15
-rw-r--r--libs/hwui/RenderNode.cpp19
-rw-r--r--libs/hwui/RenderNode.h21
-rw-r--r--libs/hwui/VectorDrawable.cpp43
-rw-r--r--libs/hwui/VectorDrawable.h5
-rw-r--r--libs/hwui/hwui/MinikinUtils.cpp3
-rw-r--r--libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp22
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp5
-rw-r--r--libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp5
-rw-r--r--libs/hwui/renderthread/EglManager.cpp2
-rw-r--r--media/java/android/media/AudioAttributes.java17
-rw-r--r--media/java/android/media/AudioManager.java4
-rw-r--r--media/java/android/media/ExifInterface.java180
-rw-r--r--media/java/android/media/IAudioService.aidl2
-rw-r--r--media/java/android/media/IMediaRouterService.aidl1
-rw-r--r--media/java/android/media/MediaPlayer.java12
-rw-r--r--media/java/android/media/MediaRouter.java59
-rw-r--r--media/java/android/media/PlayerBase.java1
-rw-r--r--packages/PrintSpooler/res/values-hi/strings.xml6
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java7
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java4
-rw-r--r--packages/SettingsLib/res/drawable/ic_info_outline_24dp.xml10
-rw-r--r--packages/SettingsLib/res/values-af/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-am/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ar/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-az/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-b+sr+Latn/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-be/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-bg/arrays.xml24
-rw-r--r--packages/SettingsLib/res/values-bg/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-bn/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-bs/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ca/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-cs/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-da/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-de/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-el/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-en-rAU/arrays.xml24
-rw-r--r--packages/SettingsLib/res/values-en-rAU/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-en-rCA/arrays.xml24
-rw-r--r--packages/SettingsLib/res/values-en-rCA/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-en-rGB/arrays.xml24
-rw-r--r--packages/SettingsLib/res/values-en-rGB/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-en-rIN/arrays.xml24
-rw-r--r--packages/SettingsLib/res/values-en-rIN/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-en-rXC/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-es-rUS/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-es/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-et/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-eu/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-fa/arrays.xml24
-rw-r--r--packages/SettingsLib/res/values-fa/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-fi/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-fr-rCA/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-fr/arrays.xml24
-rw-r--r--packages/SettingsLib/res/values-fr/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-gl/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-gu/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-hi/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-hr/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-hu/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-hy/arrays.xml24
-rw-r--r--packages/SettingsLib/res/values-hy/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-in/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-is/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-it/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-iw/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ja/arrays.xml24
-rw-r--r--packages/SettingsLib/res/values-ja/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ka/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-kk/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-km/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-kn/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ko/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ky/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-lo/arrays.xml24
-rw-r--r--packages/SettingsLib/res/values-lo/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-lt/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-lv/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-mk/strings.xml10
-rw-r--r--packages/SettingsLib/res/values-ml/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-mn/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-mr/strings.xml6
-rw-r--r--packages/SettingsLib/res/values-ms/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-my/arrays.xml24
-rw-r--r--packages/SettingsLib/res/values-my/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-nb/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ne/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-nl/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-pa/strings.xml6
-rw-r--r--packages/SettingsLib/res/values-pl/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-pt-rBR/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-pt-rPT/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-pt/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ro/arrays.xml24
-rw-r--r--packages/SettingsLib/res/values-ro/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ru/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-si/arrays.xml24
-rw-r--r--packages/SettingsLib/res/values-si/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-sk/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-sl/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-sq/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-sr/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-sv/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-sw/arrays.xml24
-rw-r--r--packages/SettingsLib/res/values-sw/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ta/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-te/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-th/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-tl/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-tr/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-uk/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-ur/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-uz/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-vi/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-zh-rCN/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-zh-rHK/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-zh-rTW/strings.xml4
-rw-r--r--packages/SettingsLib/res/values-zu/strings.xml4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/Utils.java4
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java15
-rwxr-xr-xpackages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java33
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java21
-rw-r--r--packages/Shell/res/values-hi/strings.xml36
-rw-r--r--packages/SystemUI/res-keyguard/values-hi/strings.xml2
-rw-r--r--packages/SystemUI/res-keyguard/values/strings.xml5
-rw-r--r--packages/SystemUI/res/drawable/car_qs_background_primary.xml20
-rw-r--r--packages/SystemUI/res/layout/battery_percentage_view.xml1
-rw-r--r--packages/SystemUI/res/layout/car_qs_panel.xml9
-rw-r--r--packages/SystemUI/res/layout/navigation_layout.xml4
-rw-r--r--packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml1
-rw-r--r--packages/SystemUI/res/values-km/strings.xml2
-rw-r--r--packages/SystemUI/res/values-mr/strings.xml6
-rw-r--r--packages/SystemUI/res/values-pa/strings.xml6
-rw-r--r--packages/SystemUI/res/values-sw372dp/dimens.xml21
-rw-r--r--packages/SystemUI/res/values/colors_car.xml1
-rw-r--r--packages/SystemUI/res/values/dimens.xml3
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java5
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/BatteryMeterView.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java122
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozePauser.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSDetail.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/Recents.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java22
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java64
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/model/Task.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java23
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java7
-rw-r--r--packages/SystemUI/tests/Android.mk3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/AlwaysOnDisplayPolicyTest.java86
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java69
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java5
-rw-r--r--proto/src/metrics_constants.proto13
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java3
-rw-r--r--services/accessibility/java/com/android/server/accessibility/GestureUtils.java20
-rw-r--r--services/accessibility/java/com/android/server/accessibility/MagnificationController.java40
-rw-r--r--services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java826
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java21
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java8
-rw-r--r--services/backup/java/com/android/server/backup/BackupManagerService.java2
-rw-r--r--services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java2
-rw-r--r--services/backup/java/com/android/server/backup/TransportManager.java44
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java56
-rw-r--r--services/core/java/com/android/server/VibratorService.java3
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java2
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java38
-rw-r--r--services/core/java/com/android/server/am/ActivityRecord.java161
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java196
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java130
-rw-r--r--services/core/java/com/android/server/am/ActivityStarter.java36
-rw-r--r--services/core/java/com/android/server/am/AppErrors.java3
-rw-r--r--services/core/java/com/android/server/am/BatteryExternalStatsWorker.java13
-rw-r--r--services/core/java/com/android/server/am/LockTaskController.java6
-rw-r--r--services/core/java/com/android/server/am/PinnedActivityStack.java7
-rw-r--r--services/core/java/com/android/server/am/RecentTasks.java8
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java355
-rw-r--r--services/core/java/com/android/server/am/UserController.java49
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java27
-rw-r--r--services/core/java/com/android/server/audio/PlaybackActivityMonitor.java29
-rw-r--r--services/core/java/com/android/server/connectivity/Nat464Xlat.java90
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java44
-rw-r--r--services/core/java/com/android/server/display/NightDisplayService.java34
-rw-r--r--services/core/java/com/android/server/job/JobSchedulerService.java27
-rw-r--r--services/core/java/com/android/server/job/JobServiceContext.java29
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java42
-rw-r--r--services/core/java/com/android/server/media/MediaRouterService.java64
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java135
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsCollection.java162
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsObservers.java14
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsRecorder.java9
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsService.java165
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java52
-rw-r--r--services/core/java/com/android/server/notification/RankingConfig.java1
-rw-r--r--services/core/java/com/android/server/notification/RankingHelper.java48
-rw-r--r--services/core/java/com/android/server/om/IdmapManager.java16
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerServiceImpl.java9
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java9
-rw-r--r--services/core/java/com/android/server/policy/AccessibilityShortcutController.java12
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java39
-rw-r--r--services/core/java/com/android/server/power/ShutdownThread.java55
-rw-r--r--services/core/java/com/android/server/wallpaper/WallpaperManagerService.java18
-rw-r--r--services/core/java/com/android/server/wm/AppWindowAnimator.java2
-rw-r--r--services/core/java/com/android/server/wm/AppWindowContainerController.java37
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java160
-rw-r--r--services/core/java/com/android/server/wm/BoundsAnimationController.java41
-rw-r--r--services/core/java/com/android/server/wm/BoundsAnimationTarget.java2
-rw-r--r--services/core/java/com/android/server/wm/ConfigurationContainer.java64
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java10
-rw-r--r--services/core/java/com/android/server/wm/DockedStackDividerController.java3
-rw-r--r--services/core/java/com/android/server/wm/PinnedStackWindowController.java6
-rw-r--r--services/core/java/com/android/server/wm/PinnedStackWindowListener.java3
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java55
-rw-r--r--services/core/java/com/android/server/wm/Task.java12
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotController.java4
-rw-r--r--services/core/java/com/android/server/wm/TaskSnapshotPersister.java2
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java38
-rw-r--r--services/core/java/com/android/server/wm/TaskWindowContainerController.java15
-rw-r--r--services/core/java/com/android/server/wm/WindowAnimator.java1
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java7
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java26
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java322
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java15
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfacePlacer.java13
-rw-r--r--services/core/jni/com_android_server_VibratorService.cpp6
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java120
-rw-r--r--services/java/com/android/server/SystemServer.java12
-rw-r--r--services/net/java/android/net/ip/IpManager.java56
-rw-r--r--services/print/java/com/android/server/print/PrintManagerService.java55
-rw-r--r--services/robotests/Android.mk78
-rw-r--r--services/robotests/src/com/android/server/backup/TransportManagerTest.java513
-rw-r--r--services/robotests/src/com/android/server/backup/testing/BackupTransportStub.java179
-rw-r--r--services/robotests/src/com/android/server/backup/testing/DefaultPackageManagerWithQueryIntentServicesAsUser.java43
-rw-r--r--services/robotests/src/com/android/server/backup/testing/ShadowBackupTransportStub.java40
-rw-r--r--services/robotests/src/com/android/server/backup/testing/ShadowContextImplForBackup.java64
-rw-r--r--services/robotests/src/com/android/server/backup/testing/TransportBoundListenerStub.java64
-rw-r--r--services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java14
-rw-r--r--services/tests/notification/src/com/android/server/notification/RankingHelperTest.java106
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java535
-rw-r--r--services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/backup/BackupPasswordManagerTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java9
-rw-r--r--services/tests/servicestests/src/com/android/server/testutils/OffsettableClock.java79
-rw-r--r--services/tests/servicestests/src/com/android/server/testutils/TestHandler.java156
-rw-r--r--services/tests/servicestests/src/com/android/server/testutils/TestUtils.java (renamed from services/tests/servicestests/src/com/android/server/testutis/TestUtils.java)18
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java32
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/ConfigurationContainerTests.java80
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java19
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java13
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/ByteStream.java52
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/Usb10ACHeader.java (renamed from services/usb/java/com/android/server/usb/descriptors/UsbACHeader.java)51
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/Usb10ACInputTerminal.java (renamed from services/usb/java/com/android/server/usb/descriptors/UsbACInputTerminal.java)22
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/Usb10ACMixerUnit.java108
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/Usb10ACOutputTerminal.java (renamed from services/usb/java/com/android/server/usb/descriptors/UsbACOutputTerminal.java)17
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/Usb10ASFormatI.java (renamed from services/usb/java/com/android/server/usb/descriptors/UsbASFormatI.java)45
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/Usb10ASFormatII.java (renamed from services/usb/java/com/android/server/usb/descriptors/UsbASFormatII.java)37
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/Usb10ASGeneral.java (renamed from services/usb/java/com/android/server/usb/descriptors/UsbASGeneral.java)23
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/Usb20ACHeader.java62
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/Usb20ACInputTerminal.java86
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/Usb20ACMixerUnit.java56
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/Usb20ACOutputTerminal.java79
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatI.java69
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatII.java72
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatIIEx.java78
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatIII.java63
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/Usb20ASGeneral.java104
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACAudioControlEndpoint.java4
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACAudioStreamEndpoint.java2
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACEndpoint.java4
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACFeatureUnit.java4
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACHeaderInterface.java56
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACInterface.java91
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACInterfaceUnparsed.java28
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACMidiEndpoint.java19
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACMixerUnit.java54
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACSelectorUnit.java13
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbACTerminal.java19
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbASFormat.java73
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbBinaryParser.java6
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java20
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbDescriptor.java63
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java71
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java51
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java119
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbHIDDescriptor.java23
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbInterfaceAssoc.java13
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java29
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbMSMidiHeader.java15
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbMSMidiInputJack.java15
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbMSMidiOutputJack.java15
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbTerminalTypes.java4
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/UsbUnknown.java4
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java97
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/report/HTMLReporter.java572
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java174
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/report/Reporter.java40
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/report/Reporting.java12
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java108
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/report/UsbStrings.java42
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsACInterfaceNode.java46
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsConfigNode.java63
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsDeviceNode.java56
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsEndpointNode.java42
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsInterfaceNode.java83
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsTree.java145
-rw-r--r--services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsTreeNode.java41
-rw-r--r--services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java15
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java24
-rw-r--r--telephony/java/com/android/ims/ImsConferenceState.java44
-rw-r--r--telephony/java/com/android/ims/ImsConfig.java1
-rw-r--r--telephony/java/com/android/internal/telephony/ExponentialBackoff.java84
-rw-r--r--tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java42
-rw-r--r--tests/net/java/android/net/NetworkStatsHistoryTest.java15
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java282
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsServiceTest.java60
-rw-r--r--tools/aapt/AaptXml.cpp42
-rw-r--r--tools/aapt/SdkConstants.h1
-rw-r--r--tools/aapt2/SdkConstants.h1
-rw-r--r--tools/aapt2/cmd/Optimize.cpp43
-rw-r--r--tools/aapt2/configuration/ConfigurationParser.cpp78
-rw-r--r--tools/aapt2/configuration/ConfigurationParser.h12
-rw-r--r--tools/aapt2/configuration/ConfigurationParser_test.cpp93
-rw-r--r--tools/aapt2/link/ManifestFixer.cpp1
-rw-r--r--tools/aapt2/optimize/MultiApkGenerator.cpp37
469 files changed, 12632 insertions, 5431 deletions
diff --git a/Android.mk b/Android.mk
index 33936f361c24..e61d7c2a5c0f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -270,6 +270,7 @@ LOCAL_SRC_FILES += \
core/java/android/os/IRecoverySystemProgressListener.aidl \
core/java/android/os/IRemoteCallback.aidl \
core/java/android/os/ISchedulingPolicyService.aidl \
+ core/java/android/os/IStatsManager.aidl \
core/java/android/os/IThermalEventListener.aidl \
core/java/android/os/IThermalService.aidl \
core/java/android/os/IUpdateLock.aidl \
diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
index 74d136654c62..57a61ec8218f 100644
--- a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
+++ b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java
@@ -88,4 +88,15 @@ public class StaticLayoutPerfTest {
.build();
}
}
+
+ @Test
+ public void testCreateRandom_breakBalanced() {
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ while (state.keepRunning()) {
+ final CharSequence text = generateRandomParagraph(9);
+ StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
+ .build();
+ }
+ }
}
diff --git a/api/current.txt b/api/current.txt
index d94614b4de9f..4c882315c3e0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1524,6 +1524,7 @@ package android {
field public static final int windowHideAnimation = 16842935; // 0x10100b7
field public static final int windowIsFloating = 16842839; // 0x1010057
field public static final int windowIsTranslucent = 16842840; // 0x1010058
+ field public static final int windowLightNavigationBar = 16844140; // 0x101056c
field public static final int windowLightStatusBar = 16844000; // 0x10104e0
field public static final int windowMinWidthMajor = 16843606; // 0x1010356
field public static final int windowMinWidthMinor = 16843607; // 0x1010357
@@ -5161,6 +5162,7 @@ package android.app {
field public static final java.lang.String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
+ field public static final java.lang.String EXTRA_CHANNEL_GROUP_ID = "android.intent.extra.CHANNEL_GROUP_ID";
field public static final java.lang.String EXTRA_CHANNEL_ID = "android.intent.extra.CHANNEL_ID";
field public static final java.lang.String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
field public static final java.lang.String EXTRA_COLORIZED = "android.colorized";
@@ -5576,8 +5578,11 @@ package android.app {
method public android.app.NotificationChannelGroup clone();
method public int describeContents();
method public java.util.List<android.app.NotificationChannel> getChannels();
+ method public java.lang.String getDescription();
method public java.lang.String getId();
method public java.lang.CharSequence getName();
+ method public boolean isBlocked();
+ method public void setDescription(java.lang.String);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.NotificationChannelGroup> CREATOR;
}
@@ -6282,6 +6287,7 @@ package android.app.admin {
method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
method public void addUserRestriction(android.content.ComponentName, java.lang.String);
method public boolean bindDeviceAdminServiceAsUser(android.content.ComponentName, android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
+ method public boolean clearApplicationUserData(android.content.ComponentName, java.lang.String, android.app.admin.DevicePolicyManager.OnClearApplicationUserDataListener, android.os.Handler);
method public void clearCrossProfileIntentFilters(android.content.ComponentName);
method public deprecated void clearDeviceOwnerApp(java.lang.String);
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
@@ -6531,10 +6537,15 @@ package android.app.admin {
field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
+ field public static final int START_USER_IN_BACKGROUND = 8; // 0x8
field public static final int WIPE_EXTERNAL_STORAGE = 1; // 0x1
field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
}
+ public static abstract interface DevicePolicyManager.OnClearApplicationUserDataListener {
+ method public abstract void onApplicationUserDataCleared(java.lang.String, boolean);
+ }
+
public final class DnsEvent extends android.app.admin.NetworkEvent implements android.os.Parcelable {
method public java.lang.String getHostname();
method public java.util.List<java.net.InetAddress> getInetAddresses();
@@ -15864,6 +15875,7 @@ package android.hardware.fingerprint {
field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
+ field public static final int FINGERPRINT_ERROR_USER_CANCELED = 10; // 0xa
field public static final int FINGERPRINT_ERROR_VENDOR = 8; // 0x8
}
@@ -30672,6 +30684,7 @@ package android.os {
field public static final int N_MR1 = 25; // 0x19
field public static final int O = 26; // 0x1a
field public static final int O_MR1 = 27; // 0x1b
+ field public static final int P = 10000; // 0x2710
}
public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
@@ -34883,6 +34896,7 @@ package android.provider {
field public static final java.lang.String ACTION_BLUETOOTH_SETTINGS = "android.settings.BLUETOOTH_SETTINGS";
field public static final java.lang.String ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS";
field public static final java.lang.String ACTION_CAST_SETTINGS = "android.settings.CAST_SETTINGS";
+ field public static final java.lang.String ACTION_CHANNEL_GROUP_NOTIFICATION_SETTINGS = "android.settings.CHANNEL_GROUP_NOTIFICATION_SETTINGS";
field public static final java.lang.String ACTION_CHANNEL_NOTIFICATION_SETTINGS = "android.settings.CHANNEL_NOTIFICATION_SETTINGS";
field public static final java.lang.String ACTION_DATA_ROAMING_SETTINGS = "android.settings.DATA_ROAMING_SETTINGS";
field public static final java.lang.String ACTION_DATE_SETTINGS = "android.settings.DATE_SETTINGS";
@@ -34942,6 +34956,7 @@ package android.provider {
field public static final java.lang.String EXTRA_APP_PACKAGE = "android.provider.extra.APP_PACKAGE";
field public static final java.lang.String EXTRA_AUTHORITIES = "authorities";
field public static final java.lang.String EXTRA_BATTERY_SAVER_MODE_ENABLED = "android.settings.extra.battery_saver_mode_enabled";
+ field public static final java.lang.String EXTRA_CHANNEL_GROUP_ID = "android.provider.extra.CHANNEL_GROUP_ID";
field public static final java.lang.String EXTRA_CHANNEL_ID = "android.provider.extra.CHANNEL_ID";
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
@@ -37074,13 +37089,14 @@ package android.service.autofill {
public final class FillEventHistory implements android.os.Parcelable {
method public int describeContents();
- method public android.os.Bundle getClientState();
+ method public deprecated android.os.Bundle getClientState();
method public java.util.List<android.service.autofill.FillEventHistory.Event> getEvents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.autofill.FillEventHistory> CREATOR;
}
public static final class FillEventHistory.Event {
+ method public android.os.Bundle getClientState();
method public java.lang.String getDatasetId();
method public int getType();
field public static final int TYPE_AUTHENTICATION_SELECTED = 2; // 0x2
@@ -39652,6 +39668,7 @@ package android.telephony {
field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool";
+ field public static final java.lang.String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array";
field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
diff --git a/api/system-current.txt b/api/system-current.txt
index a43fe2e4ca9f..9437dfe575fd 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1661,6 +1661,7 @@ package android {
field public static final int windowHideAnimation = 16842935; // 0x10100b7
field public static final int windowIsFloating = 16842839; // 0x1010057
field public static final int windowIsTranslucent = 16842840; // 0x1010058
+ field public static final int windowLightNavigationBar = 16844140; // 0x101056c
field public static final int windowLightStatusBar = 16844000; // 0x10104e0
field public static final int windowMinWidthMajor = 16843606; // 0x1010356
field public static final int windowMinWidthMinor = 16843607; // 0x1010357
@@ -5346,6 +5347,7 @@ package android.app {
field public static final java.lang.String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
+ field public static final java.lang.String EXTRA_CHANNEL_GROUP_ID = "android.intent.extra.CHANNEL_GROUP_ID";
field public static final java.lang.String EXTRA_CHANNEL_ID = "android.intent.extra.CHANNEL_ID";
field public static final java.lang.String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
field public static final java.lang.String EXTRA_COLORIZED = "android.colorized";
@@ -5782,8 +5784,11 @@ package android.app {
method public android.app.NotificationChannelGroup clone();
method public int describeContents();
method public java.util.List<android.app.NotificationChannel> getChannels();
+ method public java.lang.String getDescription();
method public java.lang.String getId();
method public java.lang.CharSequence getName();
+ method public boolean isBlocked();
+ method public void setDescription(java.lang.String);
method public org.json.JSONObject toJson() throws org.json.JSONException;
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.NotificationChannelGroup> CREATOR;
@@ -6498,6 +6503,7 @@ package android.app.admin {
method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
method public void addUserRestriction(android.content.ComponentName, java.lang.String);
method public boolean bindDeviceAdminServiceAsUser(android.content.ComponentName, android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
+ method public boolean clearApplicationUserData(android.content.ComponentName, java.lang.String, android.app.admin.DevicePolicyManager.OnClearApplicationUserDataListener, android.os.Handler);
method public void clearCrossProfileIntentFilters(android.content.ComponentName);
method public deprecated void clearDeviceOwnerApp(java.lang.String);
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
@@ -6775,6 +6781,7 @@ package android.app.admin {
field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
+ field public static final int START_USER_IN_BACKGROUND = 8; // 0x8
field public static final int STATE_USER_PROFILE_COMPLETE = 4; // 0x4
field public static final int STATE_USER_SETUP_COMPLETE = 2; // 0x2
field public static final int STATE_USER_SETUP_FINALIZED = 3; // 0x3
@@ -6784,6 +6791,10 @@ package android.app.admin {
field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
}
+ public static abstract interface DevicePolicyManager.OnClearApplicationUserDataListener {
+ method public abstract void onApplicationUserDataCleared(java.lang.String, boolean);
+ }
+
public final class DnsEvent extends android.app.admin.NetworkEvent implements android.os.Parcelable {
method public java.lang.String getHostname();
method public java.util.List<java.net.InetAddress> getInetAddresses();
@@ -16618,6 +16629,7 @@ package android.hardware.fingerprint {
field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
+ field public static final int FINGERPRINT_ERROR_USER_CANCELED = 10; // 0xa
field public static final int FINGERPRINT_ERROR_VENDOR = 8; // 0x8
}
@@ -33389,6 +33401,7 @@ package android.os {
field public static final int N_MR1 = 25; // 0x19
field public static final int O = 26; // 0x1a
field public static final int O_MR1 = 27; // 0x1b
+ field public static final int P = 10000; // 0x2710
}
public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
@@ -37935,6 +37948,7 @@ package android.provider {
field public static final java.lang.String ACTION_BLUETOOTH_SETTINGS = "android.settings.BLUETOOTH_SETTINGS";
field public static final java.lang.String ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS";
field public static final java.lang.String ACTION_CAST_SETTINGS = "android.settings.CAST_SETTINGS";
+ field public static final java.lang.String ACTION_CHANNEL_GROUP_NOTIFICATION_SETTINGS = "android.settings.CHANNEL_GROUP_NOTIFICATION_SETTINGS";
field public static final java.lang.String ACTION_CHANNEL_NOTIFICATION_SETTINGS = "android.settings.CHANNEL_NOTIFICATION_SETTINGS";
field public static final java.lang.String ACTION_DATA_ROAMING_SETTINGS = "android.settings.DATA_ROAMING_SETTINGS";
field public static final java.lang.String ACTION_DATE_SETTINGS = "android.settings.DATE_SETTINGS";
@@ -37995,6 +38009,7 @@ package android.provider {
field public static final java.lang.String EXTRA_APP_PACKAGE = "android.provider.extra.APP_PACKAGE";
field public static final java.lang.String EXTRA_AUTHORITIES = "authorities";
field public static final java.lang.String EXTRA_BATTERY_SAVER_MODE_ENABLED = "android.settings.extra.battery_saver_mode_enabled";
+ field public static final java.lang.String EXTRA_CHANNEL_GROUP_ID = "android.provider.extra.CHANNEL_GROUP_ID";
field public static final java.lang.String EXTRA_CHANNEL_ID = "android.provider.extra.CHANNEL_ID";
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
@@ -40165,13 +40180,14 @@ package android.service.autofill {
public final class FillEventHistory implements android.os.Parcelable {
method public int describeContents();
- method public android.os.Bundle getClientState();
+ method public deprecated android.os.Bundle getClientState();
method public java.util.List<android.service.autofill.FillEventHistory.Event> getEvents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.autofill.FillEventHistory> CREATOR;
}
public static final class FillEventHistory.Event {
+ method public android.os.Bundle getClientState();
method public java.lang.String getDatasetId();
method public int getType();
field public static final int TYPE_AUTHENTICATION_SELECTED = 2; // 0x2
@@ -43095,6 +43111,7 @@ package android.telephony {
field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool";
+ field public static final java.lang.String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array";
field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
diff --git a/api/test-current.txt b/api/test-current.txt
index 87eb171c54ef..20a15f801790 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1524,6 +1524,7 @@ package android {
field public static final int windowHideAnimation = 16842935; // 0x10100b7
field public static final int windowIsFloating = 16842839; // 0x1010057
field public static final int windowIsTranslucent = 16842840; // 0x1010058
+ field public static final int windowLightNavigationBar = 16844140; // 0x101056c
field public static final int windowLightStatusBar = 16844000; // 0x10104e0
field public static final int windowMinWidthMajor = 16843606; // 0x1010356
field public static final int windowMinWidthMinor = 16843607; // 0x1010357
@@ -5174,6 +5175,7 @@ package android.app {
field public static final java.lang.String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
+ field public static final java.lang.String EXTRA_CHANNEL_GROUP_ID = "android.intent.extra.CHANNEL_GROUP_ID";
field public static final java.lang.String EXTRA_CHANNEL_ID = "android.intent.extra.CHANNEL_ID";
field public static final java.lang.String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
field public static final java.lang.String EXTRA_COLORIZED = "android.colorized";
@@ -5589,8 +5591,12 @@ package android.app {
method public android.app.NotificationChannelGroup clone();
method public int describeContents();
method public java.util.List<android.app.NotificationChannel> getChannels();
+ method public java.lang.String getDescription();
method public java.lang.String getId();
method public java.lang.CharSequence getName();
+ method public boolean isBlocked();
+ method public void setBlocked(boolean);
+ method public void setDescription(java.lang.String);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.NotificationChannelGroup> CREATOR;
}
@@ -6303,6 +6309,7 @@ package android.app.admin {
method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
method public void addUserRestriction(android.content.ComponentName, java.lang.String);
method public boolean bindDeviceAdminServiceAsUser(android.content.ComponentName, android.content.Intent, android.content.ServiceConnection, int, android.os.UserHandle);
+ method public boolean clearApplicationUserData(android.content.ComponentName, java.lang.String, android.app.admin.DevicePolicyManager.OnClearApplicationUserDataListener, android.os.Handler);
method public void clearCrossProfileIntentFilters(android.content.ComponentName);
method public deprecated void clearDeviceOwnerApp(java.lang.String);
method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
@@ -6562,10 +6569,15 @@ package android.app.admin {
field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2
field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1
field public static final int SKIP_SETUP_WIZARD = 1; // 0x1
+ field public static final int START_USER_IN_BACKGROUND = 8; // 0x8
field public static final int WIPE_EXTERNAL_STORAGE = 1; // 0x1
field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
}
+ public static abstract interface DevicePolicyManager.OnClearApplicationUserDataListener {
+ method public abstract void onApplicationUserDataCleared(java.lang.String, boolean);
+ }
+
public final class DnsEvent extends android.app.admin.NetworkEvent implements android.os.Parcelable {
method public java.lang.String getHostname();
method public java.util.List<java.net.InetAddress> getInetAddresses();
@@ -15950,6 +15962,7 @@ package android.hardware.fingerprint {
field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
+ field public static final int FINGERPRINT_ERROR_USER_CANCELED = 10; // 0xa
field public static final int FINGERPRINT_ERROR_VENDOR = 8; // 0x8
}
@@ -30816,6 +30829,7 @@ package android.os {
field public static final int N_MR1 = 25; // 0x19
field public static final int O = 26; // 0x1a
field public static final int O_MR1 = 27; // 0x1b
+ field public static final int P = 10000; // 0x2710
}
public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
@@ -35060,6 +35074,7 @@ package android.provider {
field public static final java.lang.String ACTION_BLUETOOTH_SETTINGS = "android.settings.BLUETOOTH_SETTINGS";
field public static final java.lang.String ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS";
field public static final java.lang.String ACTION_CAST_SETTINGS = "android.settings.CAST_SETTINGS";
+ field public static final java.lang.String ACTION_CHANNEL_GROUP_NOTIFICATION_SETTINGS = "android.settings.CHANNEL_GROUP_NOTIFICATION_SETTINGS";
field public static final java.lang.String ACTION_CHANNEL_NOTIFICATION_SETTINGS = "android.settings.CHANNEL_NOTIFICATION_SETTINGS";
field public static final java.lang.String ACTION_DATA_ROAMING_SETTINGS = "android.settings.DATA_ROAMING_SETTINGS";
field public static final java.lang.String ACTION_DATE_SETTINGS = "android.settings.DATE_SETTINGS";
@@ -35120,6 +35135,7 @@ package android.provider {
field public static final java.lang.String EXTRA_APP_PACKAGE = "android.provider.extra.APP_PACKAGE";
field public static final java.lang.String EXTRA_AUTHORITIES = "authorities";
field public static final java.lang.String EXTRA_BATTERY_SAVER_MODE_ENABLED = "android.settings.extra.battery_saver_mode_enabled";
+ field public static final java.lang.String EXTRA_CHANNEL_GROUP_ID = "android.provider.extra.CHANNEL_GROUP_ID";
field public static final java.lang.String EXTRA_CHANNEL_ID = "android.provider.extra.CHANNEL_ID";
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
@@ -37272,13 +37288,14 @@ package android.service.autofill {
public final class FillEventHistory implements android.os.Parcelable {
method public int describeContents();
- method public android.os.Bundle getClientState();
+ method public deprecated android.os.Bundle getClientState();
method public java.util.List<android.service.autofill.FillEventHistory.Event> getEvents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.autofill.FillEventHistory> CREATOR;
}
public static final class FillEventHistory.Event {
+ method public android.os.Bundle getClientState();
method public java.lang.String getDatasetId();
method public int getType();
field public static final int TYPE_AUTHENTICATION_SELECTED = 2; // 0x2
@@ -39911,6 +39928,7 @@ package android.telephony {
field public static final java.lang.String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT = "duration_blocking_disabled_after_emergency_int";
field public static final java.lang.String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
field public static final java.lang.String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool";
+ field public static final java.lang.String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array";
field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool";
field public static final java.lang.String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool";
field public static final java.lang.String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int";
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
new file mode 100644
index 000000000000..db8c89dafaba
--- /dev/null
+++ b/cmds/statsd/Android.mk
@@ -0,0 +1,106 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+# =========
+# statsd
+# =========
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := statsd
+
+LOCAL_SRC_FILES := \
+ ../../core/java/android/os/IStatsManager.aidl \
+ src/StatsService.cpp \
+ src/LogEntryPrinter.cpp \
+ src/LogReader.cpp \
+ src/main.cpp
+
+LOCAL_CFLAGS += \
+ -Wall \
+ -Werror \
+ -Wno-missing-field-initializers \
+ -Wno-unused-variable \
+ -Wno-unused-function \
+ -Wno-unused-parameter
+
+ifeq (debug,)
+ LOCAL_CFLAGS += \
+ -g -O0
+else
+ # optimize for size (protobuf glop can get big)
+ LOCAL_CFLAGS += \
+ -Os
+endif
+
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/../../core/java
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
+
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ libbinder \
+ libcutils \
+ libincident \
+ liblog \
+ libselinux \
+ libutils
+
+LOCAL_MODULE_CLASS := EXECUTABLES
+
+#LOCAL_INIT_RC := statsd.rc
+
+include $(BUILD_EXECUTABLE)
+
+# ==============
+# statsd_test
+# ==============
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := statsd_test
+LOCAL_COMPATIBILITY_SUITE := device-tests
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_CFLAGS += \
+ -Wall \
+ -Werror \
+ -Wno-missing-field-initializers \
+ -Wno-unused-variable \
+ -Wno-unused-function \
+ -Wno-unused-parameter
+
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
+
+LOCAL_SRC_FILES := \
+ ../../core/java/android/os/IStatsManager.aidl \
+ src/StatsService.cpp \
+ src/LogEntryPrinter.cpp \
+ src/LogReader.cpp \
+ tests/LogReader_test.cpp \
+
+LOCAL_STATIC_LIBRARIES := \
+ libgmock \
+
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ libbinder \
+ libcutils \
+ liblog \
+ libselinux \
+ libutils
+
+include $(BUILD_NATIVE_TEST)
+
diff --git a/cmds/statsd/src/LogEntryPrinter.cpp b/cmds/statsd/src/LogEntryPrinter.cpp
new file mode 100644
index 000000000000..ba07308086ca
--- /dev/null
+++ b/cmds/statsd/src/LogEntryPrinter.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <LogEntryPrinter.h>
+
+#include <log/event_tag_map.h>
+#include <log/logprint.h>
+#include <utils/Errors.h>
+
+using namespace android;
+
+LogEntryPrinter::LogEntryPrinter(int out)
+ :m_out(out)
+{
+ // Initialize the EventTagMap, which is how we know the names of the numeric event tags.
+ // If this fails, we can't print well, but something will print.
+ m_tags = android_openEventTagMap(NULL);
+
+ // Printing format
+ m_format = android_log_format_new();
+ android_log_setPrintFormat(m_format, FORMAT_THREADTIME);
+}
+
+LogEntryPrinter::~LogEntryPrinter()
+{
+ if (m_tags != NULL) {
+ android_closeEventTagMap(m_tags);
+ }
+ android_log_format_free(m_format);
+}
+
+void
+LogEntryPrinter::OnLogEvent(const log_msg& msg)
+{
+ status_t err;
+ AndroidLogEntry entry;
+ char buf[1024];
+
+ err = android_log_processBinaryLogBuffer(&(const_cast<log_msg*>(&msg)->entry_v1),
+ &entry, m_tags, buf, sizeof(buf));
+ if (err == NO_ERROR) {
+ android_log_printLogLine(m_format, m_out, &entry);
+ } else {
+ printf("log entry: %s\n", buf);
+ fflush(stdout);
+ }
+}
+
diff --git a/cmds/statsd/src/LogEntryPrinter.h b/cmds/statsd/src/LogEntryPrinter.h
new file mode 100644
index 000000000000..61ffddca0916
--- /dev/null
+++ b/cmds/statsd/src/LogEntryPrinter.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LOG_ENTRY_PRINTER_H
+#define LOG_ENTRY_PRINTER_H
+
+#include "LogReader.h"
+
+#include <log/logprint.h>
+
+#include <stdio.h>
+
+/**
+ * Decodes the log entry and prints it to the supplied file descriptor.
+ */
+class LogEntryPrinter : public LogListener
+{
+public:
+ LogEntryPrinter(int out);
+ virtual ~LogEntryPrinter();
+
+ virtual void OnLogEvent(const log_msg& msg);
+
+private:
+ /**
+ * Where to write to.
+ */
+ int m_out;
+
+ /**
+ * Numeric to string tag name mapping.
+ */
+ EventTagMap* m_tags;
+
+ /**
+ * Pretty printing format.
+ */
+ AndroidLogFormat* m_format;
+};
+
+#endif // LOG_ENTRY_PRINTER_H
diff --git a/cmds/statsd/src/LogReader.cpp b/cmds/statsd/src/LogReader.cpp
new file mode 100644
index 000000000000..e0ed6464f4dc
--- /dev/null
+++ b/cmds/statsd/src/LogReader.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LogReader.h"
+
+#include <log/log_read.h>
+
+#include <utils/Errors.h>
+
+#include <time.h>
+#include <unistd.h>
+
+using namespace android;
+using namespace std;
+
+#define SNOOZE_INITIAL_MS 100
+#define SNOOZE_MAX_MS (10 * 60 * 1000) // Ten minutes
+
+
+// ================================================================================
+LogListener::LogListener()
+{
+}
+
+LogListener::~LogListener()
+{
+}
+
+
+// ================================================================================
+LogReader::LogReader()
+{
+}
+
+LogReader::~LogReader()
+{
+}
+
+void
+LogReader::AddListener(const sp<LogListener>& listener)
+{
+ m_listeners.push_back(listener);
+}
+
+void
+LogReader::Run()
+{
+ int nextSnoozeMs = SNOOZE_INITIAL_MS;
+
+ // In an ideal world, this outer loop will only ever run one iteration, but it
+ // exists to handle crashes in logd. The inner loop inside connect_and_read()
+ // reads from logd forever, but if that read fails, we fall out to the outer
+ // loop, do the backoff (resetting the backoff timeout if we successfully read
+ // something), and then try again.
+ while (true) {
+ // Connect and read
+ int lineCount = connect_and_read();
+
+ // Figure out how long to sleep.
+ if (lineCount > 0) {
+ // If we managed to read at least one line, reset the backoff
+ nextSnoozeMs = SNOOZE_INITIAL_MS;
+ } else {
+ // Otherwise, expontial backoff
+ nextSnoozeMs *= 1.5f;
+ if (nextSnoozeMs > 10 * 60 * 1000) {
+ // Don't wait for toooo long.
+ nextSnoozeMs = SNOOZE_MAX_MS;
+ }
+ }
+
+ // Sleep
+ timespec ts;
+ timespec rem;
+ ts.tv_sec = nextSnoozeMs / 1000;
+ ts.tv_nsec = (nextSnoozeMs % 1000) * 1000000L;
+ while (nanosleep(&ts, &rem) == -1) {
+ if (errno == EINTR) {
+ ts = rem;
+ }
+ // other errors are basically impossible
+ }
+ }
+}
+
+int
+LogReader::connect_and_read()
+{
+ int lineCount = 0;
+ status_t err;
+ logger_list* loggers;
+ logger* eventLogger;
+
+ // Prepare the logging context
+ loggers = android_logger_list_alloc(ANDROID_LOG_RDONLY,
+ /* don't stop after N lines */ 0,
+ /* no pid restriction */ 0);
+
+ // Open the buffer(s)
+ eventLogger = android_logger_open(loggers, LOG_ID_EVENTS);
+
+ // Read forever
+ if (eventLogger) {
+ while (true) {
+ log_msg msg;
+
+ // Read a message
+ err = android_logger_list_read(loggers, &msg);
+ if (err < 0) {
+ fprintf(stderr, "logcat read failure: %s\n", strerror(err));
+ break;
+ }
+
+ // Record that we read one (used above to know how to snooze).
+ lineCount++;
+
+ // Call the listeners
+ for (vector<sp<LogListener> >::iterator it = m_listeners.begin();
+ it != m_listeners.end(); it++) {
+ (*it)->OnLogEvent(msg);
+ }
+ }
+ }
+
+ // Free the logger list and close the individual loggers
+ android_logger_list_free(loggers);
+
+ return lineCount;
+}
+
diff --git a/cmds/statsd/src/LogReader.h b/cmds/statsd/src/LogReader.h
new file mode 100644
index 000000000000..08a17a31aa18
--- /dev/null
+++ b/cmds/statsd/src/LogReader.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LOGREADER_H
+#define LOGREADER_H
+
+#include <log/log_read.h>
+
+#include <utils/RefBase.h>
+
+#include <vector>
+
+/**
+ * Callback for LogReader
+ */
+class LogListener : public virtual android::RefBase
+{
+public:
+ LogListener();
+ virtual ~LogListener();
+
+ // TODO: Rather than using log_msg, which doesn't have any real internal structure
+ // here, we should pull this out into our own LogEntry class.
+ virtual void OnLogEvent(const log_msg& msg) = 0;
+};
+
+/**
+ * Class to read logs from logd.
+ */
+class LogReader : public virtual android::RefBase
+{
+public:
+ /**
+ * Construct the LogReader with a pointer back to the StatsService
+ */
+ LogReader();
+
+ /**
+ * Destructor.
+ */
+ virtual ~LogReader();
+
+ /**
+ * Add a LogListener class.
+ */
+ void AddListener(const android::sp<LogListener>& listener);
+
+ /**
+ * Run the main LogReader loop
+ */
+ void Run();
+
+private:
+ /**
+ * List of listeners to call back on when we do get an event.
+ */
+ std::vector<android::sp<LogListener> > m_listeners;
+
+ /**
+ * Connect to a single instance of logd, and read until there's a read error.
+ * Logd can crash, exit, be killed etc.
+ *
+ * Returns the number of lines that were read.
+ */
+ int connect_and_read();
+};
+
+#endif // LOGREADER_H
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
new file mode 100644
index 000000000000..13c6f67dd37d
--- /dev/null
+++ b/cmds/statsd/src/StatsService.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "statsd"
+
+#include "StatsService.h"
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <cutils/log.h>
+#include <private/android_filesystem_config.h>
+#include <utils/Looper.h>
+
+#include <unistd.h>
+#include <stdio.h>
+
+using namespace android;
+
+// ================================================================================
+StatsService::StatsService(const sp<Looper>& handlerLooper)
+{
+ ALOGD("stats service constructed");
+}
+
+StatsService::~StatsService()
+{
+}
+
+status_t
+StatsService::dump(int fd, const Vector<String16>& args)
+{
+ FILE* out = fdopen(fd, "w");
+ if (out == NULL) {
+ return NO_MEMORY; // the fd is already open
+ }
+
+ fprintf(out, "StatsService::dump:");
+ ALOGD("StatsService::dump:");
+ const int N = args.size();
+ for (int i=0; i<N; i++) {
+ fprintf(out, " %s", String8(args[i]).string());
+ ALOGD(" %s", String8(args[i]).string());
+ }
+ fprintf(out, "\n");
+
+ fclose(out);
+ return NO_ERROR;
+}
+
+Status
+StatsService::systemRunning()
+{
+ if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
+ return Status::fromExceptionCode(Status::EX_SECURITY,
+ "Only system uid can call systemRunning");
+ }
+
+ // When system_server is up and running, schedule the dropbox task to run.
+ ALOGD("StatsService::systemRunning");
+
+ return Status::ok();
+}
+
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
new file mode 100644
index 000000000000..0f34882b4b60
--- /dev/null
+++ b/cmds/statsd/src/StatsService.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef STATS_SERVICE_H
+#define STATS_SERVICE_H
+
+#include <android/os/BnStatsManager.h>
+#include <utils/Looper.h>
+
+#include <deque>
+#include <mutex>
+
+using namespace android;
+using namespace android::base;
+using namespace android::binder;
+using namespace android::os;
+using namespace std;
+
+
+// ================================================================================
+class StatsService : public BnStatsManager {
+public:
+ StatsService(const sp<Looper>& handlerLooper);
+ virtual ~StatsService();
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual Status systemRunning();
+
+};
+
+#endif // STATS_SERVICE_H
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
new file mode 100644
index 000000000000..93405cb6bf95
--- /dev/null
+++ b/cmds/statsd/src/main.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "statsd"
+
+#include "LogEntryPrinter.h"
+#include "LogReader.h"
+#include "StatsService.h"
+
+#include <binder/IInterface.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <binder/Status.h>
+#include <cutils/log.h>
+#include <utils/Looper.h>
+#include <utils/StrongPointer.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+using namespace android;
+
+// ================================================================================
+/**
+ * Thread function data.
+ */
+struct log_reader_thread_data {
+ sp<StatsService> service;
+};
+
+/**
+ * Thread func for where the log reader runs.
+ */
+static void*
+log_reader_thread_func(void* cookie)
+{
+ log_reader_thread_data* data = static_cast<log_reader_thread_data*>(cookie);
+
+ sp<LogReader> reader = new LogReader();
+
+ // Put the printer one first, so it will print before the real ones.
+ if (true) {
+ reader->AddListener(new LogEntryPrinter(STDOUT_FILENO));
+ }
+
+ // TODO: Construct and add real LogListners here.
+
+ reader->Run();
+
+ ALOGW("statsd LogReader.Run() is not supposed to return.");
+
+ delete data;
+ return NULL;
+}
+
+/**
+ * Creates and starts the thread to own the LogReader.
+ */
+static status_t
+start_log_reader_thread(const sp<StatsService>& service)
+{
+ status_t err;
+ pthread_attr_t attr;
+ pthread_t thread;
+
+ // Thread data.
+ log_reader_thread_data* data = new log_reader_thread_data();
+ data->service = service;
+
+ // Create the thread
+ err = pthread_attr_init(&attr);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ // TODO: Do we need to tweak thread priority?
+ err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ if (err != NO_ERROR) {
+ pthread_attr_destroy(&attr);
+ return err;
+ }
+ err = pthread_create(&thread, &attr, log_reader_thread_func, static_cast<void*>(data));
+ if (err != NO_ERROR) {
+ pthread_attr_destroy(&attr);
+ return err;
+ }
+ pthread_attr_destroy(&attr);
+
+ return NO_ERROR;
+}
+
+// ================================================================================
+int
+main(int /*argc*/, char** /*argv*/)
+{
+ status_t err;
+
+ // Set up the looper
+ sp<Looper> looper(Looper::prepare(0 /* opts */));
+
+ // Set up the binder
+ sp<ProcessState> ps(ProcessState::self());
+ ps->setThreadPoolMaxThreadCount(1); // everything is oneway, let it queue and save ram
+ ps->startThreadPool();
+ ps->giveThreadPoolName();
+ IPCThreadState::self()->disableBackgroundScheduling(true);
+
+ // Create the service
+ sp<StatsService> service = new StatsService(looper);
+ if (defaultServiceManager()->addService(String16("stats"), service) != 0) {
+ ALOGE("Failed to add service");
+ return -1;
+ }
+
+ // Start the log reader thread
+ err = start_log_reader_thread(service);
+ if (err != NO_ERROR) {
+ return 1;
+ }
+
+ // Loop forever -- the reports run on this thread in a handler, and the
+ // binder calls remain responsive in their pool of one thread.
+ while (true) {
+ looper->pollAll(-1 /* timeoutMillis */);
+ }
+ ALOGW("statsd escaped from its loop.");
+
+ return 1;
+}
diff --git a/cmds/statsd/statsd.rc b/cmds/statsd/statsd.rc
new file mode 100644
index 000000000000..faccd610e223
--- /dev/null
+++ b/cmds/statsd/statsd.rc
@@ -0,0 +1,16 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+service statsd /system/bin/statsd
+ class main
diff --git a/cmds/statsd/tests/LogReader_test.cpp b/cmds/statsd/tests/LogReader_test.cpp
new file mode 100644
index 000000000000..ca538b082f89
--- /dev/null
+++ b/cmds/statsd/tests/LogReader_test.cpp
@@ -0,0 +1,24 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#define LOG_TAG "statsd_test"
+
+#include <gtest/gtest.h>
+
+#include <stdio.h>
+
+TEST(LogReaderTest, TestNothingAtAll) {
+ printf("yay!");
+}
+
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index b2f3add3b4bd..e76e1903a529 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -16,6 +16,10 @@
package android.app;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_DOCKED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
@@ -141,16 +145,6 @@ public class ActivityManager {
private static final int FIRST_START_NON_FATAL_ERROR_CODE = 100;
private static final int LAST_START_NON_FATAL_ERROR_CODE = 199;
- /**
- * System property to enable task snapshots.
- * @hide
- */
- public final static boolean ENABLE_TASK_SNAPSHOTS;
-
- static {
- ENABLE_TASK_SNAPSHOTS = SystemProperties.getBoolean("persist.enable_task_snapshots", true);
- }
-
static final class UidObserver extends IUidObserver.Stub {
final OnUidImportanceListener mListener;
final Context mContext;
@@ -884,6 +878,26 @@ public class ActivityManager {
}
return windowingMode;
}
+
+ /** Returns the activity type that should be used for this input stack id. */
+ // TODO: To be removed once we are not using stack id for stuff...
+ public static int getActivityTypeForStackId(int stackId) {
+ final int activityType;
+ switch (stackId) {
+ case HOME_STACK_ID:
+ activityType = ACTIVITY_TYPE_HOME;
+ break;
+ case RECENTS_STACK_ID:
+ activityType = ACTIVITY_TYPE_RECENTS;
+ break;
+ case ASSISTANT_STACK_ID:
+ activityType = ACTIVITY_TYPE_ASSISTANT;
+ break;
+ default :
+ activityType = ACTIVITY_TYPE_STANDARD;
+ }
+ return activityType;
+ }
}
/**
@@ -2101,165 +2115,6 @@ public class ActivityManager {
}
/**
- * Metadata related to the {@link TaskThumbnail}.
- *
- * @hide
- */
- public static class TaskThumbnailInfo implements Parcelable {
- /** @hide */
- public static final String ATTR_TASK_THUMBNAILINFO_PREFIX = "task_thumbnailinfo_";
- private static final String ATTR_TASK_WIDTH =
- ATTR_TASK_THUMBNAILINFO_PREFIX + "task_width";
- private static final String ATTR_TASK_HEIGHT =
- ATTR_TASK_THUMBNAILINFO_PREFIX + "task_height";
- private static final String ATTR_SCREEN_ORIENTATION =
- ATTR_TASK_THUMBNAILINFO_PREFIX + "screen_orientation";
-
- public int taskWidth;
- public int taskHeight;
- public int screenOrientation = Configuration.ORIENTATION_UNDEFINED;
-
- public TaskThumbnailInfo() {
- // Do nothing
- }
-
- private TaskThumbnailInfo(Parcel source) {
- readFromParcel(source);
- }
-
- /**
- * Resets this info state to the initial state.
- * @hide
- */
- public void reset() {
- taskWidth = 0;
- taskHeight = 0;
- screenOrientation = Configuration.ORIENTATION_UNDEFINED;
- }
-
- /**
- * Copies from another ThumbnailInfo.
- */
- public void copyFrom(TaskThumbnailInfo o) {
- taskWidth = o.taskWidth;
- taskHeight = o.taskHeight;
- screenOrientation = o.screenOrientation;
- }
-
- /** @hide */
- public void saveToXml(XmlSerializer out) throws IOException {
- out.attribute(null, ATTR_TASK_WIDTH, Integer.toString(taskWidth));
- out.attribute(null, ATTR_TASK_HEIGHT, Integer.toString(taskHeight));
- out.attribute(null, ATTR_SCREEN_ORIENTATION, Integer.toString(screenOrientation));
- }
-
- /** @hide */
- public void restoreFromXml(String attrName, String attrValue) {
- if (ATTR_TASK_WIDTH.equals(attrName)) {
- taskWidth = Integer.parseInt(attrValue);
- } else if (ATTR_TASK_HEIGHT.equals(attrName)) {
- taskHeight = Integer.parseInt(attrValue);
- } else if (ATTR_SCREEN_ORIENTATION.equals(attrName)) {
- screenOrientation = Integer.parseInt(attrValue);
- }
- }
-
- public int describeContents() {
- return 0;
- }
-
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(taskWidth);
- dest.writeInt(taskHeight);
- dest.writeInt(screenOrientation);
- }
-
- public void readFromParcel(Parcel source) {
- taskWidth = source.readInt();
- taskHeight = source.readInt();
- screenOrientation = source.readInt();
- }
-
- public static final Creator<TaskThumbnailInfo> CREATOR = new Creator<TaskThumbnailInfo>() {
- public TaskThumbnailInfo createFromParcel(Parcel source) {
- return new TaskThumbnailInfo(source);
- }
- public TaskThumbnailInfo[] newArray(int size) {
- return new TaskThumbnailInfo[size];
- }
- };
- }
-
- /** @hide */
- public static class TaskThumbnail implements Parcelable {
- public Bitmap mainThumbnail;
- public ParcelFileDescriptor thumbnailFileDescriptor;
- public TaskThumbnailInfo thumbnailInfo;
-
- public TaskThumbnail() {
- }
-
- private TaskThumbnail(Parcel source) {
- readFromParcel(source);
- }
-
- public int describeContents() {
- if (thumbnailFileDescriptor != null) {
- return thumbnailFileDescriptor.describeContents();
- }
- return 0;
- }
-
- public void writeToParcel(Parcel dest, int flags) {
- if (mainThumbnail != null) {
- dest.writeInt(1);
- mainThumbnail.writeToParcel(dest, flags);
- } else {
- dest.writeInt(0);
- }
- if (thumbnailFileDescriptor != null) {
- dest.writeInt(1);
- thumbnailFileDescriptor.writeToParcel(dest, flags);
- } else {
- dest.writeInt(0);
- }
- if (thumbnailInfo != null) {
- dest.writeInt(1);
- thumbnailInfo.writeToParcel(dest, flags);
- } else {
- dest.writeInt(0);
- }
- }
-
- public void readFromParcel(Parcel source) {
- if (source.readInt() != 0) {
- mainThumbnail = Bitmap.CREATOR.createFromParcel(source);
- } else {
- mainThumbnail = null;
- }
- if (source.readInt() != 0) {
- thumbnailFileDescriptor = ParcelFileDescriptor.CREATOR.createFromParcel(source);
- } else {
- thumbnailFileDescriptor = null;
- }
- if (source.readInt() != 0) {
- thumbnailInfo = TaskThumbnailInfo.CREATOR.createFromParcel(source);
- } else {
- thumbnailInfo = null;
- }
- }
-
- public static final Creator<TaskThumbnail> CREATOR = new Creator<TaskThumbnail>() {
- public TaskThumbnail createFromParcel(Parcel source) {
- return new TaskThumbnail(source);
- }
- public TaskThumbnail[] newArray(int size) {
- return new TaskThumbnail[size];
- }
- };
- }
-
- /**
* Represents a task snapshot.
* @hide
*/
@@ -2356,15 +2211,6 @@ public class ActivityManager {
}
/** @hide */
- public TaskThumbnail getTaskThumbnail(int id) throws SecurityException {
- try {
- return getService().getTaskThumbnail(id);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /** @hide */
@IntDef(flag = true, prefix = { "MOVE_TASK_" }, value = {
MOVE_TASK_WITH_HOME,
MOVE_TASK_NO_USER_ACTION,
@@ -2876,7 +2722,8 @@ public class ActivityManager {
* the user choosing to clear the app's data from within the device settings UI. It
* erases all dynamic data associated with the app -- its private data and data in its
* private area on external storage -- but does not remove the installed application
- * itself, nor any OBB files.
+ * itself, nor any OBB files. It also revokes all runtime permissions that the app has acquired,
+ * clears all notifications and removes all Uri grants related to this application.
*
* @return {@code true} if the application successfully requested that the application's
* data be erased; {@code false} otherwise.
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index c8d983933fc6..9d14f616a09a 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -40,12 +40,6 @@ import java.util.List;
public abstract class ActivityManagerInternal {
/**
- * Type for {@link #notifyAppTransitionStarting}: The transition was started because we had
- * the surface saved.
- */
- public static final int APP_TRANSITION_SAVED_SURFACE = 0;
-
- /**
* Type for {@link #notifyAppTransitionStarting}: The transition was started because we drew
* the splash screen.
*/
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index ae821915ab66..1e05ae2ec5d2 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -209,7 +209,6 @@ interface IActivityManager {
void forceStopPackage(in String packageName, int userId);
boolean killPids(in int[] pids, in String reason, boolean secure);
List<ActivityManager.RunningServiceInfo> getServices(int maxNum, int flags);
- ActivityManager.TaskThumbnail getTaskThumbnail(int taskId);
ActivityManager.TaskDescription getTaskDescription(int taskId);
// Retrieve running application processes in the system
List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses();
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 08821bebd57e..d4752a771492 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -61,6 +61,8 @@ interface INotificationManager
void createNotificationChannelsForPackage(String pkg, int uid, in ParceledListSlice channelsList);
ParceledListSlice getNotificationChannelGroupsForPackage(String pkg, int uid, boolean includeDeleted);
NotificationChannelGroup getNotificationChannelGroupForPackage(String groupId, String pkg, int uid);
+ NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(String pkg, int uid, String groupId, boolean includeDeleted);
+ void updateNotificationChannelGroupForPackage(String pkg, int uid, in NotificationChannelGroup group);
void updateNotificationChannelForPackage(String pkg, int uid, in NotificationChannel channel);
NotificationChannel getNotificationChannel(String pkg, String channelId);
NotificationChannel getNotificationChannelForPackage(String pkg, int uid, String channelId, boolean includeDeleted);
@@ -103,6 +105,7 @@ interface INotificationManager
void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim);
void setInterruptionFilter(String pkg, int interruptionFilter);
+ void updateNotificationChannelGroupFromPrivilegedListener(in INotificationListener token, String pkg, in UserHandle user, in NotificationChannelGroup group);
void updateNotificationChannelFromPrivilegedListener(in INotificationListener token, String pkg, in UserHandle user, in NotificationChannel channel);
ParceledListSlice getNotificationChannelsFromPrivilegedListener(in INotificationListener token, String pkg, in UserHandle user);
ParceledListSlice getNotificationChannelGroupsFromPrivilegedListener(in INotificationListener token, String pkg, in UserHandle user);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 9511f3fd7cef..841b9611fa20 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -124,6 +124,13 @@ public class Notification implements Parcelable
/**
* Optional extra for {@link #INTENT_CATEGORY_NOTIFICATION_PREFERENCES}. If provided, will
+ * contain a {@link NotificationChannelGroup#getId() group id} that can be used to narrow down
+ * what settings should be shown in the target app.
+ */
+ public static final String EXTRA_CHANNEL_GROUP_ID = "android.intent.extra.CHANNEL_GROUP_ID";
+
+ /**
+ * Optional extra for {@link #INTENT_CATEGORY_NOTIFICATION_PREFERENCES}. If provided, will
* contain the tag provided to {@link NotificationManager#notify(String, int, Notification)}
* that can be used to narrow down what settings should be shown in the target app.
*/
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index d6e36914ac6c..163a8dcae2f4 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -830,24 +830,24 @@ public final class NotificationChannel implements Parcelable {
@Override
public String toString() {
- return "NotificationChannel{" +
- "mId='" + mId + '\'' +
- ", mName=" + mName +
- ", mDescription=" + (!TextUtils.isEmpty(mDesc) ? "hasDescription " : "") +
- ", mImportance=" + mImportance +
- ", mBypassDnd=" + mBypassDnd +
- ", mLockscreenVisibility=" + mLockscreenVisibility +
- ", mSound=" + mSound +
- ", mLights=" + mLights +
- ", mLightColor=" + mLightColor +
- ", mVibration=" + Arrays.toString(mVibration) +
- ", mUserLockedFields=" + mUserLockedFields +
- ", mVibrationEnabled=" + mVibrationEnabled +
- ", mShowBadge=" + mShowBadge +
- ", mDeleted=" + mDeleted +
- ", mGroup='" + mGroup + '\'' +
- ", mAudioAttributes=" + mAudioAttributes +
- ", mBlockableSystem=" + mBlockableSystem +
- '}';
+ return "NotificationChannel{"
+ + "mId='" + mId + '\''
+ + ", mName=" + mName
+ + ", mDescription=" + (!TextUtils.isEmpty(mDesc) ? "hasDescription " : "")
+ + ", mImportance=" + mImportance
+ + ", mBypassDnd=" + mBypassDnd
+ + ", mLockscreenVisibility=" + mLockscreenVisibility
+ + ", mSound=" + mSound
+ + ", mLights=" + mLights
+ + ", mLightColor=" + mLightColor
+ + ", mVibration=" + Arrays.toString(mVibration)
+ + ", mUserLockedFields=" + Integer.toHexString(mUserLockedFields)
+ + ", mVibrationEnabled=" + mVibrationEnabled
+ + ", mShowBadge=" + mShowBadge
+ + ", mDeleted=" + mDeleted
+ + ", mGroup='" + mGroup + '\''
+ + ", mAudioAttributes=" + mAudioAttributes
+ + ", mBlockableSystem=" + mBlockableSystem
+ + '}';
}
}
diff --git a/core/java/android/app/NotificationChannelGroup.java b/core/java/android/app/NotificationChannelGroup.java
index 18ad9cf3d8e3..51733114f8b9 100644
--- a/core/java/android/app/NotificationChannelGroup.java
+++ b/core/java/android/app/NotificationChannelGroup.java
@@ -16,6 +16,7 @@
package android.app;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.content.Intent;
import android.os.Parcel;
import android.os.Parcelable;
@@ -23,6 +24,7 @@ import android.text.TextUtils;
import org.json.JSONException;
import org.json.JSONObject;
+import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
@@ -42,10 +44,14 @@ public final class NotificationChannelGroup implements Parcelable {
private static final String TAG_GROUP = "channelGroup";
private static final String ATT_NAME = "name";
+ private static final String ATT_DESC = "desc";
private static final String ATT_ID = "id";
+ private static final String ATT_BLOCKED = "blocked";
private final String mId;
private CharSequence mName;
+ private String mDescription;
+ private boolean mBlocked;
private List<NotificationChannel> mChannels = new ArrayList<>();
/**
@@ -73,7 +79,13 @@ public final class NotificationChannelGroup implements Parcelable {
mId = null;
}
mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ if (in.readByte() != 0) {
+ mDescription = in.readString();
+ } else {
+ mDescription = null;
+ }
in.readParcelableList(mChannels, NotificationChannel.class.getClassLoader());
+ mBlocked = in.readBoolean();
}
private String getTrimmedString(String input) {
@@ -92,24 +104,38 @@ public final class NotificationChannelGroup implements Parcelable {
dest.writeByte((byte) 0);
}
TextUtils.writeToParcel(mName, dest, flags);
+ if (mDescription != null) {
+ dest.writeByte((byte) 1);
+ dest.writeString(mDescription);
+ } else {
+ dest.writeByte((byte) 0);
+ }
dest.writeParcelableList(mChannels, flags);
+ dest.writeBoolean(mBlocked);
}
/**
- * Returns the id of this channel.
+ * Returns the id of this group.
*/
public String getId() {
return mId;
}
/**
- * Returns the user visible name of this channel.
+ * Returns the user visible name of this group.
*/
public CharSequence getName() {
return mName;
}
/**
+ * Returns the user visible description of this group.
+ */
+ public String getDescription() {
+ return mDescription;
+ }
+
+ /**
* Returns the list of channels that belong to this group
*/
public List<NotificationChannel> getChannels() {
@@ -117,6 +143,32 @@ public final class NotificationChannelGroup implements Parcelable {
}
/**
+ * Returns whether or not notifications posted to {@link NotificationChannel channels} belonging
+ * to this group are blocked.
+ */
+ public boolean isBlocked() {
+ return mBlocked;
+ }
+
+ /**
+ * Sets the user visible description of this group.
+ *
+ * <p>The recommended maximum length is 300 characters; the value may be truncated if it is too
+ * long.
+ */
+ public void setDescription(String description) {
+ mDescription = getTrimmedString(description);
+ }
+
+ /**
+ * @hide
+ */
+ @TestApi
+ public void setBlocked(boolean blocked) {
+ mBlocked = blocked;
+ }
+
+ /**
* @hide
*/
public void addChannel(NotificationChannel channel) {
@@ -126,6 +178,28 @@ public final class NotificationChannelGroup implements Parcelable {
/**
* @hide
*/
+ public void setChannels(List<NotificationChannel> channels) {
+ mChannels = channels;
+ }
+
+ /**
+ * @hide
+ */
+ public void populateFromXml(XmlPullParser parser) {
+ // Name, id, and importance are set in the constructor.
+ setDescription(parser.getAttributeValue(null, ATT_DESC));
+ setBlocked(safeBool(parser, ATT_BLOCKED, false));
+ }
+
+ private static boolean safeBool(XmlPullParser parser, String att, boolean defValue) {
+ final String value = parser.getAttributeValue(null, att);
+ if (TextUtils.isEmpty(value)) return defValue;
+ return Boolean.parseBoolean(value);
+ }
+
+ /**
+ * @hide
+ */
public void writeXml(XmlSerializer out) throws IOException {
out.startTag(null, TAG_GROUP);
@@ -133,6 +207,10 @@ public final class NotificationChannelGroup implements Parcelable {
if (getName() != null) {
out.attribute(null, ATT_NAME, getName().toString());
}
+ if (getDescription() != null) {
+ out.attribute(null, ATT_DESC, getDescription().toString());
+ }
+ out.attribute(null, ATT_BLOCKED, Boolean.toString(isBlocked()));
out.endTag(null, TAG_GROUP);
}
@@ -145,6 +223,8 @@ public final class NotificationChannelGroup implements Parcelable {
JSONObject record = new JSONObject();
record.put(ATT_ID, getId());
record.put(ATT_NAME, getName());
+ record.put(ATT_DESC, getDescription());
+ record.put(ATT_BLOCKED, isBlocked());
return record;
}
@@ -173,31 +253,46 @@ public final class NotificationChannelGroup implements Parcelable {
NotificationChannelGroup that = (NotificationChannelGroup) o;
+ if (isBlocked() != that.isBlocked()) return false;
if (getId() != null ? !getId().equals(that.getId()) : that.getId() != null) return false;
if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) {
return false;
}
- return true;
- }
-
- @Override
- public NotificationChannelGroup clone() {
- return new NotificationChannelGroup(getId(), getName());
+ if (getDescription() != null ? !getDescription().equals(that.getDescription())
+ : that.getDescription() != null) {
+ return false;
+ }
+ return getChannels() != null ? getChannels().equals(that.getChannels())
+ : that.getChannels() == null;
}
@Override
public int hashCode() {
int result = getId() != null ? getId().hashCode() : 0;
result = 31 * result + (getName() != null ? getName().hashCode() : 0);
+ result = 31 * result + (getDescription() != null ? getDescription().hashCode() : 0);
+ result = 31 * result + (isBlocked() ? 1 : 0);
+ result = 31 * result + (getChannels() != null ? getChannels().hashCode() : 0);
return result;
}
@Override
+ public NotificationChannelGroup clone() {
+ NotificationChannelGroup cloned = new NotificationChannelGroup(getId(), getName());
+ cloned.setDescription(getDescription());
+ cloned.setBlocked(isBlocked());
+ cloned.setChannels(getChannels());
+ return cloned;
+ }
+
+ @Override
public String toString() {
- return "NotificationChannelGroup{" +
- "mId='" + mId + '\'' +
- ", mName=" + mName +
- ", mChannels=" + mChannels +
- '}';
+ return "NotificationChannelGroup{"
+ + "mId='" + mId + '\''
+ + ", mName=" + mName
+ + ", mDescription=" + (!TextUtils.isEmpty(mDescription) ? "hasDescription " : "")
+ + ", mBlocked=" + mBlocked
+ + ", mChannels=" + mChannels
+ + '}';
}
}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 34343e9e106a..8fa7d6c3b4f7 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -421,7 +421,7 @@ public class NotificationManager {
* Creates a notification channel that notifications can be posted to.
*
* This can also be used to restore a deleted channel and to update an existing channel's
- * name, description, and/or importance.
+ * name, description, group, and/or importance.
*
* <p>The name and description should only be changed if the locale changes
* or in response to the user renaming this channel. For example, if a user has a channel
@@ -431,6 +431,9 @@ public class NotificationManager {
* <p>The importance of an existing channel will only be changed if the new importance is lower
* than the current value and the user has not altered any settings on this channel.
*
+ * <p>The group an existing channel will only be changed if the channel does not already
+ * belong to a group.
+ *
* All other fields are ignored for channels that already exist.
*
* @param channel the channel to create. Note that the created channel may differ from this
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 595ecd201e57..fb11272d7e62 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -964,7 +964,7 @@ public class ResourcesManager {
// TODO(adamlesinski): Make this accept more than just overlay directories.
final void applyNewResourceDirsLocked(@NonNull final String baseCodePath,
- @NonNull final String[] newResourceDirs) {
+ @Nullable final String[] newResourceDirs) {
try {
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
"ResourcesManager#applyNewResourceDirsLocked");
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index b9e739755921..942cc99585ed 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -1603,11 +1603,12 @@ public class WallpaperManager {
/**
* Clear the wallpaper for a specific user. The caller must hold the
* INTERACT_ACROSS_USERS_FULL permission to clear another user's
- * wallpaper.
+ * wallpaper, and must hold the SET_WALLPAPER permission in all
+ * circumstances.
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.SET_WALLPAPER)
+ @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
public void clearWallpaper(@SetWallpaperFlags int which, int userId) {
if (sGlobals.mService == null) {
Log.w(TAG, "WallpaperService not running");
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index 11922ec804aa..187237d240f3 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -55,7 +55,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
/** Can be freely resized within its parent container. */
public static final int WINDOWING_MODE_FREEFORM = 4;
- @IntDef(value = {
+ @IntDef({
WINDOWING_MODE_UNDEFINED,
WINDOWING_MODE_FULLSCREEN,
WINDOWING_MODE_PINNED,
@@ -64,15 +64,41 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
})
public @interface WindowingMode {}
+ /** The current activity type of the configuration. */
+ private @ActivityType int mActivityType;
+
+ /** Activity type is currently not defined. */
+ public static final int ACTIVITY_TYPE_UNDEFINED = 0;
+ /** Standard activity type. Nothing special about the activity... */
+ public static final int ACTIVITY_TYPE_STANDARD = 1;
+ /** Home/Launcher activity type. */
+ public static final int ACTIVITY_TYPE_HOME = 2;
+ /** Recents/Overview activity type. */
+ public static final int ACTIVITY_TYPE_RECENTS = 3;
+ /** Assistant activity type. */
+ public static final int ACTIVITY_TYPE_ASSISTANT = 4;
+
+ @IntDef({
+ ACTIVITY_TYPE_UNDEFINED,
+ ACTIVITY_TYPE_STANDARD,
+ ACTIVITY_TYPE_HOME,
+ ACTIVITY_TYPE_RECENTS,
+ ACTIVITY_TYPE_ASSISTANT,
+ })
+ public @interface ActivityType {}
+
/** Bit that indicates that the {@link #mAppBounds} changed. */
public static final int WINDOW_CONFIG_APP_BOUNDS = 1 << 0;
/** Bit that indicates that the {@link #mWindowingMode} changed. */
public static final int WINDOW_CONFIG_WINDOWING_MODE = 1 << 1;
+ /** Bit that indicates that the {@link #mActivityType} changed. */
+ public static final int WINDOW_CONFIG_ACTIVITY_TYPE = 1 << 2;
@IntDef(flag = true,
value = {
WINDOW_CONFIG_APP_BOUNDS,
WINDOW_CONFIG_WINDOWING_MODE,
+ WINDOW_CONFIG_ACTIVITY_TYPE,
})
public @interface WindowConfig {}
@@ -92,11 +118,13 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(mAppBounds, flags);
dest.writeInt(mWindowingMode);
+ dest.writeInt(mActivityType);
}
private void readFromParcel(Parcel source) {
mAppBounds = source.readParcelable(Rect.class.getClassLoader());
mWindowingMode = source.readInt();
+ mActivityType = source.readInt();
}
@Override
@@ -158,9 +186,27 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
return mWindowingMode;
}
+ public void setActivityType(@ActivityType int activityType) {
+ if (mActivityType == activityType) {
+ return;
+ }
+ if (mActivityType != ACTIVITY_TYPE_UNDEFINED
+ && activityType != ACTIVITY_TYPE_UNDEFINED) {
+ throw new IllegalStateException("Can't change activity type once set: " + this
+ + " activityType=" + activityTypeToString(activityType));
+ }
+ mActivityType = activityType;
+ }
+
+ @ActivityType
+ public int getActivityType() {
+ return mActivityType;
+ }
+
public void setTo(WindowConfiguration other) {
setAppBounds(other.mAppBounds);
setWindowingMode(other.mWindowingMode);
+ setActivityType(other.mActivityType);
}
/** Set this object to completely undefined. */
@@ -171,6 +217,7 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
public void setToDefaults() {
setAppBounds(null);
setWindowingMode(WINDOWING_MODE_UNDEFINED);
+ setActivityType(ACTIVITY_TYPE_UNDEFINED);
}
/**
@@ -191,6 +238,11 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
changed |= WINDOW_CONFIG_WINDOWING_MODE;
setWindowingMode(delta.mWindowingMode);
}
+ if (delta.mActivityType != ACTIVITY_TYPE_UNDEFINED
+ && mActivityType != delta.mActivityType) {
+ changed |= WINDOW_CONFIG_ACTIVITY_TYPE;
+ setActivityType(delta.mActivityType);
+ }
return changed;
}
@@ -219,6 +271,11 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
changes |= WINDOW_CONFIG_WINDOWING_MODE;
}
+ if ((compareUndefined || other.mActivityType != ACTIVITY_TYPE_UNDEFINED)
+ && mActivityType != other.mActivityType) {
+ changes |= WINDOW_CONFIG_ACTIVITY_TYPE;
+ }
+
return changes;
}
@@ -241,6 +298,8 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
}
n = mWindowingMode - that.mWindowingMode;
if (n != 0) return n;
+ n = mActivityType - that.mActivityType;
+ if (n != 0) return n;
// if (n != 0) return n;
return n;
@@ -263,13 +322,15 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
result = 31 * result + mAppBounds.hashCode();
}
result = 31 * result + mWindowingMode;
+ result = 31 * result + mActivityType;
return result;
}
@Override
public String toString() {
return "{mAppBounds=" + mAppBounds
- + " mWindowingMode=" + windowingModeToString(mWindowingMode) + "}";
+ + " mWindowingMode=" + windowingModeToString(mWindowingMode)
+ + " mActivityType=" + activityTypeToString(mActivityType) + "}";
}
/**
@@ -366,4 +427,15 @@ public class WindowConfiguration implements Parcelable, Comparable<WindowConfigu
}
return String.valueOf(windowingMode);
}
+
+ public static String activityTypeToString(@ActivityType int applicationType) {
+ switch (applicationType) {
+ case ACTIVITY_TYPE_UNDEFINED: return "undefined";
+ case ACTIVITY_TYPE_STANDARD: return "standard";
+ case ACTIVITY_TYPE_HOME: return "home";
+ case ACTIVITY_TYPE_RECENTS: return "recents";
+ case ACTIVITY_TYPE_ASSISTANT: return "assistant";
+ }
+ return String.valueOf(applicationType);
+ }
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 56123a72d00e..833af1b538d0 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -39,6 +39,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageDataObserver;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
@@ -47,6 +48,7 @@ import android.graphics.Bitmap;
import android.net.ProxyInfo;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
import android.os.Parcelable;
import android.os.PersistableBundle;
import android.os.Process;
@@ -5981,6 +5983,26 @@ public class DevicePolicyManager {
public static final int MAKE_USER_DEMO = 0x0004;
/**
+ * Flag used by {@link #createAndManageUser} to specificy that the newly created user should be
+ * started in the background as part of the user creation.
+ */
+ // TODO: Investigate solutions for the case where reboot happens before setup is completed.
+ public static final int START_USER_IN_BACKGROUND = 0x0008;
+
+ /**
+ * @hide
+ */
+ @IntDef(
+ flag = true,
+ prefix = {"SKIP_", "MAKE_USER_", "START_"},
+ value = {SKIP_SETUP_WIZARD, MAKE_USER_EPHEMERAL, MAKE_USER_DEMO,
+ START_USER_IN_BACKGROUND}
+ )
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CreateAndManageUserFlags {}
+
+
+ /**
* Called by a device owner to create a user with the specified name and a given component of
* the calling package as profile owner. The UserHandle returned by this method should not be
* persisted as user handles are recycled as users are removed and created. If you need to
@@ -6011,7 +6033,7 @@ public class DevicePolicyManager {
public @Nullable UserHandle createAndManageUser(@NonNull ComponentName admin,
@NonNull String name,
@NonNull ComponentName profileOwner, @Nullable PersistableBundle adminExtras,
- int flags) {
+ @CreateAndManageUserFlags int flags) {
throwIfParentInstance("createAndManageUser");
try {
return mService.createAndManageUser(admin, name, profileOwner, adminExtras, flags);
@@ -6770,6 +6792,10 @@ public class DevicePolicyManager {
* password, pin or pattern is set after the keyguard was disabled, the keyguard stops being
* disabled.
*
+ * <p>
+ * As of {@link android.os.Build.VERSION_CODES#P}, this call also dismisses the
+ * keyguard if it is currently shown.
+ *
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param disabled {@code true} disables the keyguard, {@code false} reenables it.
* @return {@code false} if attempting to disable the keyguard while a lock password was in
@@ -8109,4 +8135,51 @@ public class DevicePolicyManager {
throw re.rethrowFromSystemServer();
}
}
+
+ /**
+ * Called by the device owner or profile owner to clear application user data of a given
+ * package. The behaviour of this is equivalent to the target application calling
+ * {@link android.app.ActivityManager#clearApplicationUserData()}.
+ *
+ * <p><strong>Note:</strong> an application can store data outside of its application data, e.g.
+ * external storage or user dictionary. This data will not be wiped by calling this API.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param packageName The name of the package which will have its user data wiped.
+ * @param listener A callback object that will inform the caller when the clearing is done.
+ * @param handler The handler indicating the thread on which the listener should be invoked.
+ * @throws SecurityException if the caller is not the device owner/profile owner.
+ * @return whether the clearing succeeded.
+ */
+ public boolean clearApplicationUserData(@NonNull ComponentName admin,
+ @NonNull String packageName, @NonNull OnClearApplicationUserDataListener listener,
+ @NonNull Handler handler) {
+ throwIfParentInstance("clearAppData");
+ try {
+ return mService.clearApplicationUserData(admin, packageName,
+ new IPackageDataObserver.Stub() {
+ public void onRemoveCompleted(String pkg, boolean succeeded) {
+ handler.post(() ->
+ listener.onApplicationUserDataCleared(pkg, succeeded));
+ }
+ });
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Callback used in {@link #clearApplicationUserData}
+ * to indicate that the clearing of an application's user data is done.
+ */
+ public interface OnClearApplicationUserDataListener {
+ /**
+ * Method invoked when clearing the application user data has completed.
+ *
+ * @param packageName The name of the package which had its user data cleared.
+ * @param succeeded Whether the clearing succeeded. Clearing fails for device administrator
+ * apps and protected system packages.
+ */
+ void onApplicationUserDataCleared(String packageName, boolean succeeded);
+ }
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index e361d819ac2d..acfb602834ef 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -26,6 +26,7 @@ import android.app.admin.PasswordMetrics;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.IPackageDataObserver;
import android.content.pm.ParceledListSlice;
import android.content.pm.StringParceledListSlice;
import android.graphics.Bitmap;
@@ -355,4 +356,6 @@ interface IDevicePolicyManager {
boolean isCurrentInputMethodSetByOwner();
StringParceledListSlice getOwnerInstalledCaCerts(in UserHandle user);
+
+ boolean clearApplicationUserData(in ComponentName admin, in String packageName, in IPackageDataObserver callback);
}
diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java
index 3670b914ecf3..222e9a0e5e0c 100644
--- a/core/java/android/app/usage/NetworkStats.java
+++ b/core/java/android/app/usage/NetworkStats.java
@@ -97,12 +97,12 @@ public final class NetworkStats implements AutoCloseable {
private NetworkStatsHistory.Entry mRecycledHistoryEntry = null;
/** @hide */
- NetworkStats(Context context, NetworkTemplate template, long startTimestamp,
+ NetworkStats(Context context, NetworkTemplate template, int flags, long startTimestamp,
long endTimestamp) throws RemoteException, SecurityException {
final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(
ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
// Open network stats session
- mSession = statsService.openSessionForUsageStats(context.getOpPackageName());
+ mSession = statsService.openSessionForUsageStats(flags, context.getOpPackageName());
mCloseGuard.open("close");
mTemplate = template;
mStartTimeStamp = startTimestamp;
diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index ef262e046021..853b00331a4d 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -24,15 +24,14 @@ import android.app.usage.NetworkStats.Bucket;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.DataUsageRequest;
+import android.net.INetworkStatsService;
import android.net.NetworkIdentity;
import android.net.NetworkTemplate;
-import android.net.INetworkStatsService;
import android.os.Binder;
-import android.os.Build;
-import android.os.Message;
-import android.os.Messenger;
import android.os.Handler;
import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
@@ -79,7 +78,7 @@ import android.util.Log;
* In addition to tethering usage, usage by removed users and apps, and usage by the system
* is also included in the results for callers with one of these higher levels of access.
* <p />
- * <b>NOTE:</b> Prior to API level {@value Build.VERSION_CODES#N}, all calls to these APIs required
+ * <b>NOTE:</b> Prior to API level {@value android.os.Build.VERSION_CODES#N}, all calls to these APIs required
* the above permission, even to access an app's own data usage, and carrier-privileged apps were
* not included.
*/
@@ -96,6 +95,13 @@ public class NetworkStatsManager {
private final Context mContext;
private final INetworkStatsService mService;
+ /** @hide */
+ public static final int FLAG_POLL_ON_OPEN = 1 << 0;
+ /** @hide */
+ public static final int FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN = 1 << 1;
+
+ private int mFlags;
+
/**
* {@hide}
*/
@@ -103,6 +109,25 @@ public class NetworkStatsManager {
mContext = context;
mService = INetworkStatsService.Stub.asInterface(
ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE));
+ setPollOnOpen(true);
+ }
+
+ /** @hide */
+ public void setPollOnOpen(boolean pollOnOpen) {
+ if (pollOnOpen) {
+ mFlags |= FLAG_POLL_ON_OPEN;
+ } else {
+ mFlags &= ~FLAG_POLL_ON_OPEN;
+ }
+ }
+
+ /** @hide */
+ public void setAugmentWithSubscriptionPlan(boolean augmentWithSubscriptionPlan) {
+ if (augmentWithSubscriptionPlan) {
+ mFlags |= FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN;
+ } else {
+ mFlags &= ~FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN;
+ }
}
/**
@@ -136,7 +161,7 @@ public class NetworkStatsManager {
}
Bucket bucket = null;
- NetworkStats stats = new NetworkStats(mContext, template, startTime, endTime);
+ NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime);
bucket = stats.getDeviceSummaryForNetwork();
stats.close();
@@ -174,7 +199,7 @@ public class NetworkStatsManager {
}
NetworkStats stats;
- stats = new NetworkStats(mContext, template, startTime, endTime);
+ stats = new NetworkStats(mContext, template, mFlags, startTime, endTime);
stats.startSummaryEnumeration();
stats.close();
@@ -211,7 +236,7 @@ public class NetworkStatsManager {
}
NetworkStats result;
- result = new NetworkStats(mContext, template, startTime, endTime);
+ result = new NetworkStats(mContext, template, mFlags, startTime, endTime);
result.startSummaryEnumeration();
return result;
@@ -260,7 +285,7 @@ public class NetworkStatsManager {
NetworkStats result;
try {
- result = new NetworkStats(mContext, template, startTime, endTime);
+ result = new NetworkStats(mContext, template, mFlags, startTime, endTime);
result.startHistoryEnumeration(uid, tag);
} catch (RemoteException e) {
Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag, e);
@@ -305,7 +330,7 @@ public class NetworkStatsManager {
}
NetworkStats result;
- result = new NetworkStats(mContext, template, startTime, endTime);
+ result = new NetworkStats(mContext, template, mFlags, startTime, endTime);
result.startUserUidEnumeration();
return result;
}
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 1242cb0fbdfa..8a1eae2da976 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -40,7 +40,6 @@ import android.util.SparseArray;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Adapter;
import android.widget.AdapterView;
@@ -469,7 +468,9 @@ public class AppWidgetHostView extends FrameLayout {
// We've already done this -- nothing to do.
return ;
}
- Log.w(TAG, "updateAppWidget couldn't find any view, using error view", exception);
+ if (exception != null) {
+ Log.w(TAG, "Error inflating RemoteViews : " + exception.toString());
+ }
content = getErrorView();
mViewMode = VIEW_MODE_ERROR;
}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 92f4849e7d8e..48587b3630d9 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1103,12 +1103,12 @@ public class ActivityInfo extends ComponentInfo
}
/** @hide */
- public void dump(Printer pw, String prefix, int flags) {
+ public void dump(Printer pw, String prefix, int dumpFlags) {
super.dumpFront(pw, prefix);
if (permission != null) {
pw.println(prefix + "permission=" + permission);
}
- if ((flags&DUMP_FLAG_DETAILS) != 0) {
+ if ((dumpFlags & DUMP_FLAG_DETAILS) != 0) {
pw.println(prefix + "taskAffinity=" + taskAffinity
+ " targetActivity=" + targetActivity
+ " persistableMode=" + persistableModeToString());
@@ -1127,7 +1127,7 @@ public class ActivityInfo extends ComponentInfo
if (uiOptions != 0) {
pw.println(prefix + " uiOptions=0x" + Integer.toHexString(uiOptions));
}
- if ((flags&DUMP_FLAG_DETAILS) != 0) {
+ if ((dumpFlags & DUMP_FLAG_DETAILS) != 0) {
pw.println(prefix + "lockTaskLaunchMode="
+ lockTaskLaunchModeToString(lockTaskLaunchMode));
}
@@ -1143,7 +1143,7 @@ public class ActivityInfo extends ComponentInfo
if (maxAspectRatio != 0) {
pw.println(prefix + "maxAspectRatio=" + maxAspectRatio);
}
- super.dumpBack(pw, prefix, flags);
+ super.dumpBack(pw, prefix, dumpFlags);
}
public String toString() {
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 2aa3d09dd479..ad7a5ab10e41 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1046,22 +1046,22 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
}
/** @hide */
- public void dump(Printer pw, String prefix, int flags) {
+ public void dump(Printer pw, String prefix, int dumpFlags) {
super.dumpFront(pw, prefix);
- if ((flags&DUMP_FLAG_DETAILS) != 0 && className != null) {
+ if ((dumpFlags & DUMP_FLAG_DETAILS) != 0 && className != null) {
pw.println(prefix + "className=" + className);
}
if (permission != null) {
pw.println(prefix + "permission=" + permission);
}
pw.println(prefix + "processName=" + processName);
- if ((flags&DUMP_FLAG_DETAILS) != 0) {
+ if ((dumpFlags & DUMP_FLAG_DETAILS) != 0) {
pw.println(prefix + "taskAffinity=" + taskAffinity);
}
pw.println(prefix + "uid=" + uid + " flags=0x" + Integer.toHexString(flags)
+ " privateFlags=0x" + Integer.toHexString(privateFlags)
+ " theme=0x" + Integer.toHexString(theme));
- if ((flags&DUMP_FLAG_DETAILS) != 0) {
+ if ((dumpFlags & DUMP_FLAG_DETAILS) != 0) {
pw.println(prefix + "requiresSmallestWidthDp=" + requiresSmallestWidthDp
+ " compatibleWidthLimitDp=" + compatibleWidthLimitDp
+ " largestWidthLimitDp=" + largestWidthLimitDp);
@@ -1080,12 +1080,12 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
if (resourceDirs != null) {
pw.println(prefix + "resourceDirs=" + Arrays.toString(resourceDirs));
}
- if ((flags&DUMP_FLAG_DETAILS) != 0 && seInfo != null) {
+ if ((dumpFlags & DUMP_FLAG_DETAILS) != 0 && seInfo != null) {
pw.println(prefix + "seinfo=" + seInfo);
pw.println(prefix + "seinfoUser=" + seInfoUser);
}
pw.println(prefix + "dataDir=" + dataDir);
- if ((flags&DUMP_FLAG_DETAILS) != 0) {
+ if ((dumpFlags & DUMP_FLAG_DETAILS) != 0) {
pw.println(prefix + "deviceProtectedDataDir=" + deviceProtectedDataDir);
pw.println(prefix + "credentialProtectedDataDir=" + credentialProtectedDataDir);
if (sharedLibraryFiles != null) {
@@ -1104,7 +1104,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
+ " targetSdkVersion=" + targetSdkVersion
+ " versionCode=" + versionCode
+ " targetSandboxVersion=" + targetSandboxVersion);
- if ((flags&DUMP_FLAG_DETAILS) != 0) {
+ if ((dumpFlags & DUMP_FLAG_DETAILS) != 0) {
if (manageSpaceActivityName != null) {
pw.println(prefix + "manageSpaceActivityName=" + manageSpaceActivityName);
}
diff --git a/core/java/android/content/pm/ComponentInfo.java b/core/java/android/content/pm/ComponentInfo.java
index 53be9537d00d..6b1222f53959 100644
--- a/core/java/android/content/pm/ComponentInfo.java
+++ b/core/java/android/content/pm/ComponentInfo.java
@@ -183,12 +183,12 @@ public class ComponentInfo extends PackageItemInfo {
protected void dumpBack(Printer pw, String prefix) {
dumpBack(pw, prefix, DUMP_FLAG_ALL);
}
-
- void dumpBack(Printer pw, String prefix, int flags) {
- if ((flags&DUMP_FLAG_APPLICATION) != 0) {
+
+ void dumpBack(Printer pw, String prefix, int dumpFlags) {
+ if ((dumpFlags & DUMP_FLAG_APPLICATION) != 0) {
if (applicationInfo != null) {
pw.println(prefix + "ApplicationInfo:");
- applicationInfo.dump(pw, prefix + " ", flags);
+ applicationInfo.dump(pw, prefix + " ", dumpFlags);
} else {
pw.println(prefix + "ApplicationInfo: null");
}
diff --git a/core/java/android/content/pm/ProviderInfo.java b/core/java/android/content/pm/ProviderInfo.java
index 91dc06e12138..379b7833150c 100644
--- a/core/java/android/content/pm/ProviderInfo.java
+++ b/core/java/android/content/pm/ProviderInfo.java
@@ -125,11 +125,11 @@ public final class ProviderInfo extends ComponentInfo
}
/** @hide */
- public void dump(Printer pw, String prefix, int flags) {
+ public void dump(Printer pw, String prefix, int dumpFlags) {
super.dumpFront(pw, prefix);
pw.println(prefix + "authority=" + authority);
pw.println(prefix + "flags=0x" + Integer.toHexString(flags));
- super.dumpBack(pw, prefix, flags);
+ super.dumpBack(pw, prefix, dumpFlags);
}
public int describeContents() {
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index f312204e9467..799316700b4d 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -282,7 +282,7 @@ public class ResolveInfo implements Parcelable {
}
/** @hide */
- public void dump(Printer pw, String prefix, int flags) {
+ public void dump(Printer pw, String prefix, int dumpFlags) {
if (filter != null) {
pw.println(prefix + "Filter:");
filter.dump(pw, prefix + " ");
@@ -302,13 +302,13 @@ public class ResolveInfo implements Parcelable {
}
if (activityInfo != null) {
pw.println(prefix + "ActivityInfo:");
- activityInfo.dump(pw, prefix + " ", flags);
+ activityInfo.dump(pw, prefix + " ", dumpFlags);
} else if (serviceInfo != null) {
pw.println(prefix + "ServiceInfo:");
- serviceInfo.dump(pw, prefix + " ", flags);
+ serviceInfo.dump(pw, prefix + " ", dumpFlags);
} else if (providerInfo != null) {
pw.println(prefix + "ProviderInfo:");
- providerInfo.dump(pw, prefix + " ", flags);
+ providerInfo.dump(pw, prefix + " ", dumpFlags);
}
}
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index c683ea5d9739..91f884ccd3dc 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -91,13 +91,13 @@ public class ServiceInfo extends ComponentInfo
}
/** @hide */
- void dump(Printer pw, String prefix, int flags) {
+ void dump(Printer pw, String prefix, int dumpFlags) {
super.dumpFront(pw, prefix);
pw.println(prefix + "permission=" + permission);
pw.println(prefix + "flags=0x" + Integer.toHexString(flags));
- super.dumpBack(pw, prefix, flags);
+ super.dumpBack(pw, prefix, dumpFlags);
}
-
+
public String toString() {
return "ServiceInfo{"
+ Integer.toHexString(System.identityHashCode(this))
diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java
index 8cd3d7b5bc68..3d019f07cb84 100644
--- a/core/java/android/database/DatabaseUtils.java
+++ b/core/java/android/database/DatabaseUtils.java
@@ -1408,6 +1408,12 @@ public class DatabaseUtils {
} else if (prefixSql.equals("END")) {
return STATEMENT_COMMIT;
} else if (prefixSql.equals("ROL")) {
+ boolean isRollbackToSavepoint = sql.toUpperCase(Locale.ROOT).contains(" TO ");
+ if (isRollbackToSavepoint) {
+ Log.w(TAG, "Statement '" + sql
+ + "' may not work on API levels 16-27, use ';" + sql + "' instead");
+ return STATEMENT_OTHER;
+ }
return STATEMENT_ABORT;
} else if (prefixSql.equals("BEG")) {
return STATEMENT_BEGIN;
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 8b6f9c1bbdd2..987718a82c47 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -128,6 +128,13 @@ public class FingerprintManager {
public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9;
/**
+ * The user canceled the operation. Upon receiving this, applications should use alternate
+ * authentication (e.g. a password). The application should also provide the means to return
+ * to fingerprint authentication, such as a "use fingerprint" button.
+ */
+ public static final int FINGERPRINT_ERROR_USER_CANCELED = 10;
+
+ /**
* @hide
*/
public static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000;
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index e693009c3377..91801127fd4a 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -36,7 +36,7 @@ interface INetworkStatsService {
* PACKAGE_USAGE_STATS permission is always checked. If PACKAGE_USAGE_STATS is not granted
* READ_NETWORK_USAGE_STATS is checked for.
*/
- INetworkStatsSession openSessionForUsageStats(String callingPackage);
+ INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage);
/** Return network layer usage total for traffic that matches template. */
long getNetworkTotalBytes(in NetworkTemplate template, long start, long end);
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index 5f521de63cf1..433f9410cc6e 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -27,6 +27,7 @@ import static android.net.NetworkStatsHistory.Entry.UNKNOWN;
import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray;
import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray;
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
+
import static com.android.internal.util.ArrayUtils.total;
import android.os.Parcel;
@@ -282,6 +283,24 @@ public class NetworkStatsHistory implements Parcelable {
return entry;
}
+ public void setValues(int i, Entry entry) {
+ // Unwind old values
+ if (rxBytes != null) totalBytes -= rxBytes[i];
+ if (txBytes != null) totalBytes -= txBytes[i];
+
+ bucketStart[i] = entry.bucketStart;
+ setLong(activeTime, i, entry.activeTime);
+ setLong(rxBytes, i, entry.rxBytes);
+ setLong(rxPackets, i, entry.rxPackets);
+ setLong(txBytes, i, entry.txBytes);
+ setLong(txPackets, i, entry.txPackets);
+ setLong(operations, i, entry.operations);
+
+ // Apply new values
+ if (rxBytes != null) totalBytes += rxBytes[i];
+ if (txBytes != null) totalBytes += txBytes[i];
+ }
+
/**
* Record that data traffic occurred in the given time range. Will
* distribute across internal buckets, creating new buckets as needed.
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index 0d2fcd074047..b307c5d6fc53 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -326,6 +326,10 @@ public class NetworkTemplate implements Parcelable {
}
}
+ public boolean matchesSubscriberId(String subscriberId) {
+ return ArrayUtils.contains(mMatchSubscriberIds, subscriberId);
+ }
+
/**
* Check if mobile network with matching IMSI.
*/
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 062799891ffd..935f5f3b78a7 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -774,6 +774,11 @@ public class Build {
* O MR1.
*/
public static final int O_MR1 = 27;
+
+ /**
+ * P.
+ */
+ public static final int P = CUR_DEVELOPMENT; // STOPSHIP Replace with the real version.
}
/** The type of build, like "user" or "eng". */
diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl
new file mode 100644
index 000000000000..9b5139dc5092
--- /dev/null
+++ b/core/java/android/os/IStatsManager.aidl
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * Binder interface to communicate with the statistics collection service.
+ * {@hide}
+ */
+oneway interface IStatsManager {
+ /**
+ * Tell the incident daemon that the android system server is up and running.
+ */
+ void systemRunning();
+}
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 3e071437b097..4703af06c06e 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -53,31 +53,25 @@ import java.util.HashMap;
import java.util.concurrent.atomic.AtomicInteger;
/**
- * <p>StrictMode is a developer tool which detects things you might be
- * doing by accident and brings them to your attention so you can fix
- * them.
+ * StrictMode is a developer tool which detects things you might be doing by accident and brings
+ * them to your attention so you can fix them.
*
- * <p>StrictMode is most commonly used to catch accidental disk or
- * network access on the application's main thread, where UI
- * operations are received and animations take place. Keeping disk
- * and network operations off the main thread makes for much smoother,
- * more responsive applications. By keeping your application's main thread
- * responsive, you also prevent
- * <a href="{@docRoot}guide/practices/design/responsiveness.html">ANR dialogs</a>
- * from being shown to users.
+ * <p>StrictMode is most commonly used to catch accidental disk or network access on the
+ * application's main thread, where UI operations are received and animations take place. Keeping
+ * disk and network operations off the main thread makes for much smoother, more responsive
+ * applications. By keeping your application's main thread responsive, you also prevent <a
+ * href="{@docRoot}guide/practices/design/responsiveness.html">ANR dialogs</a> from being shown to
+ * users.
*
- * <p class="note">Note that even though an Android device's disk is
- * often on flash memory, many devices run a filesystem on top of that
- * memory with very limited concurrency. It's often the case that
- * almost all disk accesses are fast, but may in individual cases be
- * dramatically slower when certain I/O is happening in the background
- * from other processes. If possible, it's best to assume that such
- * things are not fast.</p>
+ * <p class="note">Note that even though an Android device's disk is often on flash memory, many
+ * devices run a filesystem on top of that memory with very limited concurrency. It's often the case
+ * that almost all disk accesses are fast, but may in individual cases be dramatically slower when
+ * certain I/O is happening in the background from other processes. If possible, it's best to assume
+ * that such things are not fast.
*
- * <p>Example code to enable from early in your
- * {@link android.app.Application}, {@link android.app.Activity}, or
- * other application component's
- * {@link android.app.Application#onCreate} method:
+ * <p>Example code to enable from early in your {@link android.app.Application}, {@link
+ * android.app.Activity}, or other application component's {@link android.app.Application#onCreate}
+ * method:
*
* <pre>
* public void onCreate() {
@@ -99,36 +93,32 @@ import java.util.concurrent.atomic.AtomicInteger;
* }
* </pre>
*
- * <p>You can decide what should happen when a violation is detected.
- * For example, using {@link ThreadPolicy.Builder#penaltyLog} you can
- * watch the output of <code>adb logcat</code> while you use your
- * application to see the violations as they happen.
+ * <p>You can decide what should happen when a violation is detected. For example, using {@link
+ * ThreadPolicy.Builder#penaltyLog} you can watch the output of <code>adb logcat</code> while you
+ * use your application to see the violations as they happen.
*
- * <p>If you find violations that you feel are problematic, there are
- * a variety of tools to help solve them: threads, {@link android.os.Handler},
- * {@link android.os.AsyncTask}, {@link android.app.IntentService}, etc.
- * But don't feel compelled to fix everything that StrictMode finds. In particular,
- * many cases of disk access are often necessary during the normal activity lifecycle. Use
- * StrictMode to find things you did by accident. Network requests on the UI thread
+ * <p>If you find violations that you feel are problematic, there are a variety of tools to help
+ * solve them: threads, {@link android.os.Handler}, {@link android.os.AsyncTask}, {@link
+ * android.app.IntentService}, etc. But don't feel compelled to fix everything that StrictMode
+ * finds. In particular, many cases of disk access are often necessary during the normal activity
+ * lifecycle. Use StrictMode to find things you did by accident. Network requests on the UI thread
* are almost always a problem, though.
*
- * <p class="note">StrictMode is not a security mechanism and is not
- * guaranteed to find all disk or network accesses. While it does
- * propagate its state across process boundaries when doing
- * {@link android.os.Binder} calls, it's still ultimately a best
- * effort mechanism. Notably, disk or network access from JNI calls
- * won't necessarily trigger it. Future versions of Android may catch
- * more (or fewer) operations, so you should never leave StrictMode
- * enabled in applications distributed on Google Play.
+ * <p class="note">StrictMode is not a security mechanism and is not guaranteed to find all disk or
+ * network accesses. While it does propagate its state across process boundaries when doing {@link
+ * android.os.Binder} calls, it's still ultimately a best effort mechanism. Notably, disk or network
+ * access from JNI calls won't necessarily trigger it. Future versions of Android may catch more (or
+ * fewer) operations, so you should never leave StrictMode enabled in applications distributed on
+ * Google Play.
*/
public final class StrictMode {
private static final String TAG = "StrictMode";
private static final boolean LOG_V = Log.isLoggable(TAG, Log.VERBOSE);
/**
- * Boolean system property to disable strict mode checks outright.
- * Set this to 'true' to force disable; 'false' has no effect on other
- * enable/disable policy.
+ * Boolean system property to disable strict mode checks outright. Set this to 'true' to force
+ * disable; 'false' has no effect on other enable/disable policy.
+ *
* @hide
*/
public static final String DISABLE_PROPERTY = "persist.sys.strictmode.disable";
@@ -141,9 +131,9 @@ public final class StrictMode {
public static final String VISUAL_PROPERTY = "persist.sys.strictmode.visual";
/**
- * Temporary property used to include {@link #DETECT_VM_CLEARTEXT_NETWORK}
- * in {@link VmPolicy.Builder#detectAll()}. Apps can still always opt-into
- * detection using {@link VmPolicy.Builder#detectCleartextNetwork()}.
+ * Temporary property used to include {@link #DETECT_VM_CLEARTEXT_NETWORK} in {@link
+ * VmPolicy.Builder#detectAll()}. Apps can still always opt-into detection using {@link
+ * VmPolicy.Builder#detectCleartextNetwork()}.
*/
private static final String CLEARTEXT_PROPERTY = "persist.sys.strictmode.clear";
@@ -162,105 +152,96 @@ public final class StrictMode {
// Byte 1: Thread-policy
- /**
- * @hide
- */
- public static final int DETECT_DISK_WRITE = 0x01; // for ThreadPolicy
+ /** @hide */
+ public static final int DETECT_DISK_WRITE = 0x01; // for ThreadPolicy
- /**
- * @hide
- */
- public static final int DETECT_DISK_READ = 0x02; // for ThreadPolicy
+ /** @hide */
+ public static final int DETECT_DISK_READ = 0x02; // for ThreadPolicy
- /**
- * @hide
- */
- public static final int DETECT_NETWORK = 0x04; // for ThreadPolicy
+ /** @hide */
+ public static final int DETECT_NETWORK = 0x04; // for ThreadPolicy
/**
* For StrictMode.noteSlowCall()
*
* @hide
*/
- public static final int DETECT_CUSTOM = 0x08; // for ThreadPolicy
+ public static final int DETECT_CUSTOM = 0x08; // for ThreadPolicy
/**
* For StrictMode.noteResourceMismatch()
*
* @hide
*/
- public static final int DETECT_RESOURCE_MISMATCH = 0x10; // for ThreadPolicy
+ public static final int DETECT_RESOURCE_MISMATCH = 0x10; // for ThreadPolicy
- /**
- * @hide
- */
- public static final int DETECT_UNBUFFERED_IO = 0x20; // for ThreadPolicy
+ /** @hide */
+ public static final int DETECT_UNBUFFERED_IO = 0x20; // for ThreadPolicy
private static final int ALL_THREAD_DETECT_BITS =
- DETECT_DISK_WRITE | DETECT_DISK_READ | DETECT_NETWORK | DETECT_CUSTOM |
- DETECT_RESOURCE_MISMATCH | DETECT_UNBUFFERED_IO;
+ DETECT_DISK_WRITE
+ | DETECT_DISK_READ
+ | DETECT_NETWORK
+ | DETECT_CUSTOM
+ | DETECT_RESOURCE_MISMATCH
+ | DETECT_UNBUFFERED_IO;
// Byte 2: Process-policy
/**
* Note, a "VM_" bit, not thread.
+ *
* @hide
*/
- public static final int DETECT_VM_CURSOR_LEAKS = 0x01 << 8; // for VmPolicy
+ public static final int DETECT_VM_CURSOR_LEAKS = 0x01 << 8; // for VmPolicy
/**
* Note, a "VM_" bit, not thread.
+ *
* @hide
*/
- public static final int DETECT_VM_CLOSABLE_LEAKS = 0x02 << 8; // for VmPolicy
+ public static final int DETECT_VM_CLOSABLE_LEAKS = 0x02 << 8; // for VmPolicy
/**
* Note, a "VM_" bit, not thread.
+ *
* @hide
*/
- public static final int DETECT_VM_ACTIVITY_LEAKS = 0x04 << 8; // for VmPolicy
+ public static final int DETECT_VM_ACTIVITY_LEAKS = 0x04 << 8; // for VmPolicy
- /**
- * @hide
- */
- private static final int DETECT_VM_INSTANCE_LEAKS = 0x08 << 8; // for VmPolicy
+ /** @hide */
+ private static final int DETECT_VM_INSTANCE_LEAKS = 0x08 << 8; // for VmPolicy
- /**
- * @hide
- */
- public static final int DETECT_VM_REGISTRATION_LEAKS = 0x10 << 8; // for VmPolicy
+ /** @hide */
+ public static final int DETECT_VM_REGISTRATION_LEAKS = 0x10 << 8; // for VmPolicy
- /**
- * @hide
- */
- private static final int DETECT_VM_FILE_URI_EXPOSURE = 0x20 << 8; // for VmPolicy
+ /** @hide */
+ private static final int DETECT_VM_FILE_URI_EXPOSURE = 0x20 << 8; // for VmPolicy
- /**
- * @hide
- */
- private static final int DETECT_VM_CLEARTEXT_NETWORK = 0x40 << 8; // for VmPolicy
+ /** @hide */
+ private static final int DETECT_VM_CLEARTEXT_NETWORK = 0x40 << 8; // for VmPolicy
- /**
- * @hide
- */
- private static final int DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION = 0x80 << 8; // for VmPolicy
+ /** @hide */
+ private static final int DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION = 0x80 << 8; // for VmPolicy
- /**
- * @hide
- */
- private static final int DETECT_VM_UNTAGGED_SOCKET = 0x80 << 24; // for VmPolicy
+ /** @hide */
+ private static final int DETECT_VM_UNTAGGED_SOCKET = 0x80 << 24; // for VmPolicy
private static final int ALL_VM_DETECT_BITS =
- DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS |
- DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_INSTANCE_LEAKS |
- DETECT_VM_REGISTRATION_LEAKS | DETECT_VM_FILE_URI_EXPOSURE |
- DETECT_VM_CLEARTEXT_NETWORK | DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION |
- DETECT_VM_UNTAGGED_SOCKET;
+ DETECT_VM_CURSOR_LEAKS
+ | DETECT_VM_CLOSABLE_LEAKS
+ | DETECT_VM_ACTIVITY_LEAKS
+ | DETECT_VM_INSTANCE_LEAKS
+ | DETECT_VM_REGISTRATION_LEAKS
+ | DETECT_VM_FILE_URI_EXPOSURE
+ | DETECT_VM_CLEARTEXT_NETWORK
+ | DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION
+ | DETECT_VM_UNTAGGED_SOCKET;
// Byte 3: Penalty
/** {@hide} */
- public static final int PENALTY_LOG = 0x01 << 16; // normal android.util.Log
+ public static final int PENALTY_LOG = 0x01 << 16; // normal android.util.Log
/** {@hide} */
public static final int PENALTY_DIALOG = 0x02 << 16;
/** {@hide} */
@@ -271,13 +252,11 @@ public final class StrictMode {
public static final int PENALTY_DROPBOX = 0x20 << 16;
/**
- * Non-public penalty mode which overrides all the other penalty
- * bits and signals that we're in a Binder call and we should
- * ignore the other penalty bits and instead serialize back all
- * our offending stack traces to the caller to ultimately handle
- * in the originating process.
+ * Non-public penalty mode which overrides all the other penalty bits and signals that we're in
+ * a Binder call and we should ignore the other penalty bits and instead serialize back all our
+ * offending stack traces to the caller to ultimately handle in the originating process.
*
- * This must be kept in sync with the constant in libs/binder/Parcel.cpp
+ * <p>This must be kept in sync with the constant in libs/binder/Parcel.cpp
*
* @hide
*/
@@ -308,18 +287,23 @@ public final class StrictMode {
// CAUTION: we started stealing the top bits of Byte 4 for VM above
- /**
- * Mask of all the penalty bits valid for thread policies.
- */
+ /** Mask of all the penalty bits valid for thread policies. */
private static final int THREAD_PENALTY_MASK =
- PENALTY_LOG | PENALTY_DIALOG | PENALTY_DEATH | PENALTY_DROPBOX | PENALTY_GATHER |
- PENALTY_DEATH_ON_NETWORK | PENALTY_FLASH;
-
- /**
- * Mask of all the penalty bits valid for VM policies.
- */
- private static final int VM_PENALTY_MASK = PENALTY_LOG | PENALTY_DEATH | PENALTY_DROPBOX
- | PENALTY_DEATH_ON_CLEARTEXT_NETWORK | PENALTY_DEATH_ON_FILE_URI_EXPOSURE;
+ PENALTY_LOG
+ | PENALTY_DIALOG
+ | PENALTY_DEATH
+ | PENALTY_DROPBOX
+ | PENALTY_GATHER
+ | PENALTY_DEATH_ON_NETWORK
+ | PENALTY_FLASH;
+
+ /** Mask of all the penalty bits valid for VM policies. */
+ private static final int VM_PENALTY_MASK =
+ PENALTY_LOG
+ | PENALTY_DEATH
+ | PENALTY_DROPBOX
+ | PENALTY_DEATH_ON_CLEARTEXT_NETWORK
+ | PENALTY_DEATH_ON_FILE_URI_EXPOSURE;
/** {@hide} */
public static final int NETWORK_POLICY_ACCEPT = 0;
@@ -330,14 +314,16 @@ public final class StrictMode {
// TODO: wrap in some ImmutableHashMap thing.
// Note: must be before static initialization of sVmPolicy.
- private static final HashMap<Class, Integer> EMPTY_CLASS_LIMIT_MAP = new HashMap<Class, Integer>();
+ private static final HashMap<Class, Integer> EMPTY_CLASS_LIMIT_MAP =
+ new HashMap<Class, Integer>();
/**
* The current VmPolicy in effect.
*
- * TODO: these are redundant (mask is in VmPolicy). Should remove sVmPolicyMask.
+ * <p>TODO: these are redundant (mask is in VmPolicy). Should remove sVmPolicyMask.
*/
private static volatile int sVmPolicyMask = 0;
+
private static volatile VmPolicy sVmPolicy = VmPolicy.LAX;
/** {@hide} */
@@ -355,8 +341,8 @@ public final class StrictMode {
}
/**
- * The number of threads trying to do an async dropbox write.
- * Just to limit ourselves out of paranoia.
+ * The number of threads trying to do an async dropbox write. Just to limit ourselves out of
+ * paranoia.
*/
private static final AtomicInteger sDropboxCallsInFlight = new AtomicInteger(0);
@@ -365,18 +351,15 @@ public final class StrictMode {
/**
* {@link StrictMode} policy applied to a certain thread.
*
- * <p>The policy is enabled by {@link #setThreadPolicy}. The current policy
- * can be retrieved with {@link #getThreadPolicy}.
+ * <p>The policy is enabled by {@link #setThreadPolicy}. The current policy can be retrieved
+ * with {@link #getThreadPolicy}.
*
- * <p>Note that multiple penalties may be provided and they're run
- * in order from least to most severe (logging before process
- * death, for example). There's currently no mechanism to choose
+ * <p>Note that multiple penalties may be provided and they're run in order from least to most
+ * severe (logging before process death, for example). There's currently no mechanism to choose
* different penalties for different detected actions.
*/
public static final class ThreadPolicy {
- /**
- * The default, lax policy which doesn't catch anything.
- */
+ /** The default, lax policy which doesn't catch anything. */
public static final ThreadPolicy LAX = new ThreadPolicy(0);
final int mask;
@@ -391,16 +374,15 @@ public final class StrictMode {
}
/**
- * Creates {@link ThreadPolicy} instances. Methods whose names start
- * with {@code detect} specify what problems we should look
- * for. Methods whose names start with {@code penalty} specify what
- * we should do when we detect a problem.
+ * Creates {@link ThreadPolicy} instances. Methods whose names start with {@code detect}
+ * specify what problems we should look for. Methods whose names start with {@code penalty}
+ * specify what we should do when we detect a problem.
*
- * <p>You can call as many {@code detect} and {@code penalty}
- * methods as you like. Currently order is insignificant: all
- * penalties apply to all detected problems.
+ * <p>You can call as many {@code detect} and {@code penalty} methods as you like. Currently
+ * order is insignificant: all penalties apply to all detected problems.
*
* <p>For example, detect everything and log anything that's found:
+ *
* <pre>
* StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
* .detectAll()
@@ -413,18 +395,15 @@ public final class StrictMode {
private int mMask = 0;
/**
- * Create a Builder that detects nothing and has no
- * violations. (but note that {@link #build} will default
- * to enabling {@link #penaltyLog} if no other penalties
- * are specified)
+ * Create a Builder that detects nothing and has no violations. (but note that {@link
+ * #build} will default to enabling {@link #penaltyLog} if no other penalties are
+ * specified)
*/
public Builder() {
mMask = 0;
}
- /**
- * Initialize a Builder from an existing ThreadPolicy.
- */
+ /** Initialize a Builder from an existing ThreadPolicy. */
public Builder(ThreadPolicy policy) {
mMask = policy.mask;
}
@@ -432,8 +411,8 @@ public final class StrictMode {
/**
* Detect everything that's potentially suspect.
*
- * <p>As of the Gingerbread release this includes network and
- * disk operations but will likely expand in future releases.
+ * <p>As of the Gingerbread release this includes network and disk operations but will
+ * likely expand in future releases.
*/
public Builder detectAll() {
detectDiskReads();
@@ -453,135 +432,106 @@ public final class StrictMode {
return this;
}
- /**
- * Disable the detection of everything.
- */
+ /** Disable the detection of everything. */
public Builder permitAll() {
return disable(ALL_THREAD_DETECT_BITS);
}
- /**
- * Enable detection of network operations.
- */
+ /** Enable detection of network operations. */
public Builder detectNetwork() {
return enable(DETECT_NETWORK);
}
- /**
- * Disable detection of network operations.
- */
+ /** Disable detection of network operations. */
public Builder permitNetwork() {
return disable(DETECT_NETWORK);
}
- /**
- * Enable detection of disk reads.
- */
+ /** Enable detection of disk reads. */
public Builder detectDiskReads() {
return enable(DETECT_DISK_READ);
}
- /**
- * Disable detection of disk reads.
- */
+ /** Disable detection of disk reads. */
public Builder permitDiskReads() {
return disable(DETECT_DISK_READ);
}
- /**
- * Enable detection of slow calls.
- */
+ /** Enable detection of slow calls. */
public Builder detectCustomSlowCalls() {
return enable(DETECT_CUSTOM);
}
- /**
- * Disable detection of slow calls.
- */
+ /** Disable detection of slow calls. */
public Builder permitCustomSlowCalls() {
return disable(DETECT_CUSTOM);
}
- /**
- * Disable detection of mismatches between defined resource types
- * and getter calls.
- */
+ /** Disable detection of mismatches between defined resource types and getter calls. */
public Builder permitResourceMismatches() {
return disable(DETECT_RESOURCE_MISMATCH);
}
- /**
- * Detect unbuffered input/output operations.
- */
+ /** Detect unbuffered input/output operations. */
public Builder detectUnbufferedIo() {
return enable(DETECT_UNBUFFERED_IO);
}
- /**
- * Disable detection of unbuffered input/output operations.
- */
+ /** Disable detection of unbuffered input/output operations. */
public Builder permitUnbufferedIo() {
return disable(DETECT_UNBUFFERED_IO);
}
/**
- * Enables detection of mismatches between defined resource types
- * and getter calls.
- * <p>
- * This helps detect accidental type mismatches and potentially
- * expensive type conversions when obtaining typed resources.
- * <p>
- * For example, a strict mode violation would be thrown when
- * calling {@link android.content.res.TypedArray#getInt(int, int)}
- * on an index that contains a String-type resource. If the string
- * value can be parsed as an integer, this method call will return
- * a value without crashing; however, the developer should format
- * the resource as an integer to avoid unnecessary type conversion.
+ * Enables detection of mismatches between defined resource types and getter calls.
+ *
+ * <p>This helps detect accidental type mismatches and potentially expensive type
+ * conversions when obtaining typed resources.
+ *
+ * <p>For example, a strict mode violation would be thrown when calling {@link
+ * android.content.res.TypedArray#getInt(int, int)} on an index that contains a
+ * String-type resource. If the string value can be parsed as an integer, this method
+ * call will return a value without crashing; however, the developer should format the
+ * resource as an integer to avoid unnecessary type conversion.
*/
public Builder detectResourceMismatches() {
return enable(DETECT_RESOURCE_MISMATCH);
}
- /**
- * Enable detection of disk writes.
- */
+ /** Enable detection of disk writes. */
public Builder detectDiskWrites() {
return enable(DETECT_DISK_WRITE);
}
- /**
- * Disable detection of disk writes.
- */
+ /** Disable detection of disk writes. */
public Builder permitDiskWrites() {
return disable(DETECT_DISK_WRITE);
}
/**
- * Show an annoying dialog to the developer on detected
- * violations, rate-limited to be only a little annoying.
+ * Show an annoying dialog to the developer on detected violations, rate-limited to be
+ * only a little annoying.
*/
public Builder penaltyDialog() {
return enable(PENALTY_DIALOG);
}
/**
- * Crash the whole process on violation. This penalty runs at
- * the end of all enabled penalties so you'll still get
- * see logging or other violations before the process dies.
+ * Crash the whole process on violation. This penalty runs at the end of all enabled
+ * penalties so you'll still get see logging or other violations before the process
+ * dies.
*
- * <p>Unlike {@link #penaltyDeathOnNetwork}, this applies
- * to disk reads, disk writes, and network usage if their
- * corresponding detect flags are set.
+ * <p>Unlike {@link #penaltyDeathOnNetwork}, this applies to disk reads, disk writes,
+ * and network usage if their corresponding detect flags are set.
*/
public Builder penaltyDeath() {
return enable(PENALTY_DEATH);
}
/**
- * Crash the whole process on any network usage. Unlike
- * {@link #penaltyDeath}, this penalty runs
- * <em>before</em> anything else. You must still have
- * called {@link #detectNetwork} to enable this.
+ * Crash the whole process on any network usage. Unlike {@link #penaltyDeath}, this
+ * penalty runs <em>before</em> anything else. You must still have called {@link
+ * #detectNetwork} to enable this.
*
* <p>In the Honeycomb or later SDKs, this is on by default.
*/
@@ -589,25 +539,20 @@ public final class StrictMode {
return enable(PENALTY_DEATH_ON_NETWORK);
}
- /**
- * Flash the screen during a violation.
- */
+ /** Flash the screen during a violation. */
public Builder penaltyFlashScreen() {
return enable(PENALTY_FLASH);
}
- /**
- * Log detected violations to the system log.
- */
+ /** Log detected violations to the system log. */
public Builder penaltyLog() {
return enable(PENALTY_LOG);
}
/**
- * Enable detected violations log a stacktrace and timing data
- * to the {@link android.os.DropBoxManager DropBox} on policy
- * violation. Intended mostly for platform integrators doing
- * beta user field data collection.
+ * Enable detected violations log a stacktrace and timing data to the {@link
+ * android.os.DropBoxManager DropBox} on policy violation. Intended mostly for platform
+ * integrators doing beta user field data collection.
*/
public Builder penaltyDropBox() {
return enable(PENALTY_DROPBOX);
@@ -626,16 +571,19 @@ public final class StrictMode {
/**
* Construct the ThreadPolicy instance.
*
- * <p>Note: if no penalties are enabled before calling
- * <code>build</code>, {@link #penaltyLog} is implicitly
- * set.
+ * <p>Note: if no penalties are enabled before calling <code>build</code>, {@link
+ * #penaltyLog} is implicitly set.
*/
public ThreadPolicy build() {
// If there are detection bits set but no violation bits
// set, enable simple logging.
- if (mMask != 0 &&
- (mMask & (PENALTY_DEATH | PENALTY_LOG |
- PENALTY_DROPBOX | PENALTY_DIALOG)) == 0) {
+ if (mMask != 0
+ && (mMask
+ & (PENALTY_DEATH
+ | PENALTY_LOG
+ | PENALTY_DROPBOX
+ | PENALTY_DIALOG))
+ == 0) {
penaltyLog();
}
return new ThreadPolicy(mMask);
@@ -649,9 +597,7 @@ public final class StrictMode {
* <p>The policy is enabled by {@link #setVmPolicy}.
*/
public static final class VmPolicy {
- /**
- * The default, lax policy which doesn't catch anything.
- */
+ /** The default, lax policy which doesn't catch anything. */
public static final VmPolicy LAX = new VmPolicy(0, EMPTY_CLASS_LIMIT_MAP);
final int mask;
@@ -673,16 +619,15 @@ public final class StrictMode {
}
/**
- * Creates {@link VmPolicy} instances. Methods whose names start
- * with {@code detect} specify what problems we should look
- * for. Methods whose names start with {@code penalty} specify what
- * we should do when we detect a problem.
+ * Creates {@link VmPolicy} instances. Methods whose names start with {@code detect} specify
+ * what problems we should look for. Methods whose names start with {@code penalty} specify
+ * what we should do when we detect a problem.
*
- * <p>You can call as many {@code detect} and {@code penalty}
- * methods as you like. Currently order is insignificant: all
- * penalties apply to all detected problems.
+ * <p>You can call as many {@code detect} and {@code penalty} methods as you like. Currently
+ * order is insignificant: all penalties apply to all detected problems.
*
* <p>For example, detect everything and log anything that's found:
+ *
* <pre>
* StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder()
* .detectAll()
@@ -694,16 +639,14 @@ public final class StrictMode {
public static final class Builder {
private int mMask;
- private HashMap<Class, Integer> mClassInstanceLimit; // null until needed
- private boolean mClassInstanceLimitNeedCow = false; // need copy-on-write
+ private HashMap<Class, Integer> mClassInstanceLimit; // null until needed
+ private boolean mClassInstanceLimitNeedCow = false; // need copy-on-write
public Builder() {
mMask = 0;
}
- /**
- * Build upon an existing VmPolicy.
- */
+ /** Build upon an existing VmPolicy. */
public Builder(VmPolicy base) {
mMask = base.mask;
mClassInstanceLimitNeedCow = true;
@@ -711,16 +654,16 @@ public final class StrictMode {
}
/**
- * Set an upper bound on how many instances of a class can be in memory
- * at once. Helps to prevent object leaks.
+ * Set an upper bound on how many instances of a class can be in memory at once. Helps
+ * to prevent object leaks.
*/
public Builder setClassInstanceLimit(Class klass, int instanceLimit) {
if (klass == null) {
throw new NullPointerException("klass == null");
}
if (mClassInstanceLimitNeedCow) {
- if (mClassInstanceLimit.containsKey(klass) &&
- mClassInstanceLimit.get(klass) == instanceLimit) {
+ if (mClassInstanceLimit.containsKey(klass)
+ && mClassInstanceLimit.get(klass) == instanceLimit) {
// no-op; don't break COW
return this;
}
@@ -734,9 +677,7 @@ public final class StrictMode {
return this;
}
- /**
- * Detect leaks of {@link android.app.Activity} subclasses.
- */
+ /** Detect leaks of {@link android.app.Activity} subclasses. */
public Builder detectActivityLeaks() {
return enable(DETECT_VM_ACTIVITY_LEAKS);
}
@@ -744,9 +685,8 @@ public final class StrictMode {
/**
* Detect everything that's potentially suspect.
*
- * <p>In the Honeycomb release this includes leaks of
- * SQLite cursors, Activities, and other closable objects
- * but will likely expand in future releases.
+ * <p>In the Honeycomb release this includes leaks of SQLite cursors, Activities, and
+ * other closable objects but will likely expand in future releases.
*/
public Builder detectAll() {
detectLeakedSqlLiteObjects();
@@ -777,53 +717,46 @@ public final class StrictMode {
}
/**
- * Detect when an
- * {@link android.database.sqlite.SQLiteCursor} or other
- * SQLite object is finalized without having been closed.
+ * Detect when an {@link android.database.sqlite.SQLiteCursor} or other SQLite object is
+ * finalized without having been closed.
*
- * <p>You always want to explicitly close your SQLite
- * cursors to avoid unnecessary database contention and
- * temporary memory leaks.
+ * <p>You always want to explicitly close your SQLite cursors to avoid unnecessary
+ * database contention and temporary memory leaks.
*/
public Builder detectLeakedSqlLiteObjects() {
return enable(DETECT_VM_CURSOR_LEAKS);
}
/**
- * Detect when an {@link java.io.Closeable} or other
- * object with a explict termination method is finalized
- * without having been closed.
+ * Detect when an {@link java.io.Closeable} or other object with a explict termination
+ * method is finalized without having been closed.
*
- * <p>You always want to explicitly close such objects to
- * avoid unnecessary resources leaks.
+ * <p>You always want to explicitly close such objects to avoid unnecessary resources
+ * leaks.
*/
public Builder detectLeakedClosableObjects() {
return enable(DETECT_VM_CLOSABLE_LEAKS);
}
/**
- * Detect when a {@link BroadcastReceiver} or
- * {@link ServiceConnection} is leaked during {@link Context}
- * teardown.
+ * Detect when a {@link BroadcastReceiver} or {@link ServiceConnection} is leaked during
+ * {@link Context} teardown.
*/
public Builder detectLeakedRegistrationObjects() {
return enable(DETECT_VM_REGISTRATION_LEAKS);
}
/**
- * Detect when the calling application exposes a {@code file://}
- * {@link android.net.Uri} to another app.
- * <p>
- * This exposure is discouraged since the receiving app may not have
- * access to the shared path. For example, the receiving app may not
- * have requested the
- * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} runtime
- * permission, or the platform may be sharing the
- * {@link android.net.Uri} across user profile boundaries.
- * <p>
- * Instead, apps should use {@code content://} Uris so the platform
- * can extend temporary permission for the receiving app to access
- * the resource.
+ * Detect when the calling application exposes a {@code file://} {@link android.net.Uri}
+ * to another app.
+ *
+ * <p>This exposure is discouraged since the receiving app may not have access to the
+ * shared path. For example, the receiving app may not have requested the {@link
+ * android.Manifest.permission#READ_EXTERNAL_STORAGE} runtime permission, or the
+ * platform may be sharing the {@link android.net.Uri} across user profile boundaries.
+ *
+ * <p>Instead, apps should use {@code content://} Uris so the platform can extend
+ * temporary permission for the receiving app to access the resource.
*
* @see android.support.v4.content.FileProvider
* @see Intent#FLAG_GRANT_READ_URI_PERMISSION
@@ -833,34 +766,32 @@ public final class StrictMode {
}
/**
- * Detect any network traffic from the calling app which is not
- * wrapped in SSL/TLS. This can help you detect places that your app
- * is inadvertently sending cleartext data across the network.
- * <p>
- * Using {@link #penaltyDeath()} or
- * {@link #penaltyDeathOnCleartextNetwork()} will block further
- * traffic on that socket to prevent accidental data leakage, in
- * addition to crashing your process.
- * <p>
- * Using {@link #penaltyDropBox()} will log the raw contents of the
- * packet that triggered the violation.
- * <p>
- * This inspects both IPv4/IPv6 and TCP/UDP network traffic, but it
- * may be subject to false positives, such as when STARTTLS
- * protocols or HTTP proxies are used.
+ * Detect any network traffic from the calling app which is not wrapped in SSL/TLS. This
+ * can help you detect places that your app is inadvertently sending cleartext data
+ * across the network.
+ *
+ * <p>Using {@link #penaltyDeath()} or {@link #penaltyDeathOnCleartextNetwork()} will
+ * block further traffic on that socket to prevent accidental data leakage, in addition
+ * to crashing your process.
+ *
+ * <p>Using {@link #penaltyDropBox()} will log the raw contents of the packet that
+ * triggered the violation.
+ *
+ * <p>This inspects both IPv4/IPv6 and TCP/UDP network traffic, but it may be subject to
+ * false positives, such as when STARTTLS protocols or HTTP proxies are used.
*/
public Builder detectCleartextNetwork() {
return enable(DETECT_VM_CLEARTEXT_NETWORK);
}
/**
- * Detect when the calling application sends a {@code content://}
- * {@link android.net.Uri} to another app without setting
- * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} or
- * {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION}.
- * <p>
- * Forgetting to include one or more of these flags when sending an
- * intent is typically an app bug.
+ * Detect when the calling application sends a {@code content://} {@link
+ * android.net.Uri} to another app without setting {@link
+ * Intent#FLAG_GRANT_READ_URI_PERMISSION} or {@link
+ * Intent#FLAG_GRANT_WRITE_URI_PERMISSION}.
+ *
+ * <p>Forgetting to include one or more of these flags when sending an intent is
+ * typically an app bug.
*
* @see Intent#FLAG_GRANT_READ_URI_PERMISSION
* @see Intent#FLAG_GRANT_WRITE_URI_PERMISSION
@@ -870,12 +801,11 @@ public final class StrictMode {
}
/**
- * Detect any sockets in the calling app which have not been tagged
- * using {@link TrafficStats}. Tagging sockets can help you
- * investigate network usage inside your app, such as a narrowing
- * down heavy usage to a specific library or component.
- * <p>
- * This currently does not detect sockets created in native code.
+ * Detect any sockets in the calling app which have not been tagged using {@link
+ * TrafficStats}. Tagging sockets can help you investigate network usage inside your
+ * app, such as a narrowing down heavy usage to a specific library or component.
+ *
+ * <p>This currently does not detect sockets created in native code.
*
* @see TrafficStats#setThreadStatsTag(int)
* @see TrafficStats#tagSocket(java.net.Socket)
@@ -886,17 +816,16 @@ public final class StrictMode {
}
/**
- * Crashes the whole process on violation. This penalty runs at the
- * end of all enabled penalties so you'll still get your logging or
- * other violations before the process dies.
+ * Crashes the whole process on violation. This penalty runs at the end of all enabled
+ * penalties so you'll still get your logging or other violations before the process
+ * dies.
*/
public Builder penaltyDeath() {
return enable(PENALTY_DEATH);
}
/**
- * Crashes the whole process when cleartext network traffic is
- * detected.
+ * Crashes the whole process when cleartext network traffic is detected.
*
* @see #detectCleartextNetwork()
*/
@@ -905,8 +834,8 @@ public final class StrictMode {
}
/**
- * Crashes the whole process when a {@code file://}
- * {@link android.net.Uri} is exposed beyond this app.
+ * Crashes the whole process when a {@code file://} {@link android.net.Uri} is exposed
+ * beyond this app.
*
* @see #detectFileUriExposure()
*/
@@ -914,18 +843,15 @@ public final class StrictMode {
return enable(PENALTY_DEATH_ON_FILE_URI_EXPOSURE);
}
- /**
- * Log detected violations to the system log.
- */
+ /** Log detected violations to the system log. */
public Builder penaltyLog() {
return enable(PENALTY_LOG);
}
/**
- * Enable detected violations log a stacktrace and timing data
- * to the {@link android.os.DropBoxManager DropBox} on policy
- * violation. Intended mostly for platform integrators doing
- * beta user field data collection.
+ * Enable detected violations log a stacktrace and timing data to the {@link
+ * android.os.DropBoxManager DropBox} on policy violation. Intended mostly for platform
+ * integrators doing beta user field data collection.
*/
public Builder penaltyDropBox() {
return enable(PENALTY_DROPBOX);
@@ -944,48 +870,51 @@ public final class StrictMode {
/**
* Construct the VmPolicy instance.
*
- * <p>Note: if no penalties are enabled before calling
- * <code>build</code>, {@link #penaltyLog} is implicitly
- * set.
+ * <p>Note: if no penalties are enabled before calling <code>build</code>, {@link
+ * #penaltyLog} is implicitly set.
*/
public VmPolicy build() {
// If there are detection bits set but no violation bits
// set, enable simple logging.
- if (mMask != 0 &&
- (mMask & (PENALTY_DEATH | PENALTY_LOG |
- PENALTY_DROPBOX | PENALTY_DIALOG)) == 0) {
+ if (mMask != 0
+ && (mMask
+ & (PENALTY_DEATH
+ | PENALTY_LOG
+ | PENALTY_DROPBOX
+ | PENALTY_DIALOG))
+ == 0) {
penaltyLog();
}
- return new VmPolicy(mMask,
+ return new VmPolicy(
+ mMask,
mClassInstanceLimit != null ? mClassInstanceLimit : EMPTY_CLASS_LIMIT_MAP);
}
}
}
/**
- * Log of strict mode violation stack traces that have occurred
- * during a Binder call, to be serialized back later to the caller
- * via Parcel.writeNoException() (amusingly) where the caller can
- * choose how to react.
+ * Log of strict mode violation stack traces that have occurred during a Binder call, to be
+ * serialized back later to the caller via Parcel.writeNoException() (amusingly) where the
+ * caller can choose how to react.
*/
private static final ThreadLocal<ArrayList<ViolationInfo>> gatheredViolations =
new ThreadLocal<ArrayList<ViolationInfo>>() {
- @Override protected ArrayList<ViolationInfo> initialValue() {
- // Starts null to avoid unnecessary allocations when
- // checking whether there are any violations or not in
- // hasGatheredViolations() below.
- return null;
- }
- };
+ @Override
+ protected ArrayList<ViolationInfo> initialValue() {
+ // Starts null to avoid unnecessary allocations when
+ // checking whether there are any violations or not in
+ // hasGatheredViolations() below.
+ return null;
+ }
+ };
/**
- * Sets the policy for what actions on the current thread should
- * be detected, as well as the penalty if such actions occur.
+ * Sets the policy for what actions on the current thread should be detected, as well as the
+ * penalty if such actions occur.
*
- * <p>Internally this sets a thread-local variable which is
- * propagated across cross-process IPC calls, meaning you can
- * catch violations when a system service or another process
- * accesses the disk or network on your behalf.
+ * <p>Internally this sets a thread-local variable which is propagated across cross-process IPC
+ * calls, meaning you can catch violations when a system service or another process accesses the
+ * disk or network on your behalf.
*
* @param policy the policy to put into place
*/
@@ -1016,7 +945,7 @@ public final class StrictMode {
if (policy instanceof AndroidBlockGuardPolicy) {
androidPolicy = (AndroidBlockGuardPolicy) policy;
} else {
- androidPolicy = threadAndroidPolicy.get();
+ androidPolicy = THREAD_ANDROID_POLICY.get();
BlockGuard.setThreadPolicy(androidPolicy);
}
androidPolicy.setPolicyMask(policyMask);
@@ -1030,63 +959,49 @@ public final class StrictMode {
CloseGuard.setEnabled(enabled);
}
- /**
- * @hide
- */
+ /** @hide */
public static class StrictModeViolation extends BlockGuard.BlockGuardPolicyException {
public StrictModeViolation(int policyState, int policyViolated, String message) {
super(policyState, policyViolated, message);
}
}
- /**
- * @hide
- */
+ /** @hide */
public static class StrictModeNetworkViolation extends StrictModeViolation {
public StrictModeNetworkViolation(int policyMask) {
super(policyMask, DETECT_NETWORK, null);
}
}
- /**
- * @hide
- */
+ /** @hide */
private static class StrictModeDiskReadViolation extends StrictModeViolation {
public StrictModeDiskReadViolation(int policyMask) {
super(policyMask, DETECT_DISK_READ, null);
}
}
- /**
- * @hide
- */
- private static class StrictModeDiskWriteViolation extends StrictModeViolation {
+ /** @hide */
+ private static class StrictModeDiskWriteViolation extends StrictModeViolation {
public StrictModeDiskWriteViolation(int policyMask) {
super(policyMask, DETECT_DISK_WRITE, null);
}
}
- /**
- * @hide
- */
+ /** @hide */
private static class StrictModeCustomViolation extends StrictModeViolation {
public StrictModeCustomViolation(int policyMask, String name) {
super(policyMask, DETECT_CUSTOM, name);
}
}
- /**
- * @hide
- */
+ /** @hide */
private static class StrictModeResourceMismatchViolation extends StrictModeViolation {
public StrictModeResourceMismatchViolation(int policyMask, Object tag) {
super(policyMask, DETECT_RESOURCE_MISMATCH, tag != null ? tag.toString() : null);
}
}
- /**
- * @hide
- */
+ /** @hide */
private static class StrictModeUnbufferedIOViolation extends StrictModeViolation {
public StrictModeUnbufferedIOViolation(int policyMask) {
super(policyMask, DETECT_UNBUFFERED_IO, null);
@@ -1097,16 +1012,13 @@ public final class StrictMode {
* Returns the bitmask of the current thread's policy.
*
* @return the bitmask of all the DETECT_* and PENALTY_* bits currently enabled
- *
* @hide
*/
public static int getThreadPolicyMask() {
return BlockGuard.getThreadPolicy().getPolicyMask();
}
- /**
- * Returns the current thread's policy.
- */
+ /** Returns the current thread's policy. */
public static ThreadPolicy getThreadPolicy() {
// TODO: this was a last minute Gingerbread API change (to
// introduce VmPolicy cleanly) but this isn't particularly
@@ -1116,14 +1028,13 @@ public final class StrictMode {
}
/**
- * A convenience wrapper that takes the current
- * {@link ThreadPolicy} from {@link #getThreadPolicy}, modifies it
- * to permit both disk reads &amp; writes, and sets the new policy
- * with {@link #setThreadPolicy}, returning the old policy so you
- * can restore it at the end of a block.
+ * A convenience wrapper that takes the current {@link ThreadPolicy} from {@link
+ * #getThreadPolicy}, modifies it to permit both disk reads &amp; writes, and sets the new
+ * policy with {@link #setThreadPolicy}, returning the old policy so you can restore it at the
+ * end of a block.
*
- * @return the old policy, to be passed to {@link #setThreadPolicy} to
- * restore the policy at the end of a block
+ * @return the old policy, to be passed to {@link #setThreadPolicy} to restore the policy at the
+ * end of a block
*/
public static ThreadPolicy allowThreadDiskWrites() {
int oldPolicyMask = getThreadPolicyMask();
@@ -1135,14 +1046,11 @@ public final class StrictMode {
}
/**
- * A convenience wrapper that takes the current
- * {@link ThreadPolicy} from {@link #getThreadPolicy}, modifies it
- * to permit disk reads, and sets the new policy
- * with {@link #setThreadPolicy}, returning the old policy so you
- * can restore it at the end of a block.
+ * A convenience wrapper that takes the current {@link ThreadPolicy} from {@link
+ * #getThreadPolicy}, modifies it to permit disk reads, and sets the new policy with {@link
+ * #setThreadPolicy}, returning the old policy so you can restore it at the end of a block.
*
- * @return the old policy, to be passed to setThreadPolicy to
- * restore the policy.
+ * @return the old policy, to be passed to setThreadPolicy to restore the policy.
*/
public static ThreadPolicy allowThreadDiskReads() {
int oldPolicyMask = getThreadPolicyMask();
@@ -1182,8 +1090,8 @@ public final class StrictMode {
* @hide
*/
public static boolean conditionallyEnableDebugLogging() {
- boolean doFlashes = SystemProperties.getBoolean(VISUAL_PROPERTY, false)
- && !amTheSystemServerProcess();
+ boolean doFlashes =
+ SystemProperties.getBoolean(VISUAL_PROPERTY, false) && !amTheSystemServerProcess();
final boolean suppress = SystemProperties.getBoolean(DISABLE_PROPERTY, false);
// For debug builds, log event loop stalls to dropbox for analysis.
@@ -1201,9 +1109,10 @@ public final class StrictMode {
}
// Thread policy controls BlockGuard.
- int threadPolicyMask = StrictMode.DETECT_DISK_WRITE |
- StrictMode.DETECT_DISK_READ |
- StrictMode.DETECT_NETWORK;
+ int threadPolicyMask =
+ StrictMode.DETECT_DISK_WRITE
+ | StrictMode.DETECT_DISK_READ
+ | StrictMode.DETECT_NETWORK;
if (!Build.IS_USER) {
threadPolicyMask |= StrictMode.PENALTY_DROPBOX;
@@ -1243,8 +1152,7 @@ public final class StrictMode {
}
/**
- * Used by the framework to make network usage on the main
- * thread a fatal error.
+ * Used by the framework to make network usage on the main thread a fatal error.
*
* @hide
*/
@@ -1264,8 +1172,8 @@ public final class StrictMode {
}
/**
- * Used by lame internal apps that haven't done the hard work to get
- * themselves off file:// Uris yet.
+ * Used by lame internal apps that haven't done the hard work to get themselves off file:// Uris
+ * yet.
*
* @hide
*/
@@ -1274,17 +1182,14 @@ public final class StrictMode {
}
/**
- * Parses the BlockGuard policy mask out from the Exception's
- * getMessage() String value. Kinda gross, but least
- * invasive. :/
+ * Parses the BlockGuard policy mask out from the Exception's getMessage() String value. Kinda
+ * gross, but least invasive. :/
*
- * Input is of the following forms:
- * "policy=137 violation=64"
- * "policy=137 violation=64 msg=Arbitrary text"
+ * <p>Input is of the following forms: "policy=137 violation=64" "policy=137 violation=64
+ * msg=Arbitrary text"
*
- * Returns 0 on failure, which is a valid policy, but not a
- * valid policy during a violation (else there must've been
- * some policy in effect to violate).
+ * <p>Returns 0 on failure, which is a valid policy, but not a valid policy during a violation
+ * (else there must've been some policy in effect to violate).
*/
private static int parsePolicyFromMessage(String message) {
if (message == null || !message.startsWith("policy=")) {
@@ -1302,9 +1207,7 @@ public final class StrictMode {
}
}
- /**
- * Like parsePolicyFromMessage(), but returns the violation.
- */
+ /** Like parsePolicyFromMessage(), but returns the violation. */
private static int parseViolationFromMessage(String message) {
if (message == null) {
return 0;
@@ -1328,25 +1231,28 @@ public final class StrictMode {
private static final ThreadLocal<ArrayList<ViolationInfo>> violationsBeingTimed =
new ThreadLocal<ArrayList<ViolationInfo>>() {
- @Override protected ArrayList<ViolationInfo> initialValue() {
- return new ArrayList<ViolationInfo>();
- }
- };
+ @Override
+ protected ArrayList<ViolationInfo> initialValue() {
+ return new ArrayList<ViolationInfo>();
+ }
+ };
// Note: only access this once verifying the thread has a Looper.
- private static final ThreadLocal<Handler> threadHandler = new ThreadLocal<Handler>() {
- @Override protected Handler initialValue() {
- return new Handler();
- }
- };
+ private static final ThreadLocal<Handler> THREAD_HANDLER =
+ new ThreadLocal<Handler>() {
+ @Override
+ protected Handler initialValue() {
+ return new Handler();
+ }
+ };
- private static final ThreadLocal<AndroidBlockGuardPolicy>
- threadAndroidPolicy = new ThreadLocal<AndroidBlockGuardPolicy>() {
- @Override
- protected AndroidBlockGuardPolicy initialValue() {
- return new AndroidBlockGuardPolicy(0);
- }
- };
+ private static final ThreadLocal<AndroidBlockGuardPolicy> THREAD_ANDROID_POLICY =
+ new ThreadLocal<AndroidBlockGuardPolicy>() {
+ @Override
+ protected AndroidBlockGuardPolicy initialValue() {
+ return new AndroidBlockGuardPolicy(0);
+ }
+ };
private static boolean tooManyViolationsThisLoop() {
return violationsBeingTimed.get().size() >= MAX_OFFENSES_PER_LOOP;
@@ -1395,7 +1301,8 @@ public final class StrictMode {
if (tooManyViolationsThisLoop()) {
return;
}
- BlockGuard.BlockGuardPolicyException e = new StrictModeCustomViolation(mPolicyMask, name);
+ BlockGuard.BlockGuardPolicyException e =
+ new StrictModeCustomViolation(mPolicyMask, name);
e.fillInStackTrace();
startHandlingViolationException(e);
}
@@ -1496,9 +1403,8 @@ public final class StrictMode {
//
// TODO: if in gather mode, ignore Looper.myLooper() and always
// go into this immediate mode?
- if (looper == null ||
- (info.policy & THREAD_PENALTY_MASK) == PENALTY_DEATH) {
- info.durationMillis = -1; // unknown (redundant, already set)
+ if (looper == null || (info.policy & THREAD_PENALTY_MASK) == PENALTY_DEATH) {
+ info.durationMillis = -1; // unknown (redundant, already set)
handleViolation(info);
return;
}
@@ -1516,8 +1422,8 @@ public final class StrictMode {
return;
}
- final IWindowManager windowManager = (info.policy & PENALTY_FLASH) != 0 ?
- sWindowManager.get() : null;
+ final IWindowManager windowManager =
+ (info.policy & PENALTY_FLASH) != 0 ? sWindowManager.get() : null;
if (windowManager != null) {
try {
windowManager.showStrictModeViolation(true);
@@ -1534,31 +1440,34 @@ public final class StrictMode {
// throttled back to 60fps via SurfaceFlinger/View
// invalidates, _not_ by posting frame updates every 16
// milliseconds.
- threadHandler.get().postAtFrontOfQueue(new Runnable() {
- public void run() {
- long loopFinishTime = SystemClock.uptimeMillis();
-
- // Note: we do this early, before handling the
- // violation below, as handling the violation
- // may include PENALTY_DEATH and we don't want
- // to keep the red border on.
- if (windowManager != null) {
- try {
- windowManager.showStrictModeViolation(false);
- } catch (RemoteException unused) {
- }
- }
-
- for (int n = 0; n < records.size(); ++n) {
- ViolationInfo v = records.get(n);
- v.violationNumThisLoop = n + 1;
- v.durationMillis =
- (int) (loopFinishTime - v.violationUptimeMillis);
- handleViolation(v);
- }
- records.clear();
- }
- });
+ THREAD_HANDLER
+ .get()
+ .postAtFrontOfQueue(
+ new Runnable() {
+ public void run() {
+ long loopFinishTime = SystemClock.uptimeMillis();
+
+ // Note: we do this early, before handling the
+ // violation below, as handling the violation
+ // may include PENALTY_DEATH and we don't want
+ // to keep the red border on.
+ if (windowManager != null) {
+ try {
+ windowManager.showStrictModeViolation(false);
+ } catch (RemoteException unused) {
+ }
+ }
+
+ for (int n = 0; n < records.size(); ++n) {
+ ViolationInfo v = records.get(n);
+ v.violationNumThisLoop = n + 1;
+ v.durationMillis =
+ (int) (loopFinishTime - v.violationUptimeMillis);
+ handleViolation(v);
+ }
+ records.clear();
+ }
+ });
}
// Note: It's possible (even quite likely) that the
@@ -1603,17 +1512,21 @@ public final class StrictMode {
}
long now = SystemClock.uptimeMillis();
mLastViolationTime.put(crashFingerprint, now);
- long timeSinceLastViolationMillis = lastViolationTime == 0 ?
- Long.MAX_VALUE : (now - lastViolationTime);
+ long timeSinceLastViolationMillis =
+ lastViolationTime == 0 ? Long.MAX_VALUE : (now - lastViolationTime);
if ((info.policy & PENALTY_LOG) != 0 && sListener != null) {
sListener.onViolation(info.crashInfo.stackTrace);
}
- if ((info.policy & PENALTY_LOG) != 0 &&
- timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
+ if ((info.policy & PENALTY_LOG) != 0
+ && timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
if (info.durationMillis != -1) {
- Log.d(TAG, "StrictMode policy violation; ~duration=" +
- info.durationMillis + " ms: " + info.crashInfo.stackTrace);
+ Log.d(
+ TAG,
+ "StrictMode policy violation; ~duration="
+ + info.durationMillis
+ + " ms: "
+ + info.crashInfo.stackTrace);
} else {
Log.d(TAG, "StrictMode policy violation: " + info.crashInfo.stackTrace);
}
@@ -1625,8 +1538,8 @@ public final class StrictMode {
// by the ActivityManagerService remaining set.
int violationMaskSubset = 0;
- if ((info.policy & PENALTY_DIALOG) != 0 &&
- timeSinceLastViolationMillis > MIN_DIALOG_INTERVAL_MS) {
+ if ((info.policy & PENALTY_DIALOG) != 0
+ && timeSinceLastViolationMillis > MIN_DIALOG_INTERVAL_MS) {
violationMaskSubset |= PENALTY_DIALOG;
}
@@ -1659,10 +1572,9 @@ public final class StrictMode {
// We restore the current policy below, in the finally block.
setThreadPolicyMask(0);
- ActivityManager.getService().handleApplicationStrictModeViolation(
- RuntimeInit.getApplicationObject(),
- violationMaskSubset,
- info);
+ ActivityManager.getService()
+ .handleApplicationStrictModeViolation(
+ RuntimeInit.getApplicationObject(), violationMaskSubset, info);
} catch (RemoteException e) {
if (e instanceof DeadObjectException) {
// System process is dead; ignore
@@ -1687,12 +1599,10 @@ public final class StrictMode {
}
/**
- * In the common case, as set by conditionallyEnableDebugLogging,
- * we're just dropboxing any violations but not showing a dialog,
- * not loggging, and not killing the process. In these cases we
- * don't need to do a synchronous call to the ActivityManager.
- * This is used by both per-thread and vm-wide violations when
- * applicable.
+ * In the common case, as set by conditionallyEnableDebugLogging, we're just dropboxing any
+ * violations but not showing a dialog, not loggging, and not killing the process. In these
+ * cases we don't need to do a synchronous call to the ActivityManager. This is used by both
+ * per-thread and vm-wide violations when applicable.
*/
private static void dropboxViolationAsync(
final int violationMaskSubset, final ViolationInfo info) {
@@ -1715,9 +1625,7 @@ public final class StrictMode {
Log.d(TAG, "No activity manager; failed to Dropbox violation.");
} else {
am.handleApplicationStrictModeViolation(
- RuntimeInit.getApplicationObject(),
- violationMaskSubset,
- info);
+ RuntimeInit.getApplicationObject(), violationMaskSubset, info);
}
} catch (RemoteException e) {
if (e instanceof DeadObjectException) {
@@ -1738,25 +1646,20 @@ public final class StrictMode {
}
}
- /**
- * Called from Parcel.writeNoException()
- */
+ /** Called from Parcel.writeNoException() */
/* package */ static boolean hasGatheredViolations() {
return gatheredViolations.get() != null;
}
/**
- * Called from Parcel.writeException(), so we drop this memory and
- * don't incorrectly attribute it to the wrong caller on the next
- * Binder call on this thread.
+ * Called from Parcel.writeException(), so we drop this memory and don't incorrectly attribute
+ * it to the wrong caller on the next Binder call on this thread.
*/
/* package */ static void clearGatheredViolations() {
gatheredViolations.set(null);
}
- /**
- * @hide
- */
+ /** @hide */
public static void conditionallyCheckInstanceCounts() {
VmPolicy policy = getVmPolicy();
int policySize = policy.classInstanceLimit.size();
@@ -1784,7 +1687,7 @@ public final class StrictMode {
}
private static long sLastInstanceCountCheckMillis = 0;
- private static boolean sIsIdlerRegistered = false; // guarded by StrictMode.class
+ private static boolean sIsIdlerRegistered = false; // guarded by StrictMode.class
private static final MessageQueue.IdleHandler sProcessIdleHandler =
new MessageQueue.IdleHandler() {
public boolean queueIdle() {
@@ -1798,9 +1701,8 @@ public final class StrictMode {
};
/**
- * Sets the policy for what actions in the VM process (on any
- * thread) should be detected, as well as the penalty if such
- * actions occur.
+ * Sets the policy for what actions in the VM process (on any thread) should be detected, as
+ * well as the penalty if such actions occur.
*
* @param policy the policy to put into place
*/
@@ -1813,8 +1715,8 @@ public final class StrictMode {
Looper looper = Looper.getMainLooper();
if (looper != null) {
MessageQueue mq = looper.mQueue;
- if (policy.classInstanceLimit.size() == 0 ||
- (sVmPolicyMask & VM_PENALTY_MASK) == 0) {
+ if (policy.classInstanceLimit.size() == 0
+ || (sVmPolicyMask & VM_PENALTY_MASK) == 0) {
mq.removeIdleHandler(sProcessIdleHandler);
sIsIdlerRegistered = false;
} else if (!sIsIdlerRegistered) {
@@ -1833,8 +1735,9 @@ public final class StrictMode {
}
}
- final INetworkManagementService netd = INetworkManagementService.Stub.asInterface(
- ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
+ final INetworkManagementService netd =
+ INetworkManagementService.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
if (netd != null) {
try {
netd.setUidCleartextNetworkPolicy(android.os.Process.myUid(), networkPolicy);
@@ -1846,9 +1749,7 @@ public final class StrictMode {
}
}
- /**
- * Gets the current VM policy.
- */
+ /** Gets the current VM policy. */
public static VmPolicy getVmPolicy() {
synchronized (StrictMode.class) {
return sVmPolicy;
@@ -1858,102 +1759,72 @@ public final class StrictMode {
/**
* Enable the recommended StrictMode defaults, with violations just being logged.
*
- * <p>This catches disk and network access on the main thread, as
- * well as leaked SQLite cursors and unclosed resources. This is
- * simply a wrapper around {@link #setVmPolicy} and {@link
+ * <p>This catches disk and network access on the main thread, as well as leaked SQLite cursors
+ * and unclosed resources. This is simply a wrapper around {@link #setVmPolicy} and {@link
* #setThreadPolicy}.
*/
public static void enableDefaults() {
- StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
- .detectAll()
- .penaltyLog()
- .build());
- StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
- .detectAll()
- .penaltyLog()
- .build());
+ StrictMode.setThreadPolicy(
+ new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());
+ StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build());
}
- /**
- * @hide
- */
+ /** @hide */
public static boolean vmSqliteObjectLeaksEnabled() {
return (sVmPolicyMask & DETECT_VM_CURSOR_LEAKS) != 0;
}
- /**
- * @hide
- */
+ /** @hide */
public static boolean vmClosableObjectLeaksEnabled() {
return (sVmPolicyMask & DETECT_VM_CLOSABLE_LEAKS) != 0;
}
- /**
- * @hide
- */
+ /** @hide */
public static boolean vmRegistrationLeaksEnabled() {
return (sVmPolicyMask & DETECT_VM_REGISTRATION_LEAKS) != 0;
}
- /**
- * @hide
- */
+ /** @hide */
public static boolean vmFileUriExposureEnabled() {
return (sVmPolicyMask & DETECT_VM_FILE_URI_EXPOSURE) != 0;
}
- /**
- * @hide
- */
+ /** @hide */
public static boolean vmCleartextNetworkEnabled() {
return (sVmPolicyMask & DETECT_VM_CLEARTEXT_NETWORK) != 0;
}
- /**
- * @hide
- */
+ /** @hide */
public static boolean vmContentUriWithoutPermissionEnabled() {
return (sVmPolicyMask & DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION) != 0;
}
- /**
- * @hide
- */
+ /** @hide */
public static boolean vmUntaggedSocketEnabled() {
return (sVmPolicyMask & DETECT_VM_UNTAGGED_SOCKET) != 0;
}
- /**
- * @hide
- */
+ /** @hide */
public static void onSqliteObjectLeaked(String message, Throwable originStack) {
onVmPolicyViolation(message, originStack);
}
- /**
- * @hide
- */
+ /** @hide */
public static void onWebViewMethodCalledOnWrongThread(Throwable originStack) {
onVmPolicyViolation(null, originStack);
}
- /**
- * @hide
- */
+ /** @hide */
public static void onIntentReceiverLeaked(Throwable originStack) {
onVmPolicyViolation(null, originStack);
}
- /**
- * @hide
- */
+ /** @hide */
public static void onServiceConnectionLeaked(Throwable originStack) {
onVmPolicyViolation(null, originStack);
}
- /**
- * @hide
- */
+ /** @hide */
public static void onFileUriExposed(Uri uri, String location) {
final String message = uri + " exposed beyond app through " + location;
if ((sVmPolicyMask & PENALTY_DEATH_ON_FILE_URI_EXPOSURE) != 0) {
@@ -1963,19 +1834,18 @@ public final class StrictMode {
}
}
- /**
- * @hide
- */
+ /** @hide */
public static void onContentUriWithoutPermission(Uri uri, String location) {
- final String message = uri + " exposed beyond app through " + location
- + " without permission grant flags; did you forget"
- + " FLAG_GRANT_READ_URI_PERMISSION?";
+ final String message =
+ uri
+ + " exposed beyond app through "
+ + location
+ + " without permission grant flags; did you forget"
+ + " FLAG_GRANT_READ_URI_PERMISSION?";
onVmPolicyViolation(null, new Throwable(message));
}
- /**
- * @hide
- */
+ /** @hide */
public static void onCleartextNetworkDetected(byte[] firstPacket) {
byte[] rawAddr = null;
if (firstPacket != null) {
@@ -1994,40 +1864,40 @@ public final class StrictMode {
String msg = "Detected cleartext network traffic from UID " + uid;
if (rawAddr != null) {
try {
- msg = "Detected cleartext network traffic from UID " + uid + " to "
- + InetAddress.getByAddress(rawAddr);
+ msg =
+ "Detected cleartext network traffic from UID "
+ + uid
+ + " to "
+ + InetAddress.getByAddress(rawAddr);
} catch (UnknownHostException ignored) {
}
}
final boolean forceDeath = (sVmPolicyMask & PENALTY_DEATH_ON_CLEARTEXT_NETWORK) != 0;
- onVmPolicyViolation(HexDump.dumpHexString(firstPacket).trim(), new Throwable(msg),
- forceDeath);
+ onVmPolicyViolation(
+ HexDump.dumpHexString(firstPacket).trim(), new Throwable(msg), forceDeath);
}
- /**
- * @hide
- */
+ /** @hide */
public static void onUntaggedSocket() {
- onVmPolicyViolation(null, new Throwable("Untagged socket detected; use"
- + " TrafficStats.setThreadSocketTag() to track all network usage"));
+ onVmPolicyViolation(
+ null,
+ new Throwable(
+ "Untagged socket detected; use"
+ + " TrafficStats.setThreadSocketTag() to track all network usage"));
}
// Map from VM violation fingerprint to uptime millis.
private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<Integer, Long>();
- /**
- * @hide
- */
+ /** @hide */
public static void onVmPolicyViolation(String message, Throwable originStack) {
onVmPolicyViolation(message, originStack, false);
}
- /**
- * @hide
- */
- public static void onVmPolicyViolation(String message, Throwable originStack,
- boolean forceDeath) {
+ /** @hide */
+ public static void onVmPolicyViolation(
+ String message, Throwable originStack, boolean forceDeath) {
final boolean penaltyDropbox = (sVmPolicyMask & PENALTY_DROPBOX) != 0;
final boolean penaltyDeath = ((sVmPolicyMask & PENALTY_DEATH) != 0) || forceDeath;
final boolean penaltyLog = (sVmPolicyMask & PENALTY_LOG) != 0;
@@ -2082,10 +1952,9 @@ public final class StrictMode {
// We restore the current policy below, in the finally block.
setThreadPolicyMask(0);
- ActivityManager.getService().handleApplicationStrictModeViolation(
- RuntimeInit.getApplicationObject(),
- violationMaskSubset,
- info);
+ ActivityManager.getService()
+ .handleApplicationStrictModeViolation(
+ RuntimeInit.getApplicationObject(), violationMaskSubset, info);
} catch (RemoteException e) {
if (e instanceof DeadObjectException) {
// System process is dead; ignore
@@ -2105,9 +1974,7 @@ public final class StrictMode {
}
}
- /**
- * Called from Parcel.writeNoException()
- */
+ /** Called from Parcel.writeNoException() */
/* package */ static void writeGatheredViolationsToParcel(Parcel p) {
ArrayList<ViolationInfo> violations = gatheredViolations.get();
if (violations == null) {
@@ -2128,8 +1995,8 @@ public final class StrictMode {
private static class LogStackTrace extends Exception {}
/**
- * Called from Parcel.readException() when the exception is EX_STRICT_MODE_VIOLATIONS,
- * we here read back all the encoded violations.
+ * Called from Parcel.readException() when the exception is EX_STRICT_MODE_VIOLATIONS, we here
+ * read back all the encoded violations.
*/
/* package */ static void readAndHandleBinderCallViolations(Parcel p) {
// Our own stack trace to append
@@ -2155,22 +2022,20 @@ public final class StrictMode {
}
/**
- * Called from android_util_Binder.cpp's
- * android_os_Parcel_enforceInterface when an incoming Binder call
- * requires changing the StrictMode policy mask. The role of this
- * function is to ask Binder for its current (native) thread-local
- * policy value and synchronize it to libcore's (Java)
- * thread-local policy value.
+ * Called from android_util_Binder.cpp's android_os_Parcel_enforceInterface when an incoming
+ * Binder call requires changing the StrictMode policy mask. The role of this function is to ask
+ * Binder for its current (native) thread-local policy value and synchronize it to libcore's
+ * (Java) thread-local policy value.
*/
private static void onBinderStrictModePolicyChange(int newPolicy) {
setBlockGuardPolicy(newPolicy);
}
/**
- * A tracked, critical time span. (e.g. during an animation.)
+ * A tracked, critical time span. (e.g. during an animation.)
*
- * The object itself is a linked list node, to avoid any allocations
- * during rapid span entries and exits.
+ * <p>The object itself is a linked list node, to avoid any allocations during rapid span
+ * entries and exits.
*
* @hide
*/
@@ -2178,7 +2043,7 @@ public final class StrictMode {
private String mName;
private long mCreateMillis;
private Span mNext;
- private Span mPrev; // not used when in freeList, only active
+ private Span mPrev; // not used when in freeList, only active
private final ThreadSpanState mContainerState;
Span(ThreadSpanState threadState) {
@@ -2191,12 +2056,10 @@ public final class StrictMode {
}
/**
- * To be called when the critical span is complete (i.e. the
- * animation is done animating). This can be called on any
- * thread (even a different one from where the animation was
- * taking place), but that's only a defensive implementation
- * measure. It really makes no sense for you to call this on
- * thread other than that where you created it.
+ * To be called when the critical span is complete (i.e. the animation is done animating).
+ * This can be called on any thread (even a different one from where the animation was
+ * taking place), but that's only a defensive implementation measure. It really makes no
+ * sense for you to call this on thread other than that where you created it.
*
* @hide
*/
@@ -2240,53 +2103,52 @@ public final class StrictMode {
}
// The no-op span that's used in user builds.
- private static final Span NO_OP_SPAN = new Span() {
- public void finish() {
- // Do nothing.
- }
- };
+ private static final Span NO_OP_SPAN =
+ new Span() {
+ public void finish() {
+ // Do nothing.
+ }
+ };
/**
* Linked lists of active spans and a freelist.
*
- * Locking notes: there's one of these structures per thread and
- * all members of this structure (as well as the Span nodes under
- * it) are guarded by the ThreadSpanState object instance. While
- * in theory there'd be no locking required because it's all local
- * per-thread, the finish() method above is defensive against
- * people calling it on a different thread from where they created
- * the Span, hence the locking.
+ * <p>Locking notes: there's one of these structures per thread and all members of this
+ * structure (as well as the Span nodes under it) are guarded by the ThreadSpanState object
+ * instance. While in theory there'd be no locking required because it's all local per-thread,
+ * the finish() method above is defensive against people calling it on a different thread from
+ * where they created the Span, hence the locking.
*/
private static class ThreadSpanState {
- public Span mActiveHead; // doubly-linked list.
+ public Span mActiveHead; // doubly-linked list.
public int mActiveSize;
- public Span mFreeListHead; // singly-linked list. only changes at head.
+ public Span mFreeListHead; // singly-linked list. only changes at head.
public int mFreeListSize;
}
private static final ThreadLocal<ThreadSpanState> sThisThreadSpanState =
new ThreadLocal<ThreadSpanState>() {
- @Override protected ThreadSpanState initialValue() {
- return new ThreadSpanState();
- }
- };
+ @Override
+ protected ThreadSpanState initialValue() {
+ return new ThreadSpanState();
+ }
+ };
- private static Singleton<IWindowManager> sWindowManager = new Singleton<IWindowManager>() {
- protected IWindowManager create() {
- return IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
- }
- };
+ private static Singleton<IWindowManager> sWindowManager =
+ new Singleton<IWindowManager>() {
+ protected IWindowManager create() {
+ return IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
+ }
+ };
/**
* Enter a named critical span (e.g. an animation)
*
- * <p>The name is an arbitary label (or tag) that will be applied
- * to any strictmode violation that happens while this span is
- * active. You must call finish() on the span when done.
+ * <p>The name is an arbitary label (or tag) that will be applied to any strictmode violation
+ * that happens while this span is active. You must call finish() on the span when done.
*
- * <p>This will never return null, but on devices without debugging
- * enabled, this may return a dummy object on which the finish()
- * method is a no-op.
+ * <p>This will never return null, but on devices without debugging enabled, this may return a
+ * dummy object on which the finish() method is a no-op.
*
* <p>TODO: add CloseGuard to this, verifying callers call finish.
*
@@ -2325,13 +2187,11 @@ public final class StrictMode {
}
/**
- * For code to note that it's slow. This is a no-op unless the
- * current thread's {@link android.os.StrictMode.ThreadPolicy} has
- * {@link android.os.StrictMode.ThreadPolicy.Builder#detectCustomSlowCalls}
- * enabled.
+ * For code to note that it's slow. This is a no-op unless the current thread's {@link
+ * android.os.StrictMode.ThreadPolicy} has {@link
+ * android.os.StrictMode.ThreadPolicy.Builder#detectCustomSlowCalls} enabled.
*
- * @param name a short string for the exception stack trace that's
- * built if when this fires.
+ * @param name a short string for the exception stack trace that's built if when this fires.
*/
public static void noteSlowCall(String name) {
BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
@@ -2343,14 +2203,11 @@ public final class StrictMode {
}
/**
- * For code to note that a resource was obtained using a type other than
- * its defined type. This is a no-op unless the current thread's
- * {@link android.os.StrictMode.ThreadPolicy} has
- * {@link android.os.StrictMode.ThreadPolicy.Builder#detectResourceMismatches()}
- * enabled.
+ * For code to note that a resource was obtained using a type other than its defined type. This
+ * is a no-op unless the current thread's {@link android.os.StrictMode.ThreadPolicy} has {@link
+ * android.os.StrictMode.ThreadPolicy.Builder#detectResourceMismatches()} enabled.
*
- * @param tag an object for the exception stack trace that's
- * built if when this fires.
+ * @param tag an object for the exception stack trace that's built if when this fires.
* @hide
*/
public static void noteResourceMismatch(Object tag) {
@@ -2362,9 +2219,7 @@ public final class StrictMode {
((AndroidBlockGuardPolicy) policy).onResourceMismatch(tag);
}
- /**
- * @hide
- */
+ /** @hide */
public static void noteUnbufferedIO() {
BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
if (!(policy instanceof AndroidBlockGuardPolicy)) {
@@ -2374,9 +2229,7 @@ public final class StrictMode {
((AndroidBlockGuardPolicy) policy).onUnbufferedIO();
}
- /**
- * @hide
- */
+ /** @hide */
public static void noteDiskRead() {
BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
if (!(policy instanceof AndroidBlockGuardPolicy)) {
@@ -2386,9 +2239,7 @@ public final class StrictMode {
((AndroidBlockGuardPolicy) policy).onReadFromDisk();
}
- /**
- * @hide
- */
+ /** @hide */
public static void noteDiskWrite() {
BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
if (!(policy instanceof AndroidBlockGuardPolicy)) {
@@ -2403,17 +2254,16 @@ public final class StrictMode {
new HashMap<Class, Integer>();
/**
- * Returns an object that is used to track instances of activites.
- * The activity should store a reference to the tracker object in one of its fields.
+ * Returns an object that is used to track instances of activites. The activity should store a
+ * reference to the tracker object in one of its fields.
+ *
* @hide
*/
public static Object trackActivity(Object instance) {
return new InstanceTracker(instance);
}
- /**
- * @hide
- */
+ /** @hide */
public static void incrementExpectedActivityCount(Class klass) {
if (klass == null) {
return;
@@ -2430,9 +2280,7 @@ public final class StrictMode {
}
}
- /**
- * @hide
- */
+ /** @hide */
public static void decrementExpectedActivityCount(Class klass) {
if (klass == null) {
return;
@@ -2483,70 +2331,49 @@ public final class StrictMode {
}
/**
- * Parcelable that gets sent in Binder call headers back to callers
- * to report violations that happened during a cross-process call.
+ * Parcelable that gets sent in Binder call headers back to callers to report violations that
+ * happened during a cross-process call.
*
* @hide
*/
public static class ViolationInfo implements Parcelable {
public final String message;
- /**
- * Stack and other stuff info.
- */
+ /** Stack and other stuff info. */
public final ApplicationErrorReport.CrashInfo crashInfo;
- /**
- * The strict mode policy mask at the time of violation.
- */
+ /** The strict mode policy mask at the time of violation. */
public final int policy;
- /**
- * The wall time duration of the violation, when known. -1 when
- * not known.
- */
+ /** The wall time duration of the violation, when known. -1 when not known. */
public int durationMillis = -1;
- /**
- * The number of animations currently running.
- */
+ /** The number of animations currently running. */
public int numAnimationsRunning = 0;
- /**
- * List of tags from active Span instances during this
- * violation, or null for none.
- */
+ /** List of tags from active Span instances during this violation, or null for none. */
public String[] tags;
/**
- * Which violation number this was (1-based) since the last Looper loop,
- * from the perspective of the root caller (if it crossed any processes
- * via Binder calls). The value is 0 if the root caller wasn't on a Looper
- * thread.
+ * Which violation number this was (1-based) since the last Looper loop, from the
+ * perspective of the root caller (if it crossed any processes via Binder calls). The value
+ * is 0 if the root caller wasn't on a Looper thread.
*/
public int violationNumThisLoop;
- /**
- * The time (in terms of SystemClock.uptimeMillis()) that the
- * violation occurred.
- */
+ /** The time (in terms of SystemClock.uptimeMillis()) that the violation occurred. */
public long violationUptimeMillis;
/**
- * The action of the Intent being broadcast to somebody's onReceive
- * on this thread right now, or null.
+ * The action of the Intent being broadcast to somebody's onReceive on this thread right
+ * now, or null.
*/
public String broadcastIntentAction;
- /**
- * If this is a instance count violation, the number of instances in memory,
- * else -1.
- */
+ /** If this is a instance count violation, the number of instances in memory, else -1. */
public long numInstances = -1;
- /**
- * Create an uninitialized instance of ViolationInfo
- */
+ /** Create an uninitialized instance of ViolationInfo */
public ViolationInfo() {
message = null;
crashInfo = null;
@@ -2557,9 +2384,7 @@ public final class StrictMode {
this(null, tr, policy);
}
- /**
- * Create an instance of ViolationInfo initialized from an exception.
- */
+ /** Create an instance of ViolationInfo initialized from an exception. */
public ViolationInfo(String message, Throwable tr, int policy) {
this.message = message;
crashInfo = new ApplicationErrorReport.CrashInfo(tr);
@@ -2612,9 +2437,7 @@ public final class StrictMode {
return result;
}
- /**
- * Create an instance of ViolationInfo initialized from a Parcel.
- */
+ /** Create an instance of ViolationInfo initialized from a Parcel. */
public ViolationInfo(Parcel in) {
this(in, false);
}
@@ -2622,8 +2445,8 @@ public final class StrictMode {
/**
* Create an instance of ViolationInfo initialized from a Parcel.
*
- * @param unsetGatheringBit if true, the caller is the root caller
- * and the gathering penalty should be removed.
+ * @param unsetGatheringBit if true, the caller is the root caller and the gathering penalty
+ * should be removed.
*/
public ViolationInfo(Parcel in, boolean unsetGatheringBit) {
message = in.readString();
@@ -2647,9 +2470,7 @@ public final class StrictMode {
tags = in.readStringArray();
}
- /**
- * Save a ViolationInfo instance to a parcel.
- */
+ /** Save a ViolationInfo instance to a parcel. */
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(message);
@@ -2668,23 +2489,29 @@ public final class StrictMode {
dest.writeLong(numInstances);
dest.writeString(broadcastIntentAction);
dest.writeStringArray(tags);
- int total = dest.dataPosition()-start;
- if (Binder.CHECK_PARCEL_SIZE && total > 10*1024) {
- Slog.d(TAG, "VIO: policy=" + policy + " dur=" + durationMillis
- + " numLoop=" + violationNumThisLoop
- + " anim=" + numAnimationsRunning
- + " uptime=" + violationUptimeMillis
- + " numInst=" + numInstances);
+ int total = dest.dataPosition() - start;
+ if (Binder.CHECK_PARCEL_SIZE && total > 10 * 1024) {
+ Slog.d(
+ TAG,
+ "VIO: policy="
+ + policy
+ + " dur="
+ + durationMillis
+ + " numLoop="
+ + violationNumThisLoop
+ + " anim="
+ + numAnimationsRunning
+ + " uptime="
+ + violationUptimeMillis
+ + " numInst="
+ + numInstances);
Slog.d(TAG, "VIO: action=" + broadcastIntentAction);
Slog.d(TAG, "VIO: tags=" + Arrays.toString(tags));
- Slog.d(TAG, "VIO: TOTAL BYTES WRITTEN: " + (dest.dataPosition()-start));
+ Slog.d(TAG, "VIO: TOTAL BYTES WRITTEN: " + (dest.dataPosition() - start));
}
}
-
- /**
- * Dump a ViolationInfo instance to a Printer.
- */
+ /** Dump a ViolationInfo instance to a Printer. */
public void dump(Printer pw, String prefix) {
if (crashInfo != null) {
crashInfo.dump(pw, prefix);
@@ -2743,8 +2570,8 @@ public final class StrictMode {
final int mLimit;
private static final StackTraceElement[] FAKE_STACK = {
- new StackTraceElement("android.os.StrictMode", "setClassInstanceLimit",
- "StrictMode.java", 1)
+ new StackTraceElement(
+ "android.os.StrictMode", "setClassInstanceLimit", "StrictMode.java", 1)
};
public InstanceCountViolation(Class klass, long instances, int limit) {
diff --git a/core/java/android/os/SystemProperties.java b/core/java/android/os/SystemProperties.java
index 8632194f2b02..560b4b31cdc6 100644
--- a/core/java/android/os/SystemProperties.java
+++ b/core/java/android/os/SystemProperties.java
@@ -16,6 +16,8 @@
package android.os;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.util.Log;
import android.util.MutableInt;
@@ -43,17 +45,12 @@ public class SystemProperties {
public static final int PROP_VALUE_MAX = 91;
+ @GuardedBy("sChangeCallbacks")
private static final ArrayList<Runnable> sChangeCallbacks = new ArrayList<Runnable>();
@GuardedBy("sRoReads")
- private static final HashMap<String, MutableInt> sRoReads;
- static {
- if (TRACK_KEY_ACCESS) {
- sRoReads = new HashMap<>();
- } else {
- sRoReads = null;
- }
- }
+ private static final HashMap<String, MutableInt> sRoReads =
+ TRACK_KEY_ACCESS ? new HashMap<>() : null;
private static void onKeyAccess(String key) {
if (!TRACK_KEY_ACCESS) return;
@@ -85,77 +82,102 @@ public class SystemProperties {
private static native void native_report_sysprop_change();
/**
- * Get the value for the given key.
- * @return an empty string if the key isn't found
+ * Get the String value for the given {@code key}.
+ *
+ * <b>WARNING:</b> Do not use this method if the value may not be a valid UTF string! This
+ * method will crash in native code.
+ *
+ * @param key the key to lookup
+ * @return an empty string if the {@code key} isn't found
*/
- public static String get(String key) {
+ @NonNull
+ public static String get(@NonNull String key) {
if (TRACK_KEY_ACCESS) onKeyAccess(key);
return native_get(key);
}
/**
- * Get the value for the given key.
- * @return if the key isn't found, return def if it isn't null, or an empty string otherwise
+ * Get the String value for the given {@code key}.
+ *
+ * <b>WARNING:</b> Do not use this method if the value may not be a valid UTF string! This
+ * method will crash in native code.
+ *
+ * @param key the key to lookup
+ * @param def the default value in case the property is not set or empty
+ * @return if the {@code key} isn't found, return {@code def} if it isn't null, or an empty
+ * string otherwise
*/
- public static String get(String key, String def) {
+ @NonNull
+ public static String get(@NonNull String key, @Nullable String def) {
if (TRACK_KEY_ACCESS) onKeyAccess(key);
return native_get(key, def);
}
/**
- * Get the value for the given key, and return as an integer.
+ * Get the value for the given {@code key}, and return as an integer.
+ *
* @param key the key to lookup
* @param def a default value to return
* @return the key parsed as an integer, or def if the key isn't found or
* cannot be parsed
*/
- public static int getInt(String key, int def) {
+ public static int getInt(@NonNull String key, int def) {
if (TRACK_KEY_ACCESS) onKeyAccess(key);
return native_get_int(key, def);
}
/**
- * Get the value for the given key, and return as a long.
+ * Get the value for the given {@code key}, and return as a long.
+ *
* @param key the key to lookup
* @param def a default value to return
* @return the key parsed as a long, or def if the key isn't found or
* cannot be parsed
*/
- public static long getLong(String key, long def) {
+ public static long getLong(@NonNull String key, long def) {
if (TRACK_KEY_ACCESS) onKeyAccess(key);
return native_get_long(key, def);
}
/**
- * Get the value for the given key, returned as a boolean.
+ * Get the value for the given {@code key}, returned as a boolean.
* Values 'n', 'no', '0', 'false' or 'off' are considered false.
* Values 'y', 'yes', '1', 'true' or 'on' are considered true.
* (case sensitive).
* If the key does not exist, or has any other value, then the default
* result is returned.
+ *
* @param key the key to lookup
* @param def a default value to return
* @return the key parsed as a boolean, or def if the key isn't found or is
* not able to be parsed as a boolean.
*/
- public static boolean getBoolean(String key, boolean def) {
+ public static boolean getBoolean(@NonNull String key, boolean def) {
if (TRACK_KEY_ACCESS) onKeyAccess(key);
return native_get_boolean(key, def);
}
/**
- * Set the value for the given key.
- * @throws IllegalArgumentException if the value exceeds 92 characters
+ * Set the value for the given {@code key} to {@code val}.
+ *
+ * @throws IllegalArgumentException if the {@code val} exceeds 91 characters
*/
- public static void set(String key, String val) {
+ public static void set(@NonNull String key, @Nullable String val) {
if (val != null && val.length() > PROP_VALUE_MAX) {
- throw newValueTooLargeException(key, val);
+ throw new IllegalArgumentException("value of system property '" + key
+ + "' is longer than " + PROP_VALUE_MAX + " characters: " + val);
}
if (TRACK_KEY_ACCESS) onKeyAccess(key);
native_set(key, val);
}
- public static void addChangeCallback(Runnable callback) {
+ /**
+ * Add a callback that will be run whenever any system property changes.
+ *
+ * @param callback The {@link Runnable} that should be executed when a system property
+ * changes.
+ */
+ public static void addChangeCallback(@NonNull Runnable callback) {
synchronized (sChangeCallbacks) {
if (sChangeCallbacks.size() == 0) {
native_add_change_callback();
@@ -164,7 +186,8 @@ public class SystemProperties {
}
}
- static void callChangeCallbacks() {
+ @SuppressWarnings("unused") // Called from native code.
+ private static void callChangeCallbacks() {
synchronized (sChangeCallbacks) {
//Log.i("foo", "Calling " + sChangeCallbacks.size() + " change callbacks!");
if (sChangeCallbacks.size() == 0) {
@@ -177,11 +200,6 @@ public class SystemProperties {
}
}
- private static IllegalArgumentException newValueTooLargeException(String key, String value) {
- return new IllegalArgumentException("value of system property '" + key + "' is longer than "
- + PROP_VALUE_MAX + " characters: " + value);
- }
-
/*
* Notifies listeners that a system property has changed
*/
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index fe9e8c67e566..da0ed54e003e 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -149,14 +149,43 @@ public abstract class VibrationEffect implements Parcelable {
* provide a better experience than you could otherwise build using the generic building
* blocks.
*
+ * This will fallback to a generic pattern if one exists and there does not exist a
+ * hardware-specific implementation of the effect.
+ *
* @param effectId The ID of the effect to perform:
- * {@link #EFFECT_CLICK}, {@link #EFFECT_DOUBLE_CLICK}.
+ * {@link #EFFECT_CLICK}, {@link #EFFECT_DOUBLE_CLICK}, {@link #EFFECT_TICK}
*
* @return The desired effect.
* @hide
*/
public static VibrationEffect get(int effectId) {
- VibrationEffect effect = new Prebaked(effectId);
+ return get(effectId, true);
+ }
+
+ /**
+ * Get a predefined vibration effect.
+ *
+ * Predefined effects are a set of common vibration effects that should be identical, regardless
+ * of the app they come from, in order to provide a cohesive experience for users across
+ * the entire device. They also may be custom tailored to the device hardware in order to
+ * provide a better experience than you could otherwise build using the generic building
+ * blocks.
+ *
+ * Some effects you may only want to play if there's a hardware specific implementation because
+ * they may, for example, be too disruptive to the user without tuning. The {@code fallback}
+ * parameter allows you to decide whether you want to fallback to the generic implementation or
+ * only play if there's a tuned, hardware specific one available.
+ *
+ * @param effectId The ID of the effect to perform:
+ * {@link #EFFECT_CLICK}, {@link #EFFECT_DOUBLE_CLICK}, {@link #EFFECT_TICK}
+ * @param fallback Whether to fallback to a generic pattern if a hardware specific
+ * implementation doesn't exist.
+ *
+ * @return The desired effect.
+ * @hide
+ */
+ public static VibrationEffect get(int effectId, boolean fallback) {
+ VibrationEffect effect = new Prebaked(effectId, fallback);
effect.validate();
return effect;
}
@@ -374,19 +403,29 @@ public abstract class VibrationEffect implements Parcelable {
/** @hide */
public static class Prebaked extends VibrationEffect implements Parcelable {
private int mEffectId;
+ private boolean mFallback;
public Prebaked(Parcel in) {
- this(in.readInt());
+ this(in.readInt(), in.readByte() != 0);
}
- public Prebaked(int effectId) {
+ public Prebaked(int effectId, boolean fallback) {
mEffectId = effectId;
+ mFallback = fallback;
}
public int getId() {
return mEffectId;
}
+ /**
+ * Whether the effect should fall back to a generic pattern if there's no hardware specific
+ * implementation of it.
+ */
+ public boolean shouldFallback() {
+ return mFallback;
+ }
+
@Override
public void validate() {
switch (mEffectId) {
@@ -406,7 +445,7 @@ public abstract class VibrationEffect implements Parcelable {
return false;
}
VibrationEffect.Prebaked other = (VibrationEffect.Prebaked) o;
- return mEffectId == other.mEffectId;
+ return mEffectId == other.mEffectId && mFallback == other.mFallback;
}
@Override
@@ -416,7 +455,7 @@ public abstract class VibrationEffect implements Parcelable {
@Override
public String toString() {
- return "Prebaked{mEffectId=" + mEffectId + "}";
+ return "Prebaked{mEffectId=" + mEffectId + ", mFallback=" + mFallback + "}";
}
@@ -424,6 +463,7 @@ public abstract class VibrationEffect implements Parcelable {
public void writeToParcel(Parcel out, int flags) {
out.writeInt(PARCEL_TOKEN_EFFECT);
out.writeInt(mEffectId);
+ out.writeByte((byte) (mFallback ? 1 : 0));
}
public static final Parcelable.Creator<Prebaked> CREATOR =
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1741755c2750..c44b0bcf9acc 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -31,6 +31,7 @@ import android.app.ActivityThread;
import android.app.AppOpsManager;
import android.app.Application;
import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
import android.app.SearchManager;
import android.app.WallpaperManager;
@@ -1311,6 +1312,18 @@ public final class Settings {
= "android.settings.CHANNEL_NOTIFICATION_SETTINGS";
/**
+ * Activity Action: Show notification settings for a single {@link NotificationChannelGroup}.
+ * <p>
+ * Input: {@link #EXTRA_APP_PACKAGE}, the package containing the channel group to display.
+ * Input: {@link #EXTRA_CHANNEL_GROUP_ID}, the id of the channel group to display.
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_CHANNEL_GROUP_NOTIFICATION_SETTINGS =
+ "android.settings.CHANNEL_GROUP_NOTIFICATION_SETTINGS";
+
+ /**
* Activity Extra: The package owner of the notification channel settings to display.
* <p>
* This must be passed as an extra field to the {@link #ACTION_CHANNEL_NOTIFICATION_SETTINGS}.
@@ -1326,6 +1339,15 @@ public final class Settings {
public static final String EXTRA_CHANNEL_ID = "android.provider.extra.CHANNEL_ID";
/**
+ * Activity Extra: The {@link NotificationChannelGroup#getId()} of the notification channel
+ * group settings to display.
+ * <p>
+ * This must be passed as an extra field to the
+ * {@link #ACTION_CHANNEL_GROUP_NOTIFICATION_SETTINGS}.
+ */
+ public static final String EXTRA_CHANNEL_GROUP_ID = "android.provider.extra.CHANNEL_GROUP_ID";
+
+ /**
* Activity Action: Show notification redaction settings.
*
* @hide
@@ -8015,6 +8037,8 @@ public final class Settings {
public static final String NETSTATS_GLOBAL_ALERT_BYTES = "netstats_global_alert_bytes";
/** {@hide} */
public static final String NETSTATS_SAMPLE_ENABLED = "netstats_sample_enabled";
+ /** {@hide} */
+ public static final String NETSTATS_AUGMENT_ENABLED = "netstats_augment_enabled";
/** {@hide} */
public static final String NETSTATS_DEV_BUCKET_DURATION = "netstats_dev_bucket_duration";
@@ -9332,6 +9356,25 @@ public final class Settings {
public static final String ANOMALY_DETECTION_CONSTANTS = "anomaly_detection_constants";
/**
+ * Always on display(AOD) specific settings
+ * This is encoded as a key=value list, separated by commas. Ex:
+ *
+ * "prox_screen_off_delay=10000,screen_brightness_array=0:1:2:3:4"
+ *
+ * The following keys are supported:
+ *
+ * <pre>
+ * screen_brightness_array (string)
+ * dimming_scrim_array (string)
+ * prox_screen_off_delay (long)
+ * prox_cooldown_trigger (long)
+ * prox_cooldown_period (long)
+ * </pre>
+ * @hide
+ */
+ public static final String ALWAYS_ON_DISPLAY_CONSTANTS = "always_on_display_constants";
+
+ /**
* App standby (app idle) specific settings.
* This is encoded as a key=value list, separated by commas. Ex:
*
diff --git a/core/java/android/service/autofill/AutofillServiceInfo.java b/core/java/android/service/autofill/AutofillServiceInfo.java
index e64eb0d62992..f14740066c95 100644
--- a/core/java/android/service/autofill/AutofillServiceInfo.java
+++ b/core/java/android/service/autofill/AutofillServiceInfo.java
@@ -29,11 +29,12 @@ import android.os.RemoteException;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
import com.android.internal.R;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.IOException;
/**
@@ -89,9 +90,7 @@ public final class AutofillServiceInfo {
@Nullable
private static TypedArray getMetaDataArray(PackageManager pm, ServiceInfo si) {
// Check for permissions.
- // TODO(b/37563972): remove support to BIND_AUTOFILL once clients use BIND_AUTOFILL_SERVICE
- if (!Manifest.permission.BIND_AUTOFILL_SERVICE.equals(si.permission)
- && !Manifest.permission.BIND_AUTOFILL.equals(si.permission)) {
+ if (!Manifest.permission.BIND_AUTOFILL_SERVICE.equals(si.permission)) {
Log.w(TAG, "AutofillService from '" + si.packageName + "' does not require permission "
+ Manifest.permission.BIND_AUTOFILL_SERVICE);
throw new SecurityException("Service does not require permission "
diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java
index f7dc1c58ade1..60c1c9a7e87a 100644
--- a/core/java/android/service/autofill/FillEventHistory.java
+++ b/core/java/android/service/autofill/FillEventHistory.java
@@ -81,10 +81,13 @@ public final class FillEventHistory implements Parcelable {
/**
* Returns the client state set in the previous {@link FillResponse}.
*
- * <p><b>NOTE: </b>the state is associated with the app that was autofilled in the previous
+ * <p><b>Note: </b>the state is associated with the app that was autofilled in the previous
* {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
* , which is not necessary the same app being autofilled now.
+ *
+ * @deprecated use {@link #getEvents()} then {@link Event#getClientState()} instead.
*/
+ @Deprecated
@Nullable public Bundle getClientState() {
return mClientState;
}
@@ -126,7 +129,6 @@ public final class FillEventHistory implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeBundle(mClientState);
-
if (mEvents == null) {
dest.writeInt(0);
} else {
@@ -137,6 +139,7 @@ public final class FillEventHistory implements Parcelable {
Event event = mEvents.get(i);
dest.writeInt(event.getType());
dest.writeString(event.getDatasetId());
+ dest.writeBundle(event.getClientState());
}
}
}
@@ -177,6 +180,7 @@ public final class FillEventHistory implements Parcelable {
@EventIds private final int mEventType;
@Nullable private final String mDatasetId;
+ @Nullable private final Bundle mClientState;
/**
* Returns the type of the event.
@@ -197,18 +201,32 @@ public final class FillEventHistory implements Parcelable {
}
/**
+ * Returns the client state from the {@link FillResponse} used to generate this event.
+ *
+ * <p><b>Note: </b>the state is associated with the app that was autofilled in the previous
+ * {@link
+ * AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)},
+ * which is not necessary the same app being autofilled now.
+ */
+ @Nullable public Bundle getClientState() {
+ return mClientState;
+ }
+
+ /**
* Creates a new event.
*
* @param eventType The type of the event
* @param datasetId The dataset the event was on, or {@code null} if the event was on the
* whole response.
+ * @param clientState The client state associated with the event.
*
* @hide
*/
- public Event(int eventType, String datasetId) {
+ public Event(int eventType, @Nullable String datasetId, @Nullable Bundle clientState) {
mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_SAVE_SHOWN,
"eventType");
mDatasetId = datasetId;
+ mClientState = clientState;
}
}
@@ -220,7 +238,8 @@ public final class FillEventHistory implements Parcelable {
int numEvents = parcel.readInt();
for (int i = 0; i < numEvents; i++) {
- selection.addEvent(new Event(parcel.readInt(), parcel.readString()));
+ selection.addEvent(new Event(parcel.readInt(), parcel.readString(),
+ parcel.readBundle()));
}
return selection;
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index b6a9a2648470..3b09c678ba8e 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -302,7 +302,7 @@ public final class FillResponse implements Parcelable {
// TODO: create a dump() method instead
return new StringBuilder(
"FillResponse : [mRequestId=" + mRequestId)
- .append(", datasets=").append(mDatasets)
+ .append(", datasets=").append(mDatasets == null ? "N/A" : mDatasets.getList())
.append(", saveInfo=").append(mSaveInfo)
.append(", clientState=").append(mClientState != null)
.append(", hasPresentation=").append(mPresentation != null)
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 888bb00b6b58..c124c7fd6a0c 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -780,9 +780,7 @@ public class StaticLayout extends Layout {
firstWidth, firstWidthLineCount, restWidth,
variableTabStops, TAB_INCREMENT, b.mBreakStrategy, b.mHyphenationFrequency,
// TODO: Support more justification mode, e.g. letter spacing, stretching.
- b.mJustificationMode != Layout.JUSTIFICATION_MODE_NONE,
- (indents != null && indents.length > mLineCount) ? indents : null,
- mLineCount);
+ b.mJustificationMode != Layout.JUSTIFICATION_MODE_NONE, indents, mLineCount);
// measurement has to be done before performing line breaking
// but we don't want to recompute fontmetrics or span ranges the
@@ -1506,7 +1504,7 @@ public class StaticLayout extends Layout {
@FloatRange(from = 0.0f) float restWidth, @Nullable int[] variableTabStops,
int defaultTabStop, @BreakStrategy int breakStrategy,
@HyphenationFrequency int hyphenationFrequency, boolean isJustified,
- @Nullable int[] indents, @IntRange(from = 0) int intentsOffset);
+ @Nullable int[] indents, @IntRange(from = 0) int indentsOffset);
private static native float nAddStyleRun(long nativePtr, long nativePaint, int start, int end,
boolean isRtl);
diff --git a/core/java/android/util/ExceptionUtils.java b/core/java/android/util/ExceptionUtils.java
index 44019c32560d..da7387fcae70 100644
--- a/core/java/android/util/ExceptionUtils.java
+++ b/core/java/android/util/ExceptionUtils.java
@@ -78,4 +78,12 @@ public class ExceptionUtils {
propagateIfInstanceOf(t, RuntimeException.class);
throw new RuntimeException(t);
}
+
+ /**
+ * Gets the root {@link Throwable#getCause() cause} of {@code t}
+ */
+ public static @NonNull Throwable getRootCause(@NonNull Throwable t) {
+ while (t.getCause() != null) t = t.getCause();
+ return t;
+ }
}
diff --git a/core/java/android/util/IconDrawableFactory.java b/core/java/android/util/IconDrawableFactory.java
index b07942ff7f9d..6a6c2ce4838e 100644
--- a/core/java/android/util/IconDrawableFactory.java
+++ b/core/java/android/util/IconDrawableFactory.java
@@ -21,7 +21,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
-import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.os.UserManager;
@@ -68,8 +67,7 @@ public class IconDrawableFactory {
return icon;
}
- // Before badging, add shadow to adaptive icon if needed.
- icon = mLauncherIcons.wrapIconDrawableWithShadow(icon);
+ icon = getShadowedIcon(icon);
if (appInfo.isInstantApp()) {
int badgeColor = Resources.getSystem().getColor(
com.android.internal.R.color.instant_app_badge, null);
@@ -85,6 +83,13 @@ public class IconDrawableFactory {
return icon;
}
+ /**
+ * Add shadow to the icon if {@link AdaptiveIconDrawable}
+ */
+ public Drawable getShadowedIcon(Drawable icon) {
+ return mLauncherIcons.wrapIconDrawableWithShadow(icon);
+ }
+
// Should have enough colors to cope with UserManagerService.getMaxManagedProfiles()
@VisibleForTesting
public static final int[] CORP_BADGE_COLORS = new int[] {
diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java
new file mode 100644
index 000000000000..0be1a8cfabae
--- /dev/null
+++ b/core/java/android/util/StatsLog.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.util;
+
+/**
+ * Logging access for platform metrics.
+ *
+ * <p>This is <b>not</b> the main "logcat" debugging log ({@link android.util.Log})!
+ * These diagnostic stats are for system integrators, not application authors.
+ *
+ * <p>Stats use integer tag codes.
+ * They carry a payload of one or more int, long, or String values.
+ * @hide
+ */
+public class StatsLog {
+ /** @hide */ public StatsLog() {}
+
+ private static final String TAG = "StatsLog";
+
+ // We assume that the native methods deal with any concurrency issues.
+
+ /**
+ * Records an stats log message.
+ * @param tag The stats type tag code
+ * @param value A value to log
+ * @return The number of bytes written
+ */
+ public static native int writeInt(int tag, int value);
+
+ /**
+ * Records an stats log message.
+ * @param tag The stats type tag code
+ * @param value A value to log
+ * @return The number of bytes written
+ */
+ public static native int writeLong(int tag, long value);
+
+ /**
+ * Records an stats log message.
+ * @param tag The stats type tag code
+ * @param value A value to log
+ * @return The number of bytes written
+ */
+ public static native int writeFloat(int tag, float value);
+
+ /**
+ * Records an stats log message.
+ * @param tag The stats type tag code
+ * @param str A value to log
+ * @return The number of bytes written
+ */
+ public static native int writeString(int tag, String str);
+
+ /**
+ * Records an stats log message.
+ * @param tag The stats type tag code
+ * @param list A list of values to log. All values should
+ * be of type int, long, float or String.
+ * @return The number of bytes written
+ */
+ public static native int writeArray(int tag, Object... list);
+}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 551a1556d859..e5bd5ac076f3 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3354,6 +3354,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not
* {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION
* FLAG_TRANSLUCENT_NAVIGATION}.
+ *
+ * @see android.R.attr#windowLightNavigationBar
*/
public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010;
@@ -7619,6 +7621,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* <li>Call
* {@link android.view.autofill.AutofillManager#notifyValueChanged(View, int, AutofillValue)}
* when the value of a virtual child changed.
+ * <li>Call {@link
+ * android.view.autofill.AutofillManager#notifyViewVisibilityChanged(View, int, boolean)}
+ * when the visibility of a virtual child changed.
* <li>Call {@link AutofillManager#commit()} when the autofill context of the view structure
* changed and the current context should be committed (for example, when the user tapped
* a {@code SUBMIT} button in an HTML page).
@@ -13240,6 +13245,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
&& ((privateFlags & PFLAG_FOCUSED) != 0)) {
/* Give up focus if we are no longer focusable */
clearFocus();
+ if (mParent instanceof ViewGroup) {
+ ((ViewGroup) mParent).clearFocusedInCluster();
+ }
} else if (((old & FOCUSABLE) == NOT_FOCUSABLE)
&& ((privateFlags & PFLAG_FOCUSED) == 0)) {
/*
@@ -13304,7 +13312,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
requestLayout();
if (((mViewFlags & VISIBILITY_MASK) == GONE)) {
- if (hasFocus()) clearFocus();
+ if (hasFocus()) {
+ clearFocus();
+ if (mParent instanceof ViewGroup) {
+ ((ViewGroup) mParent).clearFocusedInCluster();
+ }
+ }
clearAccessibilityFocus();
destroyDrawingCache();
if (mParent instanceof View) {
@@ -13332,7 +13345,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) {
// root view becoming invisible shouldn't clear focus and accessibility focus
if (getRootView() != this) {
- if (hasFocus()) clearFocus();
+ if (hasFocus()) {
+ clearFocus();
+ if (mParent instanceof ViewGroup) {
+ ((ViewGroup) mParent).clearFocusedInCluster();
+ }
+ }
clearAccessibilityFocus();
}
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 379ef5b18dc7..b2e5a163d872 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -818,6 +818,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
if (mFocusedInCluster != child) {
return;
}
+ clearFocusedInCluster();
+ }
+
+ /**
+ * Removes the focusedInCluster chain from this up to the cluster containing it.
+ */
+ void clearFocusedInCluster() {
View top = findKeyboardNavigationCluster();
ViewParent parent = this;
do {
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index d1e0ae5917f4..fa7b9a59c669 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -48,6 +48,7 @@ public final class TextClassification {
@NonNull private final EntityConfidence<String> mEntityConfidence;
@NonNull private final List<String> mEntities;
private int mLogType;
+ @NonNull private final String mVersionInfo;
private TextClassification(
@Nullable String text,
@@ -56,7 +57,8 @@ public final class TextClassification {
@Nullable Intent intent,
@Nullable OnClickListener onClickListener,
@NonNull EntityConfidence<String> entityConfidence,
- int logType) {
+ int logType,
+ @NonNull String versionInfo) {
mText = text;
mIcon = icon;
mLabel = label;
@@ -65,6 +67,7 @@ public final class TextClassification {
mEntityConfidence = new EntityConfidence<>(entityConfidence);
mEntities = mEntityConfidence.getEntities();
mLogType = logType;
+ mVersionInfo = versionInfo;
}
/**
@@ -145,6 +148,15 @@ public final class TextClassification {
return mLogType;
}
+ /**
+ * Returns information about the classifier model used to generate this TextClassification.
+ * @hide
+ */
+ @NonNull
+ public String getVersionInfo() {
+ return mVersionInfo;
+ }
+
@Override
public String toString() {
return String.format("TextClassification {"
@@ -179,6 +191,7 @@ public final class TextClassification {
@NonNull private final EntityConfidence<String> mEntityConfidence =
new EntityConfidence<>();
private int mLogType;
+ @NonNull private String mVersionInfo = "";
/**
* Sets the classified text.
@@ -244,11 +257,21 @@ public final class TextClassification {
}
/**
+ * Sets information about the classifier model used to generate this TextClassification.
+ * @hide
+ */
+ Builder setVersionInfo(@NonNull String versionInfo) {
+ mVersionInfo = Preconditions.checkNotNull(mVersionInfo);
+ return this;
+ }
+
+ /**
* Builds and returns a {@link TextClassification} object.
*/
public TextClassification build() {
return new TextClassification(
- mText, mIcon, mLabel, mIntent, mOnClickListener, mEntityConfidence, mLogType);
+ mText, mIcon, mLabel, mIntent, mOnClickListener, mEntityConfidence,
+ mLogType, mVersionInfo);
}
}
}
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index ab1d034bb916..bb1e693fbf43 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -34,6 +34,11 @@ import java.lang.annotation.RetentionPolicy;
*/
public interface TextClassifier {
+ /** @hide */
+ String DEFAULT_LOG_TAG = "TextClassifierImpl";
+
+ /** @hide */
+ String TYPE_UNKNOWN = ""; // TODO: Make this public API.
String TYPE_OTHER = "other";
String TYPE_EMAIL = "email";
String TYPE_PHONE = "phone";
@@ -43,7 +48,7 @@ public interface TextClassifier {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@StringDef({
- TYPE_OTHER, TYPE_EMAIL, TYPE_PHONE, TYPE_ADDRESS, TYPE_URL
+ TYPE_UNKNOWN, TYPE_OTHER, TYPE_EMAIL, TYPE_PHONE, TYPE_ADDRESS, TYPE_URL
})
@interface EntityType {}
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 290d811d01ac..7e93b78c4809 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -70,7 +70,7 @@ import java.util.regex.Pattern;
*/
final class TextClassifierImpl implements TextClassifier {
- private static final String LOG_TAG = "TextClassifierImpl";
+ private static final String LOG_TAG = DEFAULT_LOG_TAG;
private static final String MODEL_DIR = "/etc/textclassifier/";
private static final String MODEL_FILE_REGEX = "textclassifier\\.smartselection\\.(.*)\\.model";
private static final String UPDATED_MODEL_FILE_PATH =
@@ -86,6 +86,8 @@ final class TextClassifierImpl implements TextClassifier {
@GuardedBy("mSmartSelectionLock") // Do not access outside this lock.
private Locale mLocale;
@GuardedBy("mSmartSelectionLock") // Do not access outside this lock.
+ private int mVersion;
+ @GuardedBy("mSmartSelectionLock") // Do not access outside this lock.
private SmartSelection mSmartSelection;
TextClassifierImpl(Context context) {
@@ -108,8 +110,7 @@ final class TextClassifierImpl implements TextClassifier {
if (start <= end
&& start >= 0 && end <= string.length()
&& start <= selectionStartIndex && end >= selectionEndIndex) {
- final TextSelection.Builder tsBuilder = new TextSelection.Builder(start, end)
- .setLogSource(LOG_TAG);
+ final TextSelection.Builder tsBuilder = new TextSelection.Builder(start, end);
final SmartSelection.ClassificationResult[] results =
smartSelection.classifyText(
string, start, end,
@@ -118,7 +119,10 @@ final class TextClassifierImpl implements TextClassifier {
for (int i = 0; i < size; i++) {
tsBuilder.setEntityType(results[i].mCollection, results[i].mScore);
}
- return tsBuilder.build();
+ return tsBuilder
+ .setLogSource(LOG_TAG)
+ .setVersionInfo(getVersionInfo())
+ .build();
} else {
// We can not trust the result. Log the issue and ignore the result.
Log.d(LOG_TAG, "Got bad indices for input text. Ignoring result.");
@@ -202,6 +206,16 @@ final class TextClassifierImpl implements TextClassifier {
}
}
+ @NonNull
+ private String getVersionInfo() {
+ synchronized (mSmartSelectionLock) {
+ if (mLocale != null) {
+ return String.format("%s_v%d", mLocale.toLanguageTag(), mVersion);
+ }
+ return "";
+ }
+ }
+
@GuardedBy("mSmartSelectionLock") // Do not call outside this lock.
private ParcelFileDescriptor getFdLocked(Locale locale) throws FileNotFoundException {
ParcelFileDescriptor updateFd;
@@ -256,9 +270,11 @@ final class TextClassifierImpl implements TextClassifier {
final int factoryVersion = SmartSelection.getVersion(factoryFd.getFd());
if (updateVersion > factoryVersion) {
closeAndLogError(factoryFd);
+ mVersion = updateVersion;
return updateFd;
} else {
closeAndLogError(updateFd);
+ mVersion = factoryVersion;
return factoryFd;
}
}
@@ -374,7 +390,7 @@ final class TextClassifierImpl implements TextClassifier {
builder.setLabel(label != null ? label.toString() : null);
}
}
- return builder.build();
+ return builder.setVersionInfo(getVersionInfo()).build();
}
private static int getHintFlags(CharSequence text, int start, int end) {
diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
index 9a66693a93fa..085dd32966b0 100644
--- a/core/java/android/view/textclassifier/TextSelection.java
+++ b/core/java/android/view/textclassifier/TextSelection.java
@@ -35,15 +35,17 @@ public final class TextSelection {
@NonNull private final EntityConfidence<String> mEntityConfidence;
@NonNull private final List<String> mEntities;
@NonNull private final String mLogSource;
+ @NonNull private final String mVersionInfo;
private TextSelection(
int startIndex, int endIndex, @NonNull EntityConfidence<String> entityConfidence,
- @NonNull String logSource) {
+ @NonNull String logSource, @NonNull String versionInfo) {
mStartIndex = startIndex;
mEndIndex = endIndex;
mEntityConfidence = new EntityConfidence<>(entityConfidence);
mEntities = mEntityConfidence.getEntities();
mLogSource = logSource;
+ mVersionInfo = versionInfo;
}
/**
@@ -94,10 +96,20 @@ public final class TextSelection {
* Returns a tag for the source classifier used to generate this result.
* @hide
*/
+ @NonNull
public String getSourceClassifier() {
return mLogSource;
}
+ /**
+ * Returns information about the classifier model used to generate this TextSelection.
+ * @hide
+ */
+ @NonNull
+ public String getVersionInfo() {
+ return mVersionInfo;
+ }
+
@Override
public String toString() {
return String.format("TextSelection {%d, %d, %s}",
@@ -114,6 +126,7 @@ public final class TextSelection {
@NonNull private final EntityConfidence<String> mEntityConfidence =
new EntityConfidence<>();
@NonNull private String mLogSource = "";
+ @NonNull private String mVersionInfo = "";
/**
* Creates a builder used to build {@link TextSelection} objects.
@@ -152,10 +165,20 @@ public final class TextSelection {
}
/**
+ * Sets information about the classifier model used to generate this TextSelection.
+ * @hide
+ */
+ Builder setVersionInfo(@NonNull String versionInfo) {
+ mVersionInfo = Preconditions.checkNotNull(mVersionInfo);
+ return this;
+ }
+
+ /**
* Builds and returns {@link TextSelection} object.
*/
public TextSelection build() {
- return new TextSelection(mStartIndex, mEndIndex, mEntityConfidence, mLogSource);
+ return new TextSelection(
+ mStartIndex, mEndIndex, mEntityConfidence, mLogSource, mVersionInfo);
}
}
}
diff --git a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
new file mode 100644
index 000000000000..45baf912ebb2
--- /dev/null
+++ b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
@@ -0,0 +1,560 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.textclassifier.logging;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.metrics.LogMaker;
+import android.util.Log;
+import android.view.textclassifier.TextClassification;
+import android.view.textclassifier.TextClassifier;
+import android.view.textclassifier.TextSelection;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+import java.util.UUID;
+
+/**
+ * A selection event tracker.
+ * @hide
+ */
+//TODO: Do not allow any crashes from this class.
+public final class SmartSelectionEventTracker {
+
+ private static final String LOG_TAG = "SmartSelectionEventTracker";
+ private static final boolean DEBUG_LOG_ENABLED = true;
+
+ private static final int START_EVENT_DELTA = MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS;
+ private static final int PREV_EVENT_DELTA = MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS;
+ private static final int ENTITY_TYPE = MetricsEvent.NOTIFICATION_TAG;
+ private static final int INDEX = MetricsEvent.NOTIFICATION_SHADE_INDEX;
+ private static final int TAG = MetricsEvent.FIELD_CLASS_NAME;
+ private static final int SMART_INDICES = MetricsEvent.FIELD_GESTURE_LENGTH;
+ private static final int EVENT_INDICES = MetricsEvent.FIELD_CONTEXT;
+ private static final int SESSION_ID = MetricsEvent.FIELD_INSTANT_APP_LAUNCH_TOKEN;
+
+ private static final String ZERO = "0";
+ private static final String TEXTVIEW = "textview";
+ private static final String EDITTEXT = "edittext";
+ private static final String WEBVIEW = "webview";
+ private static final String EDIT_WEBVIEW = "edit-webview";
+ private static final String UNKNOWN = "unknown";
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({WidgetType.UNSPECIFIED, WidgetType.TEXTVIEW, WidgetType.WEBVIEW,
+ WidgetType.EDITTEXT, WidgetType.EDIT_WEBVIEW})
+ public @interface WidgetType {
+ int UNSPECIFIED = 0;
+ int TEXTVIEW = 1;
+ int WEBVIEW = 2;
+ int EDITTEXT = 3;
+ int EDIT_WEBVIEW = 4;
+ }
+
+ private final MetricsLogger mMetricsLogger = new MetricsLogger();
+ private final int mWidgetType;
+ private final Context mContext;
+
+ @Nullable private String mSessionId;
+ private final int[] mSmartIndices = new int[2];
+ private final int[] mPrevIndices = new int[2];
+ private int mOrigStart;
+ private int mIndex;
+ private long mSessionStartTime;
+ private long mLastEventTime;
+ private boolean mSmartSelectionTriggered;
+
+ public SmartSelectionEventTracker(@NonNull Context context, @WidgetType int widgetType) {
+ mWidgetType = widgetType;
+ mContext = Preconditions.checkNotNull(context);
+ }
+
+ /**
+ * Logs a selection event.
+ *
+ * @param event the selection event
+ */
+ public void logEvent(@NonNull SelectionEvent event) {
+ Preconditions.checkNotNull(event);
+
+ if (event.mEventType != SelectionEvent.EventType.SELECTION_STARTED && mSessionId == null) {
+ Log.d(LOG_TAG, "Selection session not yet started. Ignoring event");
+ return;
+ }
+
+ final long now = System.currentTimeMillis();
+ switch (event.mEventType) {
+ case SelectionEvent.EventType.SELECTION_STARTED:
+ mSessionId = startNewSession();
+ Preconditions.checkArgument(event.mEnd == event.mStart + 1);
+ mOrigStart = event.mStart;
+ mSessionStartTime = now;
+ break;
+ case SelectionEvent.EventType.SMART_SELECTION_SINGLE: // fall through
+ case SelectionEvent.EventType.SMART_SELECTION_MULTI:
+ mSmartSelectionTriggered = true;
+ mSmartIndices[0] = event.mStart;
+ mSmartIndices[1] = event.mEnd;
+ break;
+ case SelectionEvent.EventType.SELECTION_MODIFIED: // fall through
+ case SelectionEvent.EventType.AUTO_SELECTION:
+ if (mPrevIndices[0] == event.mStart && mPrevIndices[1] == event.mEnd) {
+ // Selection did not change. Ignore event.
+ return;
+ }
+ }
+ writeEvent(event, now);
+
+ if (event.isTerminal()) {
+ endSession();
+ }
+ }
+
+ private void writeEvent(SelectionEvent event, long now) {
+ final LogMaker log = new LogMaker(MetricsEvent.TEXT_SELECTION_MENU_ITEM_ASSIST)
+ .setType(getLogType(event))
+ .setSubtype(event.mEventType)
+ .setPackageName(mContext.getPackageName())
+ .setTimestamp(now)
+ .addTaggedData(START_EVENT_DELTA, now - mSessionStartTime)
+ .addTaggedData(PREV_EVENT_DELTA, now - mLastEventTime)
+ .addTaggedData(ENTITY_TYPE, event.mEntityType)
+ .addTaggedData(INDEX, mIndex)
+ .addTaggedData(TAG, getTag(event))
+ .addTaggedData(SMART_INDICES, getSmartDelta())
+ .addTaggedData(EVENT_INDICES, getEventDelta(event))
+ .addTaggedData(SESSION_ID, mSessionId);
+ mMetricsLogger.write(log);
+ debugLog(log);
+ mLastEventTime = now;
+ mPrevIndices[0] = event.mStart;
+ mPrevIndices[1] = event.mEnd;
+ mIndex++;
+ }
+
+ private String startNewSession() {
+ endSession();
+ mSessionId = createSessionId();
+ return mSessionId;
+ }
+
+ private void endSession() {
+ // Reset fields.
+ mOrigStart = 0;
+ mSmartIndices[0] = mSmartIndices[1] = 0;
+ mPrevIndices[0] = mPrevIndices[1] = 0;
+ mIndex = 0;
+ mSessionStartTime = 0;
+ mLastEventTime = 0;
+ mSmartSelectionTriggered = false;
+ mSessionId = null;
+ }
+
+ private int getLogType(SelectionEvent event) {
+ switch (event.mEventType) {
+ case SelectionEvent.EventType.SELECTION_STARTED: // fall through
+ case SelectionEvent.EventType.SMART_SELECTION_SINGLE: // fall through
+ case SelectionEvent.EventType.SMART_SELECTION_MULTI: // fall through
+ case SelectionEvent.EventType.AUTO_SELECTION:
+ return MetricsEvent.TYPE_OPEN;
+ case SelectionEvent.ActionType.ABANDON:
+ return MetricsEvent.TYPE_CLOSE;
+ }
+ if (event.isActionType()) {
+ if (event.isTerminal() && mSmartSelectionTriggered) {
+ if (matchesSmartSelectionBounds(event)) {
+ // Smart selection accepted.
+ return MetricsEvent.TYPE_SUCCESS;
+ } else if (containsOriginalSelection(event)) {
+ // Smart selection rejected.
+ return MetricsEvent.TYPE_FAILURE;
+ }
+ // User changed the original selection entirely.
+ }
+ return MetricsEvent.TYPE_ACTION;
+ } else {
+ return MetricsEvent.TYPE_UPDATE;
+ }
+ }
+
+ private boolean matchesSmartSelectionBounds(SelectionEvent event) {
+ return event.mStart == mSmartIndices[0] && event.mEnd == mSmartIndices[1];
+ }
+
+ private boolean containsOriginalSelection(SelectionEvent event) {
+ return event.mStart <= mOrigStart && event.mEnd > mOrigStart;
+ }
+
+ private int getSmartDelta() {
+ if (mSmartSelectionTriggered) {
+ return (clamp(mSmartIndices[0] - mOrigStart) << 16)
+ | (clamp(mSmartIndices[1] - mOrigStart) & 0xffff);
+ }
+ // If no smart selection, return start selection indices (i.e. [0, 1])
+ return /* (0 << 16) | */ (1 & 0xffff);
+ }
+
+ private int getEventDelta(SelectionEvent event) {
+ return (clamp(event.mStart - mOrigStart) << 16)
+ | (clamp(event.mEnd - mOrigStart) & 0xffff);
+ }
+
+ private String getTag(SelectionEvent event) {
+ final String widgetType;
+ switch (mWidgetType) {
+ case WidgetType.TEXTVIEW:
+ widgetType = TEXTVIEW;
+ break;
+ case WidgetType.WEBVIEW:
+ widgetType = WEBVIEW;
+ break;
+ case WidgetType.EDITTEXT:
+ widgetType = EDITTEXT;
+ break;
+ case WidgetType.EDIT_WEBVIEW:
+ widgetType = EDIT_WEBVIEW;
+ break;
+ default:
+ widgetType = UNKNOWN;
+ }
+ final String version = Objects.toString(event.mVersionTag, SelectionEvent.NO_VERSION_TAG);
+ return String.format("%s/%s", widgetType, version);
+ }
+
+ private static String createSessionId() {
+ return UUID.randomUUID().toString();
+ }
+
+ private static int clamp(int val) {
+ return Math.max(Math.min(val, Short.MAX_VALUE), Short.MIN_VALUE);
+ }
+
+ private static void debugLog(LogMaker log) {
+ if (!DEBUG_LOG_ENABLED) return;
+
+ final int index = Integer.parseInt(Objects.toString(log.getTaggedData(INDEX), ZERO));
+
+ final String event;
+ switch (log.getSubtype()) {
+ case SelectionEvent.ActionType.OVERTYPE:
+ event = "OVERTYPE";
+ break;
+ case SelectionEvent.ActionType.COPY:
+ event = "COPY";
+ break;
+ case SelectionEvent.ActionType.PASTE:
+ event = "PASTE";
+ break;
+ case SelectionEvent.ActionType.CUT:
+ event = "CUT";
+ break;
+ case SelectionEvent.ActionType.SHARE:
+ event = "SHARE";
+ break;
+ case SelectionEvent.ActionType.SMART_SHARE:
+ event = "SMART_SHARE";
+ break;
+ case SelectionEvent.ActionType.DRAG:
+ event = "DRAG";
+ break;
+ case SelectionEvent.ActionType.ABANDON:
+ event = "ABANDON";
+ break;
+ case SelectionEvent.ActionType.OTHER:
+ event = "OTHER";
+ break;
+ case SelectionEvent.ActionType.SELECT_ALL:
+ event = "SELECT_ALL";
+ break;
+ case SelectionEvent.ActionType.RESET:
+ event = "RESET";
+ break;
+ case SelectionEvent.EventType.SELECTION_STARTED:
+ final String tag = Objects.toString(log.getTaggedData(TAG), "tag");
+ String sessionId = Objects.toString(log.getTaggedData(SESSION_ID), "");
+ sessionId = sessionId.substring(sessionId.lastIndexOf("-") + 1);
+ Log.d(LOG_TAG, String.format("New selection session: %s(%s)", tag, sessionId));
+ event = "SELECTION_STARTED";
+ break;
+ case SelectionEvent.EventType.SELECTION_MODIFIED:
+ event = "SELECTION_MODIFIED";
+ break;
+ case SelectionEvent.EventType.SMART_SELECTION_SINGLE:
+ event = "SMART_SELECTION_SINGLE";
+ break;
+ case SelectionEvent.EventType.SMART_SELECTION_MULTI:
+ event = "SMART_SELECTION_MULTI";
+ break;
+ case SelectionEvent.EventType.AUTO_SELECTION:
+ event = "AUTO_SELECTION";
+ break;
+ default:
+ event = "UNKNOWN";
+ }
+
+ final int smartIndices = Integer.parseInt(
+ Objects.toString(log.getTaggedData(SMART_INDICES), ZERO));
+ final int smartStart = (short) ((smartIndices & 0xffff0000) >> 16);
+ final int smartEnd = (short) (smartIndices & 0xffff);
+
+ final int eventIndices = Integer.parseInt(
+ Objects.toString(log.getTaggedData(EVENT_INDICES), ZERO));
+ final int eventStart = (short) ((eventIndices & 0xffff0000) >> 16);
+ final int eventEnd = (short) (eventIndices & 0xffff);
+
+ final String entity = Objects.toString(
+ log.getTaggedData(ENTITY_TYPE), TextClassifier.TYPE_UNKNOWN);
+
+ Log.d(LOG_TAG, String.format("%2d: %s, context=%d,%d - old=%d,%d [%s]",
+ index, event, eventStart, eventEnd, smartStart, smartEnd, entity));
+ }
+
+ /**
+ * A selection event.
+ * Specify index parameters as word token indices.
+ */
+ public static final class SelectionEvent {
+
+ /**
+ * Use this to specify an indeterminate positive index.
+ */
+ public static final int OUT_OF_BOUNDS = Short.MAX_VALUE;
+
+ /**
+ * Use this to specify an indeterminate negative index.
+ */
+ public static final int OUT_OF_BOUNDS_NEGATIVE = Short.MIN_VALUE;
+
+ private static final String NO_VERSION_TAG = "";
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({ActionType.OVERTYPE, ActionType.COPY, ActionType.PASTE, ActionType.CUT,
+ ActionType.SHARE, ActionType.SMART_SHARE, ActionType.DRAG, ActionType.ABANDON,
+ ActionType.OTHER, ActionType.SELECT_ALL, ActionType.RESET})
+ public @interface ActionType {
+ /** User typed over the selection. */
+ int OVERTYPE = 100;
+ /** User copied the selection. */
+ int COPY = 101;
+ /** User pasted over the selection. */
+ int PASTE = 102;
+ /** User cut the selection. */
+ int CUT = 103;
+ /** User shared the selection. */
+ int SHARE = 104;
+ /** User clicked the textAssist menu item. */
+ int SMART_SHARE = 105;
+ /** User dragged+dropped the selection. */
+ int DRAG = 106;
+ /** User abandoned the selection. */
+ int ABANDON = 107;
+ /** User performed an action on the selection. */
+ int OTHER = 108;
+
+ /* Non-terminal actions. */
+ /** User activated Select All */
+ int SELECT_ALL = 200;
+ /** User reset the smart selection. */
+ int RESET = 201;
+ }
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({ActionType.OVERTYPE, ActionType.COPY, ActionType.PASTE, ActionType.CUT,
+ ActionType.SHARE, ActionType.SMART_SHARE, ActionType.DRAG, ActionType.ABANDON,
+ ActionType.OTHER, ActionType.SELECT_ALL, ActionType.RESET,
+ EventType.SELECTION_STARTED, EventType.SELECTION_MODIFIED,
+ EventType.SMART_SELECTION_SINGLE, EventType.SMART_SELECTION_MULTI,
+ EventType.AUTO_SELECTION})
+ private @interface EventType {
+ /** User started a new selection. */
+ int SELECTION_STARTED = 1;
+ /** User modified an existing selection. */
+ int SELECTION_MODIFIED = 2;
+ /** Smart selection triggered for a single token (word). */
+ int SMART_SELECTION_SINGLE = 3;
+ /** Smart selection triggered spanning multiple tokens (words). */
+ int SMART_SELECTION_MULTI = 4;
+ /** Something else other than User or the default TextClassifier triggered a selection. */
+ int AUTO_SELECTION = 5;
+ }
+
+ private final int mStart;
+ private final int mEnd;
+ private @EventType int mEventType;
+ private final @TextClassifier.EntityType String mEntityType;
+ private final String mVersionTag;
+
+ private SelectionEvent(
+ int start, int end, int eventType,
+ @TextClassifier.EntityType String entityType, String versionTag) {
+ Preconditions.checkArgument(end >= start, "end cannot be less than start");
+ mStart = start;
+ mEnd = end;
+ mEventType = eventType;
+ mEntityType = Preconditions.checkNotNull(entityType);
+ mVersionTag = Preconditions.checkNotNull(versionTag);
+ }
+
+ /**
+ * Creates a "selection started" event.
+ *
+ * @param start the word index of the selected word
+ */
+ public static SelectionEvent selectionStarted(int start) {
+ return new SelectionEvent(
+ start, start + 1, EventType.SELECTION_STARTED,
+ TextClassifier.TYPE_UNKNOWN, NO_VERSION_TAG);
+ }
+
+ /**
+ * Creates a "selection modified" event.
+ * Use when the user modifies the selection.
+ *
+ * @param start the start word (inclusive) index of the selection
+ * @param end the end word (exclusive) index of the selection
+ */
+ public static SelectionEvent selectionModified(int start, int end) {
+ return new SelectionEvent(
+ start, end, EventType.SELECTION_MODIFIED,
+ TextClassifier.TYPE_UNKNOWN, NO_VERSION_TAG);
+ }
+
+ /**
+ * Creates a "selection modified" event.
+ * Use when the user modifies the selection and the selection's entity type is known.
+ *
+ * @param start the start word (inclusive) index of the selection
+ * @param end the end word (exclusive) index of the selection
+ * @param classification the TextClassification object returned by the TextClassifier that
+ * classified the selected text
+ */
+ public static SelectionEvent selectionModified(
+ int start, int end, @NonNull TextClassification classification) {
+ final String entityType = classification.getEntityCount() > 0
+ ? classification.getEntity(0)
+ : TextClassifier.TYPE_UNKNOWN;
+ final String versionTag = classification.getVersionInfo();
+ return new SelectionEvent(
+ start, end, EventType.SELECTION_MODIFIED, entityType, versionTag);
+ }
+
+ /**
+ * Creates a "selection modified" event.
+ * Use when a TextClassifier modifies the selection.
+ *
+ * @param start the start word (inclusive) index of the selection
+ * @param end the end word (exclusive) index of the selection
+ * @param selection the TextSelection object returned by the TextClassifier for the
+ * specified selection
+ */
+ public static SelectionEvent selectionModified(
+ int start, int end, @NonNull TextSelection selection) {
+ final boolean smartSelection = selection.getSourceClassifier()
+ .equals(TextClassifier.DEFAULT_LOG_TAG);
+ final int eventType;
+ if (smartSelection) {
+ eventType = end - start > 1
+ ? EventType.SMART_SELECTION_MULTI
+ : EventType.SMART_SELECTION_SINGLE;
+
+ } else {
+ eventType = EventType.AUTO_SELECTION;
+ }
+ final String entityType = selection.getEntityCount() > 0
+ ? selection.getEntity(0)
+ : TextClassifier.TYPE_UNKNOWN;
+ final String versionTag = selection.getVersionInfo();
+ return new SelectionEvent(start, end, eventType, entityType, versionTag);
+ }
+
+ /**
+ * Creates an event specifying an action taken on a selection.
+ * Use when the user clicks on an action to act on the selected text.
+ *
+ * @param start the start word (inclusive) index of the selection
+ * @param end the end word (exclusive) index of the selection
+ * @param actionType the action that was performed on the selection
+ */
+ public static SelectionEvent selectionAction(
+ int start, int end, @ActionType int actionType) {
+ return new SelectionEvent(
+ start, end, actionType, TextClassifier.TYPE_UNKNOWN, NO_VERSION_TAG);
+ }
+
+ /**
+ * Creates an event specifying an action taken on a selection.
+ * Use when the user clicks on an action to act on the selected text and the selection's
+ * entity type is known.
+ *
+ * @param start the start word (inclusive) index of the selection
+ * @param end the end word (exclusive) index of the selection
+ * @param actionType the action that was performed on the selection
+ * @param classification the TextClassification object returned by the TextClassifier that
+ * classified the selected text
+ */
+ public static SelectionEvent selectionAction(
+ int start, int end, @ActionType int actionType,
+ @NonNull TextClassification classification) {
+ final String entityType = classification.getEntityCount() > 0
+ ? classification.getEntity(0)
+ : TextClassifier.TYPE_UNKNOWN;
+ final String versionTag = classification.getVersionInfo();
+ return new SelectionEvent(start, end, actionType, entityType, versionTag);
+ }
+
+ private boolean isActionType() {
+ switch (mEventType) {
+ case ActionType.OVERTYPE: // fall through
+ case ActionType.COPY: // fall through
+ case ActionType.PASTE: // fall through
+ case ActionType.CUT: // fall through
+ case ActionType.SHARE: // fall through
+ case ActionType.SMART_SHARE: // fall through
+ case ActionType.DRAG: // fall through
+ case ActionType.ABANDON: // fall through
+ case ActionType.SELECT_ALL: // fall through
+ case ActionType.RESET: // fall through
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private boolean isTerminal() {
+ switch (mEventType) {
+ case ActionType.OVERTYPE: // fall through
+ case ActionType.COPY: // fall through
+ case ActionType.PASTE: // fall through
+ case ActionType.CUT: // fall through
+ case ActionType.SHARE: // fall through
+ case ActionType.SMART_SHARE: // fall through
+ case ActionType.DRAG: // fall through
+ case ActionType.ABANDON: // fall through
+ return true;
+ default:
+ return false;
+ }
+ }
+ }
+}
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 5735f29b056f..81aa2f3a05fc 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -414,7 +414,7 @@ public class WebChromeClient {
* @param webView The WebView instance that is initiating the request.
* @param filePathCallback Invoke this callback to supply the list of paths to files to upload,
* or NULL to cancel. Must only be called if the
- * <code>showFileChooser</code> implementations returns true.
+ * {@link #onShowFileChooser} implementation returns true.
* @param fileChooserParams Describes the mode of file chooser to be opened, and options to be
* used with it.
* @return true if filePathCallback will be invoked, false to use default handling.
@@ -517,7 +517,7 @@ public class WebChromeClient {
* @param capture The value of the 'capture' attribute of the input tag
* associated with this file picker.
*
- * @deprecated Use {@link #showFileChooser} instead.
+ * @deprecated Use {@link #onShowFileChooser} instead.
* @hide This method was not published in any SDK version.
*/
@SystemApi
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 81ab4078e549..f918cadde87c 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1656,14 +1656,13 @@ public class WebView extends AbsoluteLayout
* Each rule should take one of these:
* <table>
* <tr><th> Rule </th> <th> Example </th> <th> Matches Subdomain</th> </tr>
- * <tr><th> HOSTNAME </th> <th> example.com </th> <th> Yes </th> </tr>
- * <tr><th>.HOSTNAME</th> <th> .example.com </th> <th> No </th> </tr>
- * <tr><th> IPV4_LITERAL </th> <th> 192.168.1.1 </th> <th> No </th></tr>
- * <tr><th> IPV6_LITERAL_WITH_BRACKETS</th><th>[10:20:30:40:50:60:70:80]</th><th>No</th></tr>
+ * <tr><td> HOSTNAME </td> <td> example.com </td> <td> Yes </td> </tr>
+ * <tr><td> .HOSTNAME </td> <td> .example.com </td> <td> No </td> </tr>
+ * <tr><td> IPV4_LITERAL </td> <td> 192.168.1.1 </td> <td> No </td></tr>
+ * <tr><td> IPV6_LITERAL_WITH_BRACKETS </td><td>[10:20:30:40:50:60:70:80]</td><td>No</td></tr>
* </table>
* <p>
* All other rules, including wildcards, are invalid.
- * <p>
*
* @param urls the list of URLs
* @param callback will be called with true if URLs are successfully added to the whitelist.
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 5845719ee537..fc9e8e70c20a 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -624,9 +624,9 @@ public class ListView extends AbsListView {
for (int i = 0; i < count; i++) {
final View child = infos.get(i).view;
- final LayoutParams p = (LayoutParams) child.getLayoutParams();
- if (p != null) {
- p.recycledHeaderFooter = false;
+ final ViewGroup.LayoutParams params = child.getLayoutParams();
+ if (checkLayoutParams(params)) {
+ ((LayoutParams) params).recycledHeaderFooter = false;
}
}
}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 5adbdbe8ab4f..46742b8852ff 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -73,6 +73,9 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
@@ -188,17 +191,12 @@ public class RemoteViews implements Parcelable, Filter {
private static final OnClickHandler DEFAULT_ON_CLICK_HANDLER = new OnClickHandler();
- private static final Object[] sMethodsLock = new Object[0];
- private static final ArrayMap<Class<? extends View>, ArrayMap<MutablePair<String, Class<?>>, Method>> sMethods =
- new ArrayMap<Class<? extends View>, ArrayMap<MutablePair<String, Class<?>>, Method>>();
- private static final ArrayMap<Method, Method> sAsyncMethods = new ArrayMap<>();
+ private static final ArrayMap<MethodKey, MethodArgs> sMethods = new ArrayMap<>();
- private static final ThreadLocal<Object[]> sInvokeArgsTls = new ThreadLocal<Object[]>() {
- @Override
- protected Object[] initialValue() {
- return new Object[1];
- }
- };
+ /**
+ * This key is used to perform lookups in sMethods without causing allocations.
+ */
+ private static final MethodKey sLookupKey = new MethodKey();
/**
* @hide
@@ -255,37 +253,47 @@ public class RemoteViews implements Parcelable, Filter {
}
/**
- * Handle with care!
+ * Stores information related to reflection method lookup.
*/
- static class MutablePair<F, S> {
- F first;
- S second;
-
- MutablePair(F first, S second) {
- this.first = first;
- this.second = second;
- }
+ static class MethodKey {
+ public Class targetClass;
+ public Class paramClass;
+ public String methodName;
@Override
public boolean equals(Object o) {
- if (!(o instanceof MutablePair)) {
+ if (!(o instanceof MethodKey)) {
return false;
}
- MutablePair<?, ?> p = (MutablePair<?, ?>) o;
- return Objects.equal(p.first, first) && Objects.equal(p.second, second);
+ MethodKey p = (MethodKey) o;
+ return Objects.equal(p.targetClass, targetClass)
+ && Objects.equal(p.paramClass, paramClass)
+ && Objects.equal(p.methodName, methodName);
}
@Override
public int hashCode() {
- return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
+ return Objects.hashCode(targetClass) ^ Objects.hashCode(paramClass)
+ ^ Objects.hashCode(methodName);
+ }
+
+ public void set(Class targetClass, Class paramClass, String methodName) {
+ this.targetClass = targetClass;
+ this.paramClass = paramClass;
+ this.methodName = methodName;
}
}
+
/**
- * This pair is used to perform lookups in sMethods without causing allocations.
+ * Stores information related to reflection method lookup result.
*/
- private final MutablePair<String, Class<?>> mPair =
- new MutablePair<String, Class<?>>(null, null);
+ static class MethodArgs {
+ public MethodHandle syncMethod;
+ public MethodHandle asyncMethod;
+ public String asyncMethodName;
+ }
+
/**
* This annotation indicates that a subclass of View is allowed to be used
@@ -307,6 +315,12 @@ public class RemoteViews implements Parcelable, Filter {
public ActionException(String message) {
super(message);
}
+ /**
+ * @hide
+ */
+ public ActionException(Throwable t) {
+ super(t);
+ }
}
/** @hide */
@@ -943,73 +957,66 @@ public class RemoteViews implements Parcelable, Filter {
return rect;
}
- private Method getMethod(View view, String methodName, Class<?> paramType) {
- Method method;
+ private MethodHandle getMethod(View view, String methodName, Class<?> paramType,
+ boolean async) {
+ MethodArgs result;
Class<? extends View> klass = view.getClass();
- synchronized (sMethodsLock) {
- ArrayMap<MutablePair<String, Class<?>>, Method> methods = sMethods.get(klass);
- if (methods == null) {
- methods = new ArrayMap<MutablePair<String, Class<?>>, Method>();
- sMethods.put(klass, methods);
- }
-
- mPair.first = methodName;
- mPair.second = paramType;
+ synchronized (sMethods) {
+ // The key is defined by the view class, param class and method name.
+ sLookupKey.set(klass, paramType, methodName);
+ result = sMethods.get(sLookupKey);
- method = methods.get(mPair);
- if (method == null) {
+ if (result == null) {
+ Method method;
try {
if (paramType == null) {
method = klass.getMethod(methodName);
} else {
method = klass.getMethod(methodName, paramType);
}
- } catch (NoSuchMethodException ex) {
- throw new ActionException("view: " + klass.getName() + " doesn't have method: "
- + methodName + getParameters(paramType));
- }
+ if (!method.isAnnotationPresent(RemotableViewMethod.class)) {
+ throw new ActionException("view: " + klass.getName()
+ + " can't use method with RemoteViews: "
+ + methodName + getParameters(paramType));
+ }
- if (!method.isAnnotationPresent(RemotableViewMethod.class)) {
- throw new ActionException("view: " + klass.getName()
- + " can't use method with RemoteViews: "
+ result = new MethodArgs();
+ result.syncMethod = MethodHandles.publicLookup().unreflect(method);
+ result.asyncMethodName =
+ method.getAnnotation(RemotableViewMethod.class).asyncImpl();
+ } catch (NoSuchMethodException | IllegalAccessException ex) {
+ throw new ActionException("view: " + klass.getName() + " doesn't have method: "
+ methodName + getParameters(paramType));
}
- methods.put(new MutablePair<String, Class<?>>(methodName, paramType), method);
+ MethodKey key = new MethodKey();
+ key.set(klass, paramType, methodName);
+ sMethods.put(key, result);
}
- }
-
- return method;
- }
- /**
- * @return the async implementation of the provided method.
- */
- private Method getAsyncMethod(Method method) {
- synchronized (sAsyncMethods) {
- int valueIndex = sAsyncMethods.indexOfKey(method);
- if (valueIndex >= 0) {
- return sAsyncMethods.valueAt(valueIndex);
+ if (!async) {
+ return result.syncMethod;
}
-
- RemotableViewMethod annotation = method.getAnnotation(RemotableViewMethod.class);
- Method asyncMethod = null;
- if (!annotation.asyncImpl().isEmpty()) {
+ // Check this so see if async method is implemented or not.
+ if (result.asyncMethodName.isEmpty()) {
+ return null;
+ }
+ // Async method is lazily loaded. If it is not yet loaded, load now.
+ if (result.asyncMethod == null) {
+ MethodType asyncType = result.syncMethod.type()
+ .dropParameterTypes(0, 1).changeReturnType(Runnable.class);
try {
- asyncMethod = method.getDeclaringClass()
- .getMethod(annotation.asyncImpl(), method.getParameterTypes());
- if (!asyncMethod.getReturnType().equals(Runnable.class)) {
- throw new ActionException("Async implementation for " + method.getName() +
- " does not return a Runnable");
- }
- } catch (NoSuchMethodException ex) {
- throw new ActionException("Async implementation declared but not defined for " +
- method.getName());
+ result.asyncMethod = MethodHandles.publicLookup().findVirtual(
+ klass, result.asyncMethodName, asyncType);
+ } catch (NoSuchMethodException | IllegalAccessException ex) {
+ throw new ActionException("Async implementation declared as "
+ + result.asyncMethodName + " but not defined for " + methodName
+ + ": public Runnable " + result.asyncMethodName + " ("
+ + TextUtils.join(",", asyncType.parameterArray()) + ")");
}
}
- sAsyncMethods.put(method, asyncMethod);
- return asyncMethod;
+ return result.asyncMethod;
}
}
@@ -1018,12 +1025,6 @@ public class RemoteViews implements Parcelable, Filter {
return "(" + paramType + ")";
}
- private static Object[] wrapArg(Object value) {
- Object[] args = sInvokeArgsTls.get();
- args[0] = value;
- return args;
- }
-
/**
* Equivalent to calling a combination of {@link Drawable#setAlpha(int)},
* {@link Drawable#setColorFilter(int, android.graphics.PorterDuff.Mode)},
@@ -1140,10 +1141,8 @@ public class RemoteViews implements Parcelable, Filter {
if (view == null) return;
try {
- getMethod(view, this.methodName, null).invoke(view);
- } catch (ActionException e) {
- throw e;
- } catch (Exception ex) {
+ getMethod(view, this.methodName, null, false /* async */).invoke(view);
+ } catch (Throwable ex) {
throw new ActionException(ex);
}
}
@@ -1516,12 +1515,9 @@ public class RemoteViews implements Parcelable, Filter {
if (param == null) {
throw new ActionException("bad type: " + this.type);
}
-
try {
- getMethod(view, this.methodName, param).invoke(view, wrapArg(this.value));
- } catch (ActionException e) {
- throw e;
- } catch (Exception ex) {
+ getMethod(view, this.methodName, param, false /* async */).invoke(view, this.value);
+ } catch (Throwable ex) {
throw new ActionException(ex);
}
}
@@ -1537,11 +1533,10 @@ public class RemoteViews implements Parcelable, Filter {
}
try {
- Method method = getMethod(view, this.methodName, param);
- Method asyncMethod = getAsyncMethod(method);
+ MethodHandle method = getMethod(view, this.methodName, param, true /* async */);
- if (asyncMethod != null) {
- Runnable endAction = (Runnable) asyncMethod.invoke(view, wrapArg(this.value));
+ if (method != null) {
+ Runnable endAction = (Runnable) method.invoke(view, this.value);
if (endAction == null) {
return ACTION_NOOP;
} else {
@@ -1555,9 +1550,7 @@ public class RemoteViews implements Parcelable, Filter {
return new RunnableAction(endAction);
}
}
- } catch (ActionException e) {
- throw e;
- } catch (Exception ex) {
+ } catch (Throwable ex) {
throw new ActionException(ex);
}
@@ -2672,7 +2665,7 @@ public class RemoteViews implements Parcelable, Filter {
* given {@link RemoteViews}.
*
* @param viewId The id of the parent {@link ViewGroup} to add the child into.
- * @param nestedView {@link RemoveViews} of the child to add.
+ * @param nestedView {@link RemoteViews} of the child to add.
* @param index The position at which to add the child.
*
* @hide
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 2561ffe572ab..cbb8d885837f 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -248,6 +248,9 @@ final class SelectionActionModeHelper {
// with the Smart Select animation
layout.getSelection(start, end, (left, top, right, bottom) ->
result.add(new RectF(left, top, right, bottom)));
+
+ result.sort(SmartSelectSprite.RECTANGLE_COMPARATOR);
+
return result;
}
diff --git a/core/java/android/widget/SmartSelectSprite.java b/core/java/android/widget/SmartSelectSprite.java
index 94109d741fd8..8d06f5fdfaf2 100644
--- a/core/java/android/widget/SmartSelectSprite.java
+++ b/core/java/android/widget/SmartSelectSprite.java
@@ -44,11 +44,8 @@ import android.view.animation.Interpolator;
import java.lang.annotation.Retention;
import java.util.Collections;
import java.util.Comparator;
-import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
-import java.util.Set;
-import java.util.Stack;
/**
* A utility class for creating and animating the Smart Select animation.
@@ -59,7 +56,6 @@ final class SmartSelectSprite {
private static final int EXPAND_DURATION = 300;
private static final int CORNER_DURATION = 150;
private static final float STROKE_WIDTH_DP = 1.5F;
- private static final int POINTS_PER_LINE = 4;
// GBLUE700
@ColorInt
@@ -73,36 +69,13 @@ final class SmartSelectSprite {
private Animator mActiveAnimator = null;
@ColorInt
private final int mStrokeColor;
- private Set<Drawable> mExistingAnimationDrawables = new HashSet<>();
- /**
- * Represents a set of points connected by lines.
- */
- private static final class PolygonShape extends Shape {
-
- private final float[] mLineCoordinates;
-
- private PolygonShape(final List<PointF> points) {
- mLineCoordinates = new float[points.size() * POINTS_PER_LINE];
-
- int index = 0;
- PointF currentPoint = points.get(0);
- for (final PointF nextPoint : points) {
- mLineCoordinates[index] = currentPoint.x;
- mLineCoordinates[index + 1] = currentPoint.y;
- mLineCoordinates[index + 2] = nextPoint.x;
- mLineCoordinates[index + 3] = nextPoint.y;
+ static final Comparator<RectF> RECTANGLE_COMPARATOR = Comparator
+ .<RectF>comparingDouble(e -> e.bottom)
+ .thenComparingDouble(e -> e.left);
- index += POINTS_PER_LINE;
- currentPoint = nextPoint;
- }
- }
-
- @Override
- public void draw(Canvas canvas, Paint paint) {
- canvas.drawLines(mLineCoordinates, paint);
- }
- }
+ private Drawable mExistingDrawable = null;
+ private RectangleList mExistingRectangleList = null;
/**
* A rounded rectangle with a configurable corner radius and the ability to expand outside of
@@ -110,7 +83,7 @@ final class SmartSelectSprite {
*/
private static final class RoundedRectangleShape extends Shape {
- private static final String PROPERTY_ROUND_PERCENTAGE = "roundPercentage";
+ private static final String PROPERTY_ROUND_RATIO = "roundRatio";
@Retention(SOURCE)
@IntDef({ExpansionDirection.LEFT, ExpansionDirection.CENTER, ExpansionDirection.RIGHT})
@@ -134,7 +107,7 @@ final class SmartSelectSprite {
private final float mStrokeWidth;
private final RectF mBoundingRectangle;
- private float mRoundPercentage = 1.0f;
+ private float mRoundRatio = 1.0f;
private final @ExpansionDirection int mExpansionDirection;
private final @RectangleBorderType int mRectangleBorderType;
@@ -156,6 +129,12 @@ final class SmartSelectSprite {
mExpansionDirection = expansionDirection;
mRectangleBorderType = rectangleBorderType;
mStrokeWidth = strokeWidth;
+
+ if (boundingRectangle.height() > boundingRectangle.width()) {
+ setRoundRatio(0.0f);
+ } else {
+ setRoundRatio(1.0f);
+ }
}
/*
@@ -195,10 +174,7 @@ final class SmartSelectSprite {
canvas.save();
mClipRect.set(mBoundingRectangle);
- mClipRect.top -= mStrokeWidth;
- mClipRect.bottom += mStrokeWidth;
- mClipRect.left -= mStrokeWidth;
- mClipRect.right += mStrokeWidth;
+ mClipRect.inset(-mStrokeWidth, -mStrokeWidth);
canvas.clipRect(mClipRect);
canvas.drawRoundRect(mDrawRect, adjustedCornerRadius, adjustedCornerRadius, paint);
canvas.restore();
@@ -215,9 +191,12 @@ final class SmartSelectSprite {
canvas.restore();
}
- public void setRoundPercentage(
- @FloatRange(from = 0.0, to = 1.0) final float newPercentage) {
- mRoundPercentage = newPercentage;
+ public void setRoundRatio(@FloatRange(from = 0.0, to = 1.0) final float roundRatio) {
+ mRoundRatio = roundRatio;
+ }
+
+ public float getRoundRatio() {
+ return mRoundRatio;
}
private void setLeftBoundary(final float leftBoundary) {
@@ -233,7 +212,7 @@ final class SmartSelectSprite {
}
private float getAdjustedCornerRadius() {
- return (getCornerRadius() * mRoundPercentage);
+ return (getCornerRadius() * mRoundRatio);
}
private float getBoundingWidth() {
@@ -252,23 +231,27 @@ final class SmartSelectSprite {
*/
private static final class RectangleList extends Shape {
+ @Retention(SOURCE)
+ @IntDef({DisplayType.RECTANGLES, DisplayType.POLYGON})
+ private @interface DisplayType {
+ int RECTANGLES = 0;
+ int POLYGON = 1;
+ }
+
private static final String PROPERTY_RIGHT_BOUNDARY = "rightBoundary";
private static final String PROPERTY_LEFT_BOUNDARY = "leftBoundary";
private final List<RoundedRectangleShape> mRectangles;
private final List<RoundedRectangleShape> mReversedRectangles;
- private RectangleList(List<RoundedRectangleShape> rectangles) {
+ private final Path mOutlinePolygonPath;
+ private @DisplayType int mDisplayType = DisplayType.RECTANGLES;
+
+ private RectangleList(final List<RoundedRectangleShape> rectangles) {
mRectangles = new LinkedList<>(rectangles);
- mRectangles.sort((o1, o2) -> {
- if (o1.mBoundingRectangle.top == o2.mBoundingRectangle.top) {
- return Float.compare(o1.mBoundingRectangle.left, o2.mBoundingRectangle.left);
- } else {
- return Float.compare(o1.mBoundingRectangle.top, o2.mBoundingRectangle.top);
- }
- });
mReversedRectangles = new LinkedList<>(rectangles);
Collections.reverse(mReversedRectangles);
+ mOutlinePolygonPath = generateOutlinePolygonPath(rectangles);
}
private void setLeftBoundary(final float leftBoundary) {
@@ -304,6 +287,10 @@ final class SmartSelectSprite {
}
}
+ void setDisplayType(@DisplayType int displayType) {
+ mDisplayType = displayType;
+ }
+
private int getTotalWidth() {
int sum = 0;
for (RoundedRectangleShape rectangle : mRectangles) {
@@ -314,11 +301,34 @@ final class SmartSelectSprite {
@Override
public void draw(Canvas canvas, Paint paint) {
+ if (mDisplayType == DisplayType.POLYGON) {
+ drawPolygon(canvas, paint);
+ } else {
+ drawRectangles(canvas, paint);
+ }
+ }
+
+ private void drawRectangles(final Canvas canvas, final Paint paint) {
for (RoundedRectangleShape rectangle : mRectangles) {
rectangle.draw(canvas, paint);
}
}
+ private void drawPolygon(final Canvas canvas, final Paint paint) {
+ canvas.drawPath(mOutlinePolygonPath, paint);
+ }
+
+ private static Path generateOutlinePolygonPath(
+ final List<RoundedRectangleShape> rectangles) {
+ final Path path = new Path();
+ for (final RoundedRectangleShape shape : rectangles) {
+ final Path rectanglePath = new Path();
+ rectanglePath.addRect(shape.mBoundingRectangle, Path.Direction.CW);
+ path.op(rectanglePath, Path.Op.UNION);
+ }
+ return path;
+ }
+
}
SmartSelectSprite(final View view) {
@@ -334,91 +344,15 @@ final class SmartSelectSprite {
mView = view;
}
- private static boolean intersectsOrTouches(RectF a, RectF b) {
- return a.left <= b.right && b.left <= a.right && a.top <= b.bottom && b.top <= a.bottom;
- }
-
- private List<Drawable> mergeRectanglesToPolygonShape(
- final List<RectF> rectangles,
- final int color) {
- final List<Drawable> drawables = new LinkedList<>();
- final Set<List<PointF>> mergedPaths = calculateMergedPolygonPoints(rectangles);
-
- for (List<PointF> path : mergedPaths) {
- // Add the starting point to the end of the polygon so that it ends up closed.
- path.add(path.get(0));
-
- final PolygonShape shape = new PolygonShape(path);
- final ShapeDrawable drawable = new ShapeDrawable(shape);
-
- drawable.getPaint().setColor(color);
- drawable.getPaint().setStyle(Paint.Style.STROKE);
- drawable.getPaint().setStrokeWidth(mStrokeWidth);
-
- drawables.add(drawable);
- }
-
- return drawables;
- }
-
- private static Set<List<PointF>> calculateMergedPolygonPoints(
- List<RectF> rectangles) {
- final Set<List<RectF>> partitions = new HashSet<>();
- final LinkedList<RectF> listOfRects = new LinkedList<>(rectangles);
-
- while (!listOfRects.isEmpty()) {
- final RectF candidate = listOfRects.removeFirst();
- final List<RectF> partition = new LinkedList<>();
- partition.add(candidate);
-
- final LinkedList<RectF> otherCandidates = new LinkedList<>();
- otherCandidates.addAll(listOfRects);
-
- while (!otherCandidates.isEmpty()) {
- final RectF otherCandidate = otherCandidates.removeFirst();
- for (RectF partitionElement : partition) {
- if (intersectsOrTouches(partitionElement, otherCandidate)) {
- partition.add(otherCandidate);
- listOfRects.remove(otherCandidate);
- break;
- }
- }
- }
-
- partition.sort(Comparator.comparing(o -> o.top));
- partitions.add(partition);
- }
-
- final Set<List<PointF>> result = new HashSet<>();
- for (List<RectF> partition : partitions) {
- final List<PointF> points = new LinkedList<>();
-
- final Stack<RectF> rects = new Stack<>();
- for (RectF rect : partition) {
- points.add(new PointF(rect.right, rect.top));
- points.add(new PointF(rect.right, rect.bottom));
- rects.add(rect);
- }
- while (!rects.isEmpty()) {
- final RectF rect = rects.pop();
- points.add(new PointF(rect.left, rect.bottom));
- points.add(new PointF(rect.left, rect.top));
- }
-
- result.add(points);
- }
-
- return result;
-
- }
-
/**
* Performs the Smart Select animation on the view bound to this SmartSelectSprite.
*
* @param start The point from which the animation will start. Must be inside
* destinationRectangles.
* @param destinationRectangles The rectangles which the animation will fill out by its
- * "selection" and finally join them into a single polygon.
+ * "selection" and finally join them into a single polygon. In
+ * order to get the correct visual behavior, these rectangles
+ * should be sorted according to {@link #RECTANGLE_COMPARATOR}.
* @param onAnimationEnd The callback which will be invoked once the whole animation
* completes.
* @throws IllegalArgumentException if the given start point is not in any of the
@@ -485,17 +419,17 @@ final class SmartSelectSprite {
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(mStrokeWidth);
- addToOverlay(shapeDrawable);
+ mExistingRectangleList = rectangleList;
+ mExistingDrawable = shapeDrawable;
+ mView.getOverlay().add(shapeDrawable);
- mActiveAnimator = createAnimator(mStrokeColor, destinationRectangles, rectangleList,
- startingOffsetLeft, startingOffsetRight, cornerAnimators, updateListener,
+ mActiveAnimator = createAnimator(rectangleList, startingOffsetLeft, startingOffsetRight,
+ cornerAnimators, updateListener,
onAnimationEnd);
mActiveAnimator.start();
}
private Animator createAnimator(
- final @ColorInt int color,
- final List<RectF> destinationRectangles,
final RectangleList rectangleList,
final float startingOffsetLeft,
final float startingOffsetRight,
@@ -532,15 +466,12 @@ final class SmartSelectSprite {
final AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playSequentially(boundaryAnimator, cornerAnimator);
- setUpAnimatorListener(animatorSet, destinationRectangles, color, onAnimationEnd);
+ setUpAnimatorListener(animatorSet, onAnimationEnd);
return animatorSet;
}
- private void setUpAnimatorListener(final Animator animator,
- final List<RectF> destinationRectangles,
- final @ColorInt int color,
- final Runnable onAnimationEnd) {
+ private void setUpAnimatorListener(final Animator animator, final Runnable onAnimationEnd) {
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
@@ -548,15 +479,8 @@ final class SmartSelectSprite {
@Override
public void onAnimationEnd(Animator animator) {
- removeExistingDrawables();
-
- final List<Drawable> polygonShapes = mergeRectanglesToPolygonShape(
- destinationRectangles,
- color);
-
- for (Drawable drawable : polygonShapes) {
- addToOverlay(drawable);
- }
+ mExistingRectangleList.setDisplayType(RectangleList.DisplayType.POLYGON);
+ mExistingDrawable.invalidateSelf();
onAnimationEnd.run();
}
@@ -576,8 +500,8 @@ final class SmartSelectSprite {
final ValueAnimator.AnimatorUpdateListener listener) {
final ObjectAnimator animator = ObjectAnimator.ofFloat(
shape,
- RoundedRectangleShape.PROPERTY_ROUND_PERCENTAGE,
- 1.0F, 0.0F);
+ RoundedRectangleShape.PROPERTY_ROUND_RATIO,
+ shape.getRoundRatio(), 0.0F);
animator.setDuration(CORNER_DURATION);
animator.addUpdateListener(listener);
animator.setInterpolator(mCornerInterpolator);
@@ -585,8 +509,7 @@ final class SmartSelectSprite {
}
private static @RoundedRectangleShape.ExpansionDirection int[] generateDirections(
- final RectF centerRectangle,
- final List<RectF> rectangles) throws IllegalArgumentException {
+ final RectF centerRectangle, final List<RectF> rectangles) {
final @RoundedRectangleShape.ExpansionDirection int[] result = new int[rectangles.size()];
final int centerRectangleIndex = rectangles.indexOf(centerRectangle);
@@ -594,7 +517,17 @@ final class SmartSelectSprite {
for (int i = 0; i < centerRectangleIndex - 1; ++i) {
result[i] = RoundedRectangleShape.ExpansionDirection.LEFT;
}
- result[centerRectangleIndex] = RoundedRectangleShape.ExpansionDirection.CENTER;
+
+ if (rectangles.size() == 1) {
+ result[centerRectangleIndex] = RoundedRectangleShape.ExpansionDirection.CENTER;
+ } else if (centerRectangleIndex == 0) {
+ result[centerRectangleIndex] = RoundedRectangleShape.ExpansionDirection.LEFT;
+ } else if (centerRectangleIndex == rectangles.size() - 1) {
+ result[centerRectangleIndex] = RoundedRectangleShape.ExpansionDirection.RIGHT;
+ } else {
+ result[centerRectangleIndex] = RoundedRectangleShape.ExpansionDirection.CENTER;
+ }
+
for (int i = centerRectangleIndex + 1; i < result.length; ++i) {
result[i] = RoundedRectangleShape.ExpansionDirection.RIGHT;
}
@@ -647,17 +580,12 @@ final class SmartSelectSprite {
&& y <= rectangle.bottom;
}
- private void addToOverlay(final Drawable drawable) {
- mView.getOverlay().add(drawable);
- mExistingAnimationDrawables.add(drawable);
- }
-
private void removeExistingDrawables() {
final ViewOverlay overlay = mView.getOverlay();
- for (Drawable drawable : mExistingAnimationDrawables) {
- overlay.remove(drawable);
- }
- mExistingAnimationDrawables.clear();
+ overlay.remove(mExistingDrawable);
+
+ mExistingDrawable = null;
+ mExistingRectangleList = null;
}
/**
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 5c1bafdbca3f..ceb06f511108 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -36,6 +36,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@@ -50,6 +51,7 @@ import android.os.UserManager;
import android.provider.MediaStore;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.IconDrawableFactory;
import android.util.Log;
import android.util.Slog;
import android.view.LayoutInflater;
@@ -120,6 +122,8 @@ public class ResolverActivity extends Activity {
/** See {@link #setRetainInOnStop}. */
private boolean mRetainInOnStop;
+ IconDrawableFactory mIconFactory;
+
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@Override public void onSomePackagesChanged() {
mAdapter.handlePackagesChanged();
@@ -330,6 +334,13 @@ public class ResolverActivity extends Activity {
: MetricsProto.MetricsEvent.ACTION_SHOW_APP_DISAMBIG_NONE_FEATURED,
intent.getAction() + ":" + intent.getType() + ":"
+ (categories != null ? Arrays.toString(categories.toArray()) : ""));
+ mIconFactory = IconDrawableFactory.newInstance(this, true);
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ mAdapter.handlePackagesChanged();
}
/**
@@ -468,20 +479,20 @@ public class ResolverActivity extends Activity {
if (ri.resolvePackageName != null && ri.icon != 0) {
dr = getIcon(mPm.getResourcesForApplication(ri.resolvePackageName), ri.icon);
if (dr != null) {
- return dr;
+ return mIconFactory.getShadowedIcon(dr);
}
}
final int iconRes = ri.getIconResource();
if (iconRes != 0) {
dr = getIcon(mPm.getResourcesForApplication(ri.activityInfo.packageName), iconRes);
if (dr != null) {
- return dr;
+ return mIconFactory.getShadowedIcon(dr);
}
}
} catch (NameNotFoundException e) {
Log.e(TAG, "Couldn't find resources for package", e);
}
- return ri.loadIcon(mPm);
+ return mIconFactory.getBadgedIcon(ri.activityInfo.applicationInfo);
}
@Override
@@ -1930,7 +1941,8 @@ public class ResolverActivity extends Activity {
final int checkedPos = mAdapterView.getCheckedItemPosition();
final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
if (!useLayoutWithDefault()
- && (!hasValidSelection || mLastSelected != checkedPos)) {
+ && (!hasValidSelection || mLastSelected != checkedPos)
+ && mAlwaysButton != null) {
setAlwaysButtonEnabled(hasValidSelection, checkedPos, true);
mOnceButton.setEnabled(hasValidSelection);
if (hasValidSelection) {
diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java
index 378826dc1deb..77cfc2fc5bd4 100644
--- a/core/java/com/android/internal/app/ResolverComparator.java
+++ b/core/java/com/android/internal/app/ResolverComparator.java
@@ -337,11 +337,13 @@ class ResolverComparator implements Comparator<ResolvedComponentInfo> {
final ResolverTarget rhsTarget = mTargetsDict.get(new ComponentName(
rhs.activityInfo.packageName, rhs.activityInfo.name));
- final int selectProbabilityDiff = Float.compare(
+ if (lhsTarget != null && rhsTarget != null) {
+ final int selectProbabilityDiff = Float.compare(
rhsTarget.getSelectProbability(), lhsTarget.getSelectProbability());
- if (selectProbabilityDiff != 0) {
- return selectProbabilityDiff > 0 ? 1 : -1;
+ if (selectProbabilityDiff != 0) {
+ return selectProbabilityDiff > 0 ? 1 : -1;
+ }
}
}
}
diff --git a/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
index 13cc6e6ea831..8884d24ff0ac 100644
--- a/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
@@ -46,6 +46,7 @@ import java.io.IOException;
* delta.
*/
public class KernelUidCpuFreqTimeReader {
+ private static final boolean DEBUG = false;
private static final String TAG = "KernelUidCpuFreqTimeReader";
private static final String UID_TIMES_PROC_FILE = "/proc/uid_time_in_state";
@@ -165,14 +166,18 @@ public class KernelUidCpuFreqTimeReader {
// If there is malformed data for any uid, then we just log about it and ignore
// the data for that uid.
if (deltaUidTimeMs[i] < 0 || totalTimeMs < 0) {
- final StringBuilder sb = new StringBuilder("Malformed cpu freq data for UID=")
- .append(uid).append("\n");
- sb.append("data=").append("(").append(uidTimeMs[i]).append(",")
- .append(totalTimeMs).append(")").append("\n");
- sb.append("times=").append("(");
- TimeUtils.formatDuration(mLastTimeReadMs, sb); sb.append(",");
- TimeUtils.formatDuration(mNowTimeMs, sb); sb.append(")");
- Slog.e(TAG, sb.toString());
+ if (DEBUG) {
+ final StringBuilder sb = new StringBuilder("Malformed cpu freq data for UID=")
+ .append(uid).append("\n");
+ sb.append("data=").append("(").append(uidTimeMs[i]).append(",")
+ .append(totalTimeMs).append(")").append("\n");
+ sb.append("times=").append("(");
+ TimeUtils.formatDuration(mLastTimeReadMs, sb);
+ sb.append(",");
+ TimeUtils.formatDuration(mNowTimeMs, sb);
+ sb.append(")");
+ Slog.e(TAG, sb.toString());
+ }
return;
}
curUidTimeMs[i] = totalTimeMs;
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 51cf2eae851f..872b465a9ca5 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -205,13 +205,17 @@ public class PowerProfile {
private static final String TAG_ARRAYITEM = "value";
private static final String ATTR_NAME = "name";
+ private static final Object sLock = new Object();
+
public PowerProfile(Context context) {
// Read the XML file for the given profile (normally only one per
// device)
- if (sPowerMap.size() == 0) {
- readPowerValuesFromXml(context);
+ synchronized (sLock) {
+ if (sPowerMap.size() == 0) {
+ readPowerValuesFromXml(context);
+ }
+ initCpuClusters();
}
- initCpuClusters();
}
private void readPowerValuesFromXml(Context context) {
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index bd94fc7b2112..8ea0242b3549 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1807,7 +1807,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
mFloatingActionMode.finish();
}
cleanupFloatingActionModeViews();
- mFloatingToolbar = new FloatingToolbar(mContext, mWindow);
+ mFloatingToolbar = new FloatingToolbar(mWindow);
final FloatingActionMode mode =
new FloatingActionMode(mContext, callback, originatingView, mFloatingToolbar);
mFloatingActionModeOriginatingView = originatingView;
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 544afd993b37..0d66376138c2 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -2453,6 +2453,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
decor.setSystemUiVisibility(
decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
+ if (a.getBoolean(R.styleable.Window_windowLightNavigationBar, false)) {
+ decor.setSystemUiVisibility(
+ decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
+ }
if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion
>= android.os.Build.VERSION_CODES.HONEYCOMB) {
diff --git a/core/java/com/android/internal/view/TooltipPopup.java b/core/java/com/android/internal/view/TooltipPopup.java
index 3930214ea286..d38ea2c19af4 100644
--- a/core/java/com/android/internal/view/TooltipPopup.java
+++ b/core/java/com/android/internal/view/TooltipPopup.java
@@ -93,7 +93,7 @@ public class TooltipPopup {
private void computePosition(View anchorView, int anchorX, int anchorY, boolean fromTouch,
WindowManager.LayoutParams outParams) {
- outParams.token = anchorView.getWindowToken();
+ outParams.token = anchorView.getApplicationWindowToken();
final int tooltipPreciseAnchorThreshold = mContext.getResources().getDimensionPixelOffset(
com.android.internal.R.dimen.tooltip_precise_anchor_threshold);
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index 1d56e1ad3e03..f63b5a213528 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -120,8 +120,10 @@ public final class FloatingToolbar {
/**
* Initializes a floating toolbar.
*/
- public FloatingToolbar(Context context, Window window) {
- mContext = applyDefaultTheme(Preconditions.checkNotNull(context));
+ public FloatingToolbar(Window window) {
+ // TODO(b/65172902): Pass context in constructor when DecorView (and other callers)
+ // supports multi-display.
+ mContext = applyDefaultTheme(window.getContext());
mWindow = Preconditions.checkNotNull(window);
mPopup = new FloatingToolbarPopup(mContext, window.getDecorView());
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index c62934100540..d63e22c189f8 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -103,6 +103,7 @@ cc_library_shared {
"android_nio_utils.cpp",
"android_util_AssetManager.cpp",
"android_util_Binder.cpp",
+ "android_util_StatsLog.cpp",
"android_util_EventLog.cpp",
"android_util_MemoryIntArray.cpp",
"android_util_Log.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 5afd06750601..02c9848ea149 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -111,6 +111,7 @@ namespace android {
extern int register_android_app_admin_SecurityLog(JNIEnv* env);
extern int register_android_content_AssetManager(JNIEnv* env);
extern int register_android_util_EventLog(JNIEnv* env);
+extern int register_android_util_StatsLog(JNIEnv* env);
extern int register_android_util_Log(JNIEnv* env);
extern int register_android_util_MemoryIntArray(JNIEnv* env);
extern int register_android_util_PathParser(JNIEnv* env);
@@ -1311,6 +1312,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
REG_JNI(register_android_os_SystemClock),
REG_JNI(register_android_util_EventLog),
+ REG_JNI(register_android_util_StatsLog),
REG_JNI(register_android_util_Log),
REG_JNI(register_android_util_MemoryIntArray),
REG_JNI(register_android_util_PathParser),
diff --git a/core/jni/android/graphics/pdf/PdfEditor.cpp b/core/jni/android/graphics/pdf/PdfEditor.cpp
index e75712c49fd3..10c30260d7e3 100644
--- a/core/jni/android/graphics/pdf/PdfEditor.cpp
+++ b/core/jni/android/graphics/pdf/PdfEditor.cpp
@@ -60,12 +60,7 @@ static jint nativeRemovePage(JNIEnv* env, jclass thiz, jlong documentPtr, jint p
FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
FPDFPage_Delete(document, pageIndex);
- HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, -1)
-
- int pageCount = FPDF_GetPageCount(document);
- HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, -1)
-
- return pageCount;
+ return FPDF_GetPageCount(document);
}
struct PdfToFdWriter : FPDF_FILEWRITE {
@@ -110,7 +105,6 @@ static void nativeWrite(JNIEnv* env, jclass thiz, jlong documentPtr, jint fd) {
jniThrowExceptionFmt(env, "java/io/IOException",
"cannot write to fd. Error: %d", errno);
}
- HANDLE_PDFIUM_ERROR_STATE(env)
}
static void nativeSetTransformAndClip(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
@@ -123,7 +117,6 @@ static void nativeSetTransformAndClip(JNIEnv* env, jclass thiz, jlong documentPt
"cannot open page");
return;
}
- HANDLE_PDFIUM_ERROR_STATE(env);
double width = 0;
double height = 0;
@@ -134,11 +127,6 @@ static void nativeSetTransformAndClip(JNIEnv* env, jclass thiz, jlong documentPt
"cannot get page size");
return;
}
- bool isExceptionPending = forwardPdfiumError(env);
- if (isExceptionPending) {
- FPDF_ClosePage(page);
- return;
- }
// PDF's coordinate system origin is left-bottom while in graphics it
// is the top-left. So, translate the PDF coordinates to ours.
@@ -170,14 +158,8 @@ static void nativeSetTransformAndClip(JNIEnv* env, jclass thiz, jlong documentPt
FS_RECTF clip = {(float) clipLeft, (float) clipTop, (float) clipRight, (float) clipBottom};
FPDFPage_TransFormWithClip(page, &transform, &clip);
- isExceptionPending = forwardPdfiumError(env);
- if (isExceptionPending) {
- FPDF_ClosePage(page);
- return;
- }
FPDF_ClosePage(page);
- HANDLE_PDFIUM_ERROR_STATE(env);
}
static void nativeGetPageSize(JNIEnv* env, jclass thiz, jlong documentPtr,
@@ -190,7 +172,6 @@ static void nativeGetPageSize(JNIEnv* env, jclass thiz, jlong documentPtr,
"cannot open page");
return;
}
- HANDLE_PDFIUM_ERROR_STATE(env);
double width = 0;
double height = 0;
@@ -201,17 +182,11 @@ static void nativeGetPageSize(JNIEnv* env, jclass thiz, jlong documentPtr,
"cannot get page size");
return;
}
- bool isExceptionPending = forwardPdfiumError(env);
- if (isExceptionPending) {
- FPDF_ClosePage(page);
- return;
- }
env->SetIntField(outSize, gPointClassInfo.x, width);
env->SetIntField(outSize, gPointClassInfo.y, height);
FPDF_ClosePage(page);
- HANDLE_PDFIUM_ERROR_STATE(env);
}
static bool nativeGetPageBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
@@ -224,7 +199,6 @@ static bool nativeGetPageBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint p
"cannot open page");
return false;
}
- HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, false);
float left;
float top;
@@ -234,14 +208,8 @@ static bool nativeGetPageBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint p
const FPDF_BOOL success = (pageBox == PAGE_BOX_MEDIA)
? FPDFPage_GetMediaBox(page, &left, &top, &right, &bottom)
: FPDFPage_GetCropBox(page, &left, &top, &right, &bottom);
- bool isExceptionPending = forwardPdfiumError(env);
- if (isExceptionPending) {
- FPDF_ClosePage(page);
- return false;
- }
FPDF_ClosePage(page);
- HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, false);
if (!success) {
return false;
@@ -279,7 +247,6 @@ static void nativeSetPageBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint p
"cannot open page");
return;
}
- HANDLE_PDFIUM_ERROR_STATE(env);
const int left = env->GetIntField(box, gRectClassInfo.left);
const int top = env->GetIntField(box, gRectClassInfo.top);
@@ -291,14 +258,8 @@ static void nativeSetPageBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint p
} else {
FPDFPage_SetCropBox(page, left, top, right, bottom);
}
- bool isExceptionPending = forwardPdfiumError(env);
- if (isExceptionPending) {
- FPDF_ClosePage(page);
- return;
- }
FPDF_ClosePage(page);
- HANDLE_PDFIUM_ERROR_STATE(env);
}
static void nativeSetPageMediaBox(JNIEnv* env, jclass thiz, jlong documentPtr, jint pageIndex,
diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp
index 95cdbb5cba25..d20c7ef2ec76 100644
--- a/core/jni/android/graphics/pdf/PdfRenderer.cpp
+++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp
@@ -50,7 +50,6 @@ static jlong nativeOpenPageAndGetSize(JNIEnv* env, jclass thiz, jlong documentPt
"cannot load page");
return -1;
}
- HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, -1)
double width = 0;
double height = 0;
@@ -61,7 +60,6 @@ static jlong nativeOpenPageAndGetSize(JNIEnv* env, jclass thiz, jlong documentPt
"cannot get page size");
return -1;
}
- HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, -1)
env->SetIntField(outSize, gPointClassInfo.x, width);
env->SetIntField(outSize, gPointClassInfo.y, height);
@@ -72,7 +70,6 @@ static jlong nativeOpenPageAndGetSize(JNIEnv* env, jclass thiz, jlong documentPt
static void nativeClosePage(JNIEnv* env, jclass thiz, jlong pagePtr) {
FPDF_PAGE page = reinterpret_cast<FPDF_PAGE>(pagePtr);
FPDF_ClosePage(page);
- HANDLE_PDFIUM_ERROR_STATE(env)
}
static void nativeRenderPage(JNIEnv* env, jclass thiz, jlong documentPtr, jlong pagePtr,
@@ -87,11 +84,6 @@ static void nativeRenderPage(JNIEnv* env, jclass thiz, jlong documentPtr, jlong
FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(skBitmap.width(), skBitmap.height(),
FPDFBitmap_BGRA, skBitmap.getPixels(), stride);
- bool isExceptionPending = forwardPdfiumError(env);
- if (isExceptionPending || bitmap == NULL) {
- ALOGE("Error creating bitmap");
- return;
- }
int renderFlags = FPDF_REVERSE_BYTE_ORDER;
if (renderMode == RENDER_MODE_FOR_DISPLAY) {
@@ -129,7 +121,6 @@ static void nativeRenderPage(JNIEnv* env, jclass thiz, jlong documentPtr, jlong
FS_RECTF clip = {(float) clipLeft, (float) clipTop, (float) clipRight, (float) clipBottom};
FPDF_RenderPageBitmapWithMatrix(bitmap, page, &transform, &clip, renderFlags);
- HANDLE_PDFIUM_ERROR_STATE(env);
skBitmap.notifyPixelsChanged();
}
diff --git a/core/jni/android/graphics/pdf/PdfUtils.cpp b/core/jni/android/graphics/pdf/PdfUtils.cpp
index 905a2aa49b1c..dacca78c650a 100644
--- a/core/jni/android/graphics/pdf/PdfUtils.cpp
+++ b/core/jni/android/graphics/pdf/PdfUtils.cpp
@@ -78,34 +78,24 @@ bool forwardPdfiumError(JNIEnv* env) {
return true;
}
-static bool initializeLibraryIfNeeded(JNIEnv* env) {
+static void initializeLibraryIfNeeded(JNIEnv* env) {
if (sUnmatchedPdfiumInitRequestCount == 0) {
FPDF_InitLibrary();
-
- HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, false);
}
sUnmatchedPdfiumInitRequestCount++;
- return true;
}
static void destroyLibraryIfNeeded(JNIEnv* env, bool handleError) {
if (sUnmatchedPdfiumInitRequestCount == 1) {
- FPDF_DestroyLibrary();
-
- if (handleError) {
- HANDLE_PDFIUM_ERROR_STATE(env);
- }
+ FPDF_DestroyLibrary();
}
sUnmatchedPdfiumInitRequestCount--;
}
jlong nativeOpen(JNIEnv* env, jclass thiz, jint fd, jlong size) {
- bool isInitialized = initializeLibraryIfNeeded(env);
- if (!isInitialized) {
- return -1;
- }
+ initializeLibraryIfNeeded(env);
FPDF_FILEACCESS loader;
loader.m_FileLen = size;
@@ -125,7 +115,6 @@ jlong nativeOpen(JNIEnv* env, jclass thiz, jint fd, jlong size) {
void nativeClose(JNIEnv* env, jclass thiz, jlong documentPtr) {
FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
FPDF_CloseDocument(document);
- HANDLE_PDFIUM_ERROR_STATE(env)
destroyLibraryIfNeeded(env, true);
}
@@ -133,17 +122,12 @@ void nativeClose(JNIEnv* env, jclass thiz, jlong documentPtr) {
jint nativeGetPageCount(JNIEnv* env, jclass thiz, jlong documentPtr) {
FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
- int pageCount = FPDF_GetPageCount(document);
- HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, -1);
-
- return pageCount;
+ return FPDF_GetPageCount(document);
}
jboolean nativeScaleForPrinting(JNIEnv* env, jclass thiz, jlong documentPtr) {
FPDF_DOCUMENT document = reinterpret_cast<FPDF_DOCUMENT>(documentPtr);
-
FPDF_BOOL printScaling = FPDF_VIEWERREF_GetPrintScaling(document);
- HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, false);
return printScaling ? JNI_TRUE : JNI_FALSE;
}
diff --git a/core/jni/android/graphics/pdf/PdfUtils.h b/core/jni/android/graphics/pdf/PdfUtils.h
index 6e3cebd6414d..65327382e899 100644
--- a/core/jni/android/graphics/pdf/PdfUtils.h
+++ b/core/jni/android/graphics/pdf/PdfUtils.h
@@ -24,24 +24,6 @@ namespace android {
int getBlock(void* param, unsigned long position, unsigned char* outBuffer,
unsigned long size);
-bool forwardPdfiumError(JNIEnv* env);
-
-#define HANDLE_PDFIUM_ERROR_STATE(env) \
- { \
- bool isExceptionPending = forwardPdfiumError(env); \
- if (isExceptionPending) { \
- return; \
- } \
- }
-
-#define HANDLE_PDFIUM_ERROR_STATE_WITH_RET_CODE(env, retCode) \
- { \
- bool isExceptionPending = forwardPdfiumError(env); \
- if (isExceptionPending) { \
- return retCode; \
- } \
- }
-
jlong nativeOpen(JNIEnv* env, jclass thiz, jint fd, jlong size);
void nativeClose(JNIEnv* env, jclass thiz, jlong documentPtr);
diff --git a/core/jni/android_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp
index 8844fb0a261f..a94cac0f18f5 100644
--- a/core/jni/android_os_SystemProperties.cpp
+++ b/core/jni/android_os_SystemProperties.cpp
@@ -17,188 +17,109 @@
#define LOG_TAG "SysPropJNI"
+#include "android-base/logging.h"
+#include "android-base/properties.h"
#include "cutils/properties.h"
#include "utils/misc.h"
#include <utils/Log.h>
#include "jni.h"
#include "core_jni_helpers.h"
#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/ScopedUtfChars.h>
namespace android
{
-static jstring SystemProperties_getSS(JNIEnv *env, jobject clazz,
- jstring keyJ, jstring defJ)
-{
- int len;
- const char* key;
- char buf[PROPERTY_VALUE_MAX];
- jstring rvJ = NULL;
-
- if (keyJ == NULL) {
- jniThrowNullPointerException(env, "key must not be null.");
- goto error;
- }
-
- key = env->GetStringUTFChars(keyJ, NULL);
-
- len = property_get(key, buf, "");
- if ((len <= 0) && (defJ != NULL)) {
- rvJ = defJ;
- } else if (len >= 0) {
- rvJ = env->NewStringUTF(buf);
- } else {
- rvJ = env->NewStringUTF("");
+namespace {
+
+template <typename T, typename Handler>
+T ConvertKeyAndForward(JNIEnv *env, jstring keyJ, T defJ, Handler handler) {
+ std::string key;
+ {
+ // Scope the String access. If the handler can throw an exception,
+ // releasing the string characters late would trigger an abort.
+ ScopedUtfChars key_utf(env, keyJ);
+ if (key_utf.c_str() == nullptr) {
+ return defJ;
+ }
+ key = key_utf.c_str(); // This will make a copy, but we can't avoid
+ // with the existing interface in
+ // android::base.
}
-
- env->ReleaseStringUTFChars(keyJ, key);
-
-error:
- return rvJ;
+ return handler(key, defJ);
}
-static jstring SystemProperties_getS(JNIEnv *env, jobject clazz,
- jstring keyJ)
+jstring SystemProperties_getSS(JNIEnv *env, jclass clazz, jstring keyJ,
+ jstring defJ)
{
- return SystemProperties_getSS(env, clazz, keyJ, NULL);
+ // Using ConvertKeyAndForward is sub-optimal for copying the key string,
+ // but improves reuse and reasoning over code.
+ auto handler = [&](const std::string& key, jstring defJ) {
+ std::string prop_val = android::base::GetProperty(key, "");
+ if (!prop_val.empty()) {
+ return env->NewStringUTF(prop_val.c_str());
+ };
+ if (defJ != nullptr) {
+ return defJ;
+ }
+ // This function is specified to never return null (or have an
+ // exception pending).
+ return env->NewStringUTF("");
+ };
+ return ConvertKeyAndForward(env, keyJ, defJ, handler);
}
-static jint SystemProperties_get_int(JNIEnv *env, jobject clazz,
- jstring keyJ, jint defJ)
+jstring SystemProperties_getS(JNIEnv *env, jclass clazz, jstring keyJ)
{
- int len;
- const char* key;
- char buf[PROPERTY_VALUE_MAX];
- char* end;
- jint result = defJ;
-
- if (keyJ == NULL) {
- jniThrowNullPointerException(env, "key must not be null.");
- goto error;
- }
-
- key = env->GetStringUTFChars(keyJ, NULL);
-
- len = property_get(key, buf, "");
- if (len > 0) {
- result = strtol(buf, &end, 0);
- if (end == buf) {
- result = defJ;
- }
- }
-
- env->ReleaseStringUTFChars(keyJ, key);
-
-error:
- return result;
+ return SystemProperties_getSS(env, clazz, keyJ, nullptr);
}
-static jlong SystemProperties_get_long(JNIEnv *env, jobject clazz,
- jstring keyJ, jlong defJ)
+template <typename T>
+T SystemProperties_get_integral(JNIEnv *env, jclass, jstring keyJ,
+ T defJ)
{
- int len;
- const char* key;
- char buf[PROPERTY_VALUE_MAX];
- char* end;
- jlong result = defJ;
-
- if (keyJ == NULL) {
- jniThrowNullPointerException(env, "key must not be null.");
- goto error;
- }
-
- key = env->GetStringUTFChars(keyJ, NULL);
-
- len = property_get(key, buf, "");
- if (len > 0) {
- result = strtoll(buf, &end, 0);
- if (end == buf) {
- result = defJ;
- }
- }
-
- env->ReleaseStringUTFChars(keyJ, key);
-
-error:
- return result;
+ auto handler = [](const std::string& key, T defV) {
+ return android::base::GetIntProperty<T>(key, defV);
+ };
+ return ConvertKeyAndForward(env, keyJ, defJ, handler);
}
-static jboolean SystemProperties_get_boolean(JNIEnv *env, jobject clazz,
- jstring keyJ, jboolean defJ)
+jboolean SystemProperties_get_boolean(JNIEnv *env, jclass, jstring keyJ,
+ jboolean defJ)
{
- int len;
- const char* key;
- char buf[PROPERTY_VALUE_MAX];
- jboolean result = defJ;
-
- if (keyJ == NULL) {
- jniThrowNullPointerException(env, "key must not be null.");
- goto error;
- }
-
- key = env->GetStringUTFChars(keyJ, NULL);
-
- len = property_get(key, buf, "");
- if (len == 1) {
- char ch = buf[0];
- if (ch == '0' || ch == 'n')
- result = false;
- else if (ch == '1' || ch == 'y')
- result = true;
- } else if (len > 1) {
- if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
- result = false;
- } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) {
- result = true;
- }
- }
-
- env->ReleaseStringUTFChars(keyJ, key);
-
-error:
- return result;
+ auto handler = [](const std::string& key, jboolean defV) -> jboolean {
+ bool result = android::base::GetBoolProperty(key, defV);
+ return result ? JNI_TRUE : JNI_FALSE;
+ };
+ return ConvertKeyAndForward(env, keyJ, defJ, handler);
}
-static void SystemProperties_set(JNIEnv *env, jobject clazz,
- jstring keyJ, jstring valJ)
+void SystemProperties_set(JNIEnv *env, jobject clazz, jstring keyJ,
+ jstring valJ)
{
- int err;
- const char* key;
- const char* val;
-
- if (keyJ == NULL) {
- jniThrowNullPointerException(env, "key must not be null.");
- return ;
- }
- key = env->GetStringUTFChars(keyJ, NULL);
-
- if (valJ == NULL) {
- val = ""; /* NULL pointer not allowed here */
- } else {
- val = env->GetStringUTFChars(valJ, NULL);
- }
-
- err = property_set(key, val);
-
- env->ReleaseStringUTFChars(keyJ, key);
-
- if (valJ != NULL) {
- env->ReleaseStringUTFChars(valJ, val);
- }
-
- if (err < 0) {
+ auto handler = [&](const std::string& key, bool) {
+ std::string val;
+ if (valJ != nullptr) {
+ ScopedUtfChars key_utf(env, valJ);
+ val = key_utf.c_str();
+ }
+ return android::base::SetProperty(key, val);
+ };
+ if (!ConvertKeyAndForward(env, keyJ, true, handler)) {
+ // Must have been a failure in SetProperty.
jniThrowException(env, "java/lang/RuntimeException",
"failed to set system property");
}
}
-static JavaVM* sVM = NULL;
-static jclass sClazz = NULL;
-static jmethodID sCallChangeCallbacks;
+JavaVM* sVM = nullptr;
+jclass sClazz = nullptr;
+jmethodID sCallChangeCallbacks;
-static void do_report_sysprop_change() {
+void do_report_sysprop_change() {
//ALOGI("Java SystemProperties: VM=%p, Clazz=%p", sVM, sClazz);
- if (sVM != NULL && sClazz != NULL) {
+ if (sVM != nullptr && sClazz != nullptr) {
JNIEnv* env;
if (sVM->GetEnv((void **)&env, JNI_VERSION_1_4) >= 0) {
//ALOGI("Java SystemProperties: calling %p", sCallChangeCallbacks);
@@ -207,47 +128,49 @@ static void do_report_sysprop_change() {
}
}
-static void SystemProperties_add_change_callback(JNIEnv *env, jobject clazz)
+void SystemProperties_add_change_callback(JNIEnv *env, jobject clazz)
{
// This is called with the Java lock held.
- if (sVM == NULL) {
+ if (sVM == nullptr) {
env->GetJavaVM(&sVM);
}
- if (sClazz == NULL) {
+ if (sClazz == nullptr) {
sClazz = (jclass) env->NewGlobalRef(clazz);
sCallChangeCallbacks = env->GetStaticMethodID(sClazz, "callChangeCallbacks", "()V");
add_sysprop_change_callback(do_report_sysprop_change, -10000);
}
}
-static void SystemProperties_report_sysprop_change(JNIEnv /**env*/, jobject /*clazz*/)
+void SystemProperties_report_sysprop_change(JNIEnv /**env*/, jobject /*clazz*/)
{
report_sysprop_change();
}
-static const JNINativeMethod method_table[] = {
- { "native_get", "(Ljava/lang/String;)Ljava/lang/String;",
- (void*) SystemProperties_getS },
- { "native_get", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
- (void*) SystemProperties_getSS },
- { "native_get_int", "(Ljava/lang/String;I)I",
- (void*) SystemProperties_get_int },
- { "native_get_long", "(Ljava/lang/String;J)J",
- (void*) SystemProperties_get_long },
- { "native_get_boolean", "(Ljava/lang/String;Z)Z",
- (void*) SystemProperties_get_boolean },
- { "native_set", "(Ljava/lang/String;Ljava/lang/String;)V",
- (void*) SystemProperties_set },
- { "native_add_change_callback", "()V",
- (void*) SystemProperties_add_change_callback },
- { "native_report_sysprop_change", "()V",
- (void*) SystemProperties_report_sysprop_change },
-};
+} // namespace
int register_android_os_SystemProperties(JNIEnv *env)
{
- return RegisterMethodsOrDie(env, "android/os/SystemProperties", method_table,
- NELEM(method_table));
+ const JNINativeMethod method_table[] = {
+ { "native_get", "(Ljava/lang/String;)Ljava/lang/String;",
+ (void*) SystemProperties_getS },
+ { "native_get",
+ "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
+ (void*) SystemProperties_getSS },
+ { "native_get_int", "(Ljava/lang/String;I)I",
+ (void*) SystemProperties_get_integral<jint> },
+ { "native_get_long", "(Ljava/lang/String;J)J",
+ (void*) SystemProperties_get_integral<jlong> },
+ { "native_get_boolean", "(Ljava/lang/String;Z)Z",
+ (void*) SystemProperties_get_boolean },
+ { "native_set", "(Ljava/lang/String;Ljava/lang/String;)V",
+ (void*) SystemProperties_set },
+ { "native_add_change_callback", "()V",
+ (void*) SystemProperties_add_change_callback },
+ { "native_report_sysprop_change", "()V",
+ (void*) SystemProperties_report_sysprop_change },
+ };
+ return RegisterMethodsOrDie(env, "android/os/SystemProperties",
+ method_table, NELEM(method_table));
}
};
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index 15ab8f7d661b..7442fa2d62dc 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -52,17 +52,46 @@ struct JLineBreaksID {
static jclass gLineBreaks_class;
static JLineBreaksID gLineBreaks_fieldID;
+class JNILineBreakerLineWidth : public minikin::LineBreaker::LineWidthDelegate {
+ public:
+ JNILineBreakerLineWidth(float firstWidth, int32_t firstLineCount, float restWidth,
+ std::vector<float>&& indents, int32_t indentsOffset)
+ : mFirstWidth(firstWidth), mFirstLineCount(firstLineCount), mRestWidth(restWidth),
+ mIndents(std::move(indents)), mIndentsOffset(indentsOffset) {}
+
+ float getLineWidth(size_t lineNo) override {
+ const float width = ((ssize_t)lineNo < (ssize_t)mFirstLineCount)
+ ? mFirstWidth : mRestWidth;
+ if (mIndents.empty()) {
+ return width;
+ }
+
+ const size_t indentIndex = lineNo + mIndentsOffset;
+ if (indentIndex < mIndents.size()) {
+ return width - mIndents[indentIndex];
+ } else {
+ return width - mIndents.back();
+ }
+ }
+
+ private:
+ const float mFirstWidth;
+ const int32_t mFirstLineCount;
+ const float mRestWidth;
+ const std::vector<float> mIndents;
+ const int32_t mIndentsOffset;
+};
+
// set text and set a number of parameters for creating a layout (width, tabstops, strategy,
// hyphenFrequency)
static void nSetupParagraph(JNIEnv* env, jclass, jlong nativePtr, jcharArray text, jint length,
jfloat firstWidth, jint firstWidthLineLimit, jfloat restWidth,
jintArray variableTabStops, jint defaultTabStop, jint strategy, jint hyphenFrequency,
- jboolean isJustified, jintArray indents, jint insetsOffset) {
+ jboolean isJustified, jintArray indents, jint indentsOffset) {
minikin::LineBreaker* b = reinterpret_cast<minikin::LineBreaker*>(nativePtr);
b->resize(length);
env->GetCharArrayRegion(text, 0, length, b->buffer());
b->setText();
- b->setLineWidths(firstWidth, firstWidthLineLimit, restWidth);
if (variableTabStops == nullptr) {
b->setTabStops(nullptr, 0, defaultTabStop);
} else {
@@ -73,17 +102,14 @@ static void nSetupParagraph(JNIEnv* env, jclass, jlong nativePtr, jcharArray tex
b->setHyphenationFrequency(static_cast<minikin::HyphenationFrequency>(hyphenFrequency));
b->setJustified(isJustified);
+ std::vector<float> indentVec;
// TODO: copy indents only once when LineBreaker is started to be used.
if (indents != nullptr) {
- // If indents is not null, it is guaranteed that lineOffset is less than the size of array.
ScopedIntArrayRO indentArr(env, indents);
- std::vector<float> indentVec(
- indentArr.get() + insetsOffset, indentArr.get() + indentArr.size());
- b->setIndents(indentVec);
- } else {
- b->setIndents(std::vector<float>());
+ indentVec.assign(indentArr.get(), indentArr.get() + indentArr.size());
}
-
+ b->setLineWidthDelegate(std::make_unique<JNILineBreakerLineWidth>(
+ firstWidth, firstWidthLineLimit, restWidth, std::move(indentVec), indentsOffset));
}
static void recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks,
diff --git a/core/jni/android_util_StatsLog.cpp b/core/jni/android_util_StatsLog.cpp
new file mode 100644
index 000000000000..c992365094f7
--- /dev/null
+++ b/core/jni/android_util_StatsLog.cpp
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2007-2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fcntl.h>
+#include <log/log_event_list.h>
+
+#include <log/log.h>
+
+#include <nativehelper/JNIHelp.h>
+#include "core_jni_helpers.h"
+#include "jni.h"
+
+#define UNUSED __attribute__((__unused__))
+
+namespace android {
+
+static jclass gCollectionClass;
+static jmethodID gCollectionAddID;
+
+static jclass gIntegerClass;
+static jfieldID gIntegerValueID;
+
+static jclass gLongClass;
+static jfieldID gLongValueID;
+
+static jclass gFloatClass;
+static jfieldID gFloatValueID;
+
+static jclass gStringClass;
+
+/*
+ * In class android.util.StatsLog:
+ * static native int writeInt(int tag, int value)
+ */
+static jint android_util_StatsLog_write_Integer(JNIEnv* env UNUSED,
+ jobject clazz UNUSED,
+ jint tag, jint value)
+{
+ android_log_event_list ctx(tag);
+ ctx << (int32_t)value;
+ return ctx.write(LOG_ID_STATS);
+}
+
+/*
+ * In class android.util.StatsLog:
+ * static native int writeLong(long tag, long value)
+ */
+static jint android_util_StatsLog_write_Long(JNIEnv* env UNUSED,
+ jobject clazz UNUSED,
+ jint tag, jlong value)
+{
+ android_log_event_list ctx(tag);
+ ctx << (int64_t)value;
+ return ctx.write(LOG_ID_STATS);
+}
+
+/*
+ * In class android.util.StatsLog:
+ * static native int writeFloat(long tag, float value)
+ */
+static jint android_util_StatsLog_write_Float(JNIEnv* env UNUSED,
+ jobject clazz UNUSED,
+ jint tag, jfloat value)
+{
+ android_log_event_list ctx(tag);
+ ctx << (float)value;
+ return ctx.write(LOG_ID_STATS);
+}
+
+/*
+ * In class android.util.StatsLog:
+ * static native int writeString(int tag, String value)
+ */
+static jint android_util_StatsLog_write_String(JNIEnv* env,
+ jobject clazz UNUSED,
+ jint tag, jstring value) {
+ android_log_event_list ctx(tag);
+ // Don't throw NPE -- I feel like it's sort of mean for a logging function
+ // to be all crashy if you pass in NULL -- but make the NULL value explicit.
+ if (value != NULL) {
+ const char *str = env->GetStringUTFChars(value, NULL);
+ ctx << str;
+ env->ReleaseStringUTFChars(value, str);
+ } else {
+ ctx << "NULL";
+ }
+ return ctx.write(LOG_ID_STATS);
+}
+
+/*
+ * In class android.util.StatsLog:
+ * static native int writeArray(long tag, Object... value)
+ */
+static jint android_util_StatsLog_write_Array(JNIEnv* env, jobject clazz,
+ jint tag, jobjectArray value) {
+ android_log_event_list ctx(tag);
+
+ if (value == NULL) {
+ ctx << "[NULL]";
+ return ctx.write(LOG_ID_STATS);
+ }
+
+ jsize copied = 0, num = env->GetArrayLength(value);
+ for (; copied < num && copied < 255; ++copied) {
+ if (ctx.status()) break;
+ jobject item = env->GetObjectArrayElement(value, copied);
+ if (item == NULL) {
+ ctx << "NULL";
+ } else if (env->IsInstanceOf(item, gStringClass)) {
+ const char *str = env->GetStringUTFChars((jstring) item, NULL);
+ ctx << str;
+ env->ReleaseStringUTFChars((jstring) item, str);
+ } else if (env->IsInstanceOf(item, gIntegerClass)) {
+ ctx << (int32_t)env->GetIntField(item, gIntegerValueID);
+ } else if (env->IsInstanceOf(item, gLongClass)) {
+ ctx << (int64_t)env->GetLongField(item, gLongValueID);
+ } else if (env->IsInstanceOf(item, gFloatClass)) {
+ ctx << (float)env->GetFloatField(item, gFloatValueID);
+ } else {
+ jniThrowException(env,
+ "java/lang/IllegalArgumentException",
+ "Invalid payload item type");
+ return -1;
+ }
+ env->DeleteLocalRef(item);
+ }
+ return ctx.write(LOG_ID_STATS);
+}
+
+/*
+ * JNI registration.
+ */
+static const JNINativeMethod gRegisterMethods[] = {
+ /* name, signature, funcPtr */
+ { "writeInt", "(II)I", (void*) android_util_StatsLog_write_Integer },
+ { "writeLong", "(IJ)I", (void*) android_util_StatsLog_write_Long },
+ { "writeFloat", "(IF)I", (void*) android_util_StatsLog_write_Float },
+ { "writeString",
+ "(ILjava/lang/String;)I",
+ (void*) android_util_StatsLog_write_String
+ },
+ { "writeArray",
+ "(I[Ljava/lang/Object;)I",
+ (void*) android_util_StatsLog_write_Array
+ },
+};
+
+static struct { const char *name; jclass *clazz; } gClasses[] = {
+ { "java/lang/Integer", &gIntegerClass },
+ { "java/lang/Long", &gLongClass },
+ { "java/lang/Float", &gFloatClass },
+ { "java/lang/String", &gStringClass },
+ { "java/util/Collection", &gCollectionClass },
+};
+
+static struct { jclass *c; const char *name, *ft; jfieldID *id; } gFields[] = {
+ { &gIntegerClass, "value", "I", &gIntegerValueID },
+ { &gLongClass, "value", "J", &gLongValueID },
+ { &gFloatClass, "value", "F", &gFloatValueID },
+};
+
+static struct { jclass *c; const char *name, *mt; jmethodID *id; } gMethods[] = {
+ { &gCollectionClass, "add", "(Ljava/lang/Object;)Z", &gCollectionAddID },
+};
+
+int register_android_util_StatsLog(JNIEnv* env) {
+ for (int i = 0; i < NELEM(gClasses); ++i) {
+ jclass clazz = FindClassOrDie(env, gClasses[i].name);
+ *gClasses[i].clazz = MakeGlobalRefOrDie(env, clazz);
+ }
+
+ for (int i = 0; i < NELEM(gFields); ++i) {
+ *gFields[i].id = GetFieldIDOrDie(env,
+ *gFields[i].c, gFields[i].name, gFields[i].ft);
+ }
+
+ for (int i = 0; i < NELEM(gMethods); ++i) {
+ *gMethods[i].id = GetMethodIDOrDie(env,
+ *gMethods[i].c, gMethods[i].name, gMethods[i].mt);
+ }
+
+ return RegisterMethodsOrDie(
+ env,
+ "android/util/StatsLog",
+ gRegisterMethods, NELEM(gRegisterMethods));
+}
+
+}; // namespace android
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 914688e3e885..fffdda13d11f 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -45,6 +45,8 @@
#include <unistd.h>
#include "android-base/logging.h"
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
#include <cutils/fs.h>
#include <cutils/multiuser.h>
#include <cutils/sched_policy.h>
@@ -65,6 +67,8 @@
namespace {
using android::String8;
+using android::base::StringPrintf;
+using android::base::WriteStringToFile;
static pid_t gSystemServerPid = 0;
@@ -770,6 +774,11 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer(
ALOGE("System server process %d has died. Restarting Zygote!", pid);
RuntimeAbort(env, __LINE__, "System server process has died. Restarting Zygote!");
}
+
+ // Assign system_server to the correct memory cgroup.
+ if (!WriteStringToFile(StringPrintf("%d", pid), "/dev/memcg/system/tasks")) {
+ ALOGE("couldn't write %d to /dev/memcg/system/tasks", pid);
+ }
}
return pid;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4f435af38c96..0d9a9959f1cf 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2635,10 +2635,6 @@
<permission android:name="android.permission.BIND_AUTOFILL_SERVICE"
android:protectionLevel="signature" />
- <!-- @hide TODO(b/37563972): remove once clients use BIND_AUTOFILL_SERVICE -->
- <permission android:name="android.permission.BIND_AUTOFILL"
- android:protectionLevel="signature" />
-
<!-- Must be required by hotword enrollment application,
to ensure that only the system can interact with it.
@hide <p>Not for use by third-party applications.</p> -->
diff --git a/core/res/res/drawable/ic_corp_icon.xml b/core/res/res/drawable/ic_corp_icon.xml
index a6b68f17409d..48531dd8c539 100644
--- a/core/res/res/drawable/ic_corp_icon.xml
+++ b/core/res/res/drawable/ic_corp_icon.xml
@@ -1,12 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
- android:viewportWidth="48.0"
- android:viewportHeight="48.0">
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
<path
- android:pathData="M24,24m-24,0a24,24 0,1 1,48 0a24,24 0,1 1,-48 0"
- android:fillColor="#FF6D00"/>
- <path
- android:pathData="M35.2,15.6h-5.6v-2.8c0,-1.55 -1.25,-2.8 -2.8,-2.8h-5.6c-1.55,0 -2.8,1.25 -2.8,2.8v2.8h-5.6c-1.55,0 -2.79,1.25 -2.79,2.8L10,33.8c0,1.55 1.25,2.8 2.8,2.8h22.4c1.55,0 2.8,-1.25 2.8,-2.8V18.4C38,16.85 36.75,15.6 35.2,15.6zM24,28.2c-1.54,0 -2.8,-1.26 -2.8,-2.8s1.26,-2.8 2.8,-2.8c1.54,0 2.8,1.26 2.8,2.8S25.54,28.2 24,28.2zM26.8,15.6h-5.6v-2.8h5.6V15.6z"
- android:fillColor="#FFFFFF"/>
+ android:pathData="M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v2L4,6c-1.11,0 -1.99,0.89 -1.99,2L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM12,15c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM14,6h-4L10,4h4v2z"
+ android:fillColor="#000000"/>
</vector> \ No newline at end of file
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 1efe639c4f56..0d63fbee456b 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -141,7 +141,7 @@
<string name="cfTemplateRegisteredTime" msgid="6781621964320635172">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: لم تتم إعادة التوجيه"</string>
<string name="fcComplete" msgid="3118848230966886575">"اكتمل كود الميزة."</string>
<string name="fcError" msgid="3327560126588500777">"حدثت مشكلة بالاتصال أو أن كود الميزة غير صحيح."</string>
- <string name="httpErrorOk" msgid="1191919378083472204">"موافق"</string>
+ <string name="httpErrorOk" msgid="1191919378083472204">"حسنًا"</string>
<string name="httpError" msgid="7956392511146698522">"حدث خطأ في الشبكة."</string>
<string name="httpErrorLookup" msgid="4711687456111963163">"‏تعذر العثور على عنوان URL."</string>
<string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"نظام مصادقة الموقع غير معتمد."</string>
@@ -1030,7 +1030,7 @@
<string name="VideoView_error_title" msgid="3534509135438353077">"مشكلة في الفيديو"</string>
<string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"عذرًا، هذا الفيديو غير صالح للبث على هذا الجهاز."</string>
<string name="VideoView_error_text_unknown" msgid="3450439155187810085">"لا يمكنك تشغيل هذا الفيديو."</string>
- <string name="VideoView_error_button" msgid="2822238215100679592">"موافق"</string>
+ <string name="VideoView_error_button" msgid="2822238215100679592">"حسنًا"</string>
<string name="relative_time" msgid="1818557177829411417">"<xliff:g id="DATE">%1$s</xliff:g>، <xliff:g id="TIME">%2$s</xliff:g>"</string>
<string name="noon" msgid="7245353528818587908">"الظهر"</string>
<string name="Noon" msgid="3342127745230013127">"الظهر"</string>
@@ -1065,9 +1065,9 @@
<string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"ليست هناك سعة تخزينية كافية للنظام. تأكد من أنه لديك مساحة خالية تبلغ ٢٥٠ ميغابايت وأعد التشغيل."</string>
<string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> قيد التشغيل"</string>
<string name="app_running_notification_text" msgid="1197581823314971177">"انقر للحصول على مزيد من المعلومات أو لإيقاف التطبيق."</string>
- <string name="ok" msgid="5970060430562524910">"موافق"</string>
+ <string name="ok" msgid="5970060430562524910">"حسنًا"</string>
<string name="cancel" msgid="6442560571259935130">"إلغاء"</string>
- <string name="yes" msgid="5362982303337969312">"موافق"</string>
+ <string name="yes" msgid="5362982303337969312">"حسنًا"</string>
<string name="no" msgid="5141531044935541497">"إلغاء"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"تنبيه"</string>
<string name="loading" msgid="7933681260296021180">"جارٍ التحميل…"</string>
@@ -1267,7 +1267,7 @@
<string name="perms_description_app" msgid="5139836143293299417">"يقدمه <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="no_permissions" msgid="7283357728219338112">"لا أذونات مطلوبة"</string>
<string name="perm_costs_money" msgid="4902470324142151116">"قد يكلفك هذا مالاً."</string>
- <string name="dlg_ok" msgid="7376953167039865701">"موافق"</string>
+ <string name="dlg_ok" msgid="7376953167039865701">"حسنًا"</string>
<string name="usb_charging_notification_title" msgid="6895185153353640787">"‏يتم استخدام الاتصال عبر USB لشحن هذا الجهاز"</string>
<string name="usb_supplying_notification_title" msgid="5310642257296510271">"‏يتم استخدام الاتصال عبر USB لإمداد الجهاز المتصل بالطاقة"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"‏USB لنقل الملفات"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 457d630c97c1..4b7d20f425c7 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -29,7 +29,7 @@
<string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"ভয়েসমেল"</string>
<string name="defaultMsisdnAlphaTag" msgid="2850889754919584674">"MSISDN1"</string>
<string name="mmiError" msgid="5154499457739052907">"সংযোগ সমস্যা বা অবৈধ MMI কোড৷"</string>
- <string name="mmiFdnError" msgid="5224398216385316471">"নির্দিষ্ট নম্বরে ডায়ালযোগ্য হিসাবে প্রক্রিয়াটি সীমিত করা হয়েছে৷"</string>
+ <string name="mmiFdnError" msgid="5224398216385316471">"নির্দিষ্ট নম্বরে ডায়ালযোগ্য হিসেবে প্রক্রিয়াটি সীমিত করা হয়েছে৷"</string>
<string name="mmiErrorWhileRoaming" msgid="762488890299284230">"আপনি রোমিংয়ে থাকাকালীন আপনার ফোন থেকে \'কল ফরওয়ার্ড করার সেটিংস\' পরিবর্তন করা যাবে না৷"</string>
<string name="serviceEnabled" msgid="8147278346414714315">"পরিষেবা সক্ষম করা ছিল৷"</string>
<string name="serviceEnabledFor" msgid="6856228140453471041">"এর জন্য পরিষেবার সক্ষম করা ছিল:"</string>
@@ -142,7 +142,7 @@
<string name="httpErrorLookup" msgid="4711687456111963163">"URL খুঁজে পাওয়া যায়নি৷"</string>
<string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"এই সাইট যাচাইকরণ স্কীমটি সমর্থিত নয়৷"</string>
<string name="httpErrorAuth" msgid="1435065629438044534">"যাচাইকরণ করা যায়নি৷"</string>
- <string name="httpErrorProxyAuth" msgid="1788207010559081331">"প্রক্সী সার্ভারের মাধ্যমে যাচাইকরণ ব্যর্থ হয়েছে৷"</string>
+ <string name="httpErrorProxyAuth" msgid="1788207010559081331">"প্রক্সী সার্ভারের মাধ্যমে প্রমাণীকরণ ব্যর্থ হয়েছে৷"</string>
<string name="httpErrorConnect" msgid="8714273236364640549">"সার্ভারের সাথে সংযোগ স্থাপন করা যায়নি৷"</string>
<string name="httpErrorIO" msgid="2340558197489302188">"সার্ভারের সাথে যোগাযোগ করা যায়নি৷ পরে আবার চেষ্টা করুন৷"</string>
<string name="httpErrorTimeout" msgid="4743403703762883954">"সার্ভারের সাথে সংযোগের সময় শেষ হয়েছে৷"</string>
@@ -316,7 +316,7 @@
<string name="permdesc_receiveMms" msgid="533019437263212260">"অ্যাপ্লিকেশানটিকে MMS বার্তা প্রাপ্ত করার এবং প্রক্রিয়া করার অনুমতি দেয়৷ এর মানে হল অ্যাপ্লিকেশানটি আপনার ডিভাইস থেকে পাঠানো বার্তাগুলিকে পর্যবেক্ষণ করতে পারে এবং মুছতে পারে সেগুলিকে আপনাকে না দেখিয়ে৷"</string>
<string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"সেল সম্প্রচার বার্তা পড়ুন"</string>
<string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"আপনার ডিভাইস দ্বারা প্রাপ্ত সেল সম্প্রচার পড়তে অ্যাপ্লিকেশানটিকে অনুমতি দেয়৷ কয়েকটি স্থানে আপনাকে জরুরি অবস্থার জন্য সতর্ক করতে জরুরি সতর্কতাগুলি বিতরণ করা হয়৷ যখন একটি জরুরি সেল সম্প্রচার প্রাপ্ত হয় তখন ক্ষতিকারক অ্যাপ্লিকেশানগুলি আপনার ডিভাইসের কার্য সম্পাদনা বা কার্যকলাপে প্রতিবন্ধকতার সৃষ্টি করতে পারে৷"</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"গ্রাহক হিসাবে নেওয়া ফিডগুলি পড়ে"</string>
+ <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"গ্রাহক হিসেবে নেওয়া ফিডগুলি পড়ে"</string>
<string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"অ্যাপ্লিকেশানকে বর্তমানে সিঙ্ক করা ফিডগুলির সম্পর্কে বিবরণ পেতে দেয়৷"</string>
<string name="permlab_sendSms" msgid="7544599214260982981">"SMS পাঠানো ও দেখা,আপনি কি পরিচিতি কে এগুলি করার অনুমতি দেবেন?"</string>
<string name="permdesc_sendSms" msgid="7094729298204937667">"অ্যাপ্লিকেশানটিকে এসএমএসগুলি পাঠাতে অনুমতি দেয়৷ এর জন্য অপ্রত্যাশিত চার্জ কাটা হতে পারে৷ ক্ষতিকারক অ্যাপ্লিকেশানগুলি আপনার নিশ্চিতকরণ ছাড়া বার্তা পাঠানোর মাধ্যমে আপনাকে অর্থ চার্জ করতে পারে৷"</string>
@@ -391,7 +391,7 @@
<string name="permdesc_accessCoarseLocation" product="tv" msgid="1884022719818788511">"মোবাইল টাওয়ার এবং ওয়াই-ফাই নেটওয়ার্কগুলির মত নেটওয়ার্কের উৎসগুলির উপর ভিত্তি করে এই অ্যাপটি আপনার অবস্থান সনাক্ত করতে পারে৷ এই অবস্থান পরিষেবাগুলি অবশ্যই চালু রাখতে হবে এবং অ্যাপটি যাতে সেগুলি ব্যবহার করতে পারে সেজন্য সেগুলিকে আপনার টিভিতে উপলব্ধ করে রাখতে হবে৷"</string>
<string name="permdesc_accessCoarseLocation" product="default" msgid="7788009094906196995">"মোবাইল টাওয়ার এবং ওয়াই-ফাই নেটওয়ার্কগুলির মত নেটওয়ার্ক উৎসগুলির উপর ভিত্তি করে এই অ্যাপটি আপনার অবস্থান সনাক্ত করতে পারে৷ এই অবস্থান পরিষেবাগুলি অবশ্যই চালু রাখতে হবে এবং অ্যাপটি যাতে সেগুলি ব্যবহার করতে পারে সেজন্য সেগুলিকে আপনার ফোনে উপলব্ধ করে রাখতে হবে৷"</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"আপনার অডিও সেটিংস পরিবর্তন করে"</string>
- <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"ভলিউম এবং যেখানে স্পিকার আউটপুট সামগ্রী হিসাবে ব্যবহৃত হয় সেই সব ক্ষেত্রে গ্লোবাল অডিও সেটিংসের সংশোধন করতে অ্যাপ্লিকেশানটিকে মঞ্জুর করে৷"</string>
+ <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"ভলিউম এবং যেখানে স্পিকার আউটপুট সামগ্রী হিসেবে ব্যবহৃত হয় সেই সব ক্ষেত্রে গ্লোবাল অডিও সেটিংসের সংশোধন করতে অ্যাপ্লিকেশানটিকে মঞ্জুর করে৷"</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"অডিও রেকর্ড"</string>
<string name="permdesc_recordAudio" msgid="4245930455135321433">"এই অ্যাপটি মাইক্রোফোন ব্যবহার করে যে কোনো সময় অডিও রেকর্ড করতে পারে৷"</string>
<string name="permlab_sim_communication" msgid="2935852302216852065">"সিম এ আদেশগুলি পাঠান"</string>
@@ -570,7 +570,7 @@
<string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"সতর্কীকরণ ছাড়াই এই টিভিতে থাকা ব্যাবহারকার্রী ডেটা মুছে ফেলে৷"</string>
<string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"সতর্কীকরণ ছাড়াই এই ফোনে থাকা ব্যাবহারকার্রী ডেটা মুছে ফেলে৷"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"ডিভাইসের বৈশ্বিক প্রক্সী সেট করে"</string>
- <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"নীতিযখন নীতি সক্ষম করা হয় তখন ডিভাইসের বৈশ্বিক প্রক্সী ব্যবহার করা হবে সেই হিসাবে সেট করে৷ শুধুমাত্র ডিভাইসের মালিক বৈশ্বিক প্রক্সী সেট করতে পারেন৷"</string>
+ <string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"নীতিযখন নীতি সক্ষম করা হয় তখন ডিভাইসের বৈশ্বিক প্রক্সী ব্যবহার করা হবে সেই হিসেবে সেট করে৷ শুধুমাত্র ডিভাইসের মালিক বৈশ্বিক প্রক্সী সেট করতে পারেন৷"</string>
<string name="policylab_expirePassword" msgid="5610055012328825874">"স্ক্রিন লক করার জন্য পাসওয়ার্ডের মেয়াদ শেষ হওয়ার সময় সেট করে"</string>
<string name="policydesc_expirePassword" msgid="5367525762204416046">"স্ক্রিন লক করার পাসওয়ার্ড কত ঘন ঘন পরিবর্তন করা আবশ্যক তা পরিবর্তন করুন৷"</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"সঞ্চয়স্থানের এনক্রিপশান সেট করে"</string>
@@ -963,7 +963,7 @@
<string name="copy" msgid="2681946229533511987">"অনুলিপি"</string>
<string name="failed_to_copy_to_clipboard" msgid="1833662432489814471">"ক্লিপবোর্ডে কপি করা যায়নি"</string>
<string name="paste" msgid="5629880836805036433">"আটকান"</string>
- <string name="paste_as_plain_text" msgid="5427792741908010675">"প্লেইন টেক্সট হিসাবে আটকান"</string>
+ <string name="paste_as_plain_text" msgid="5427792741908010675">"প্লেইন টেক্সট হিসেবে আটকান"</string>
<string name="replace" msgid="5781686059063148930">"প্রতিস্থাপন করুন..."</string>
<string name="delete" msgid="6098684844021697789">"মুছুন"</string>
<string name="copyUrl" msgid="2538211579596067402">"URL কপি করুন"</string>
@@ -1009,7 +1009,7 @@
<string name="whichSendToApplicationNamed" msgid="7768387871529295325">"%1$s ব্যবহার করে পাঠান"</string>
<string name="whichSendToApplicationLabel" msgid="8878962419005813500">"পাঠান"</string>
<string name="whichHomeApplication" msgid="4307587691506919691">"একটি হোম অ্যাপ্লিকেশন নির্বাচন করুন"</string>
- <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"হোম হিসাবে %1$s ব্যবহার করুন"</string>
+ <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"হোম হিসেবে %1$s ব্যবহার করুন"</string>
<string name="whichHomeApplicationLabel" msgid="809529747002918649">"ছবি তুলুন"</string>
<string name="whichImageCaptureApplication" msgid="3680261417470652882">"এই দিয়ে ছবি তুলুন"</string>
<string name="whichImageCaptureApplicationNamed" msgid="8619384150737825003">"%1$s দিয়ে ছবি তুলুন"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index a23595d7eba0..96b9e7685762 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1739,7 +1739,7 @@
<string name="importance_from_person" msgid="9160133597262938296">"Ovo je značajno zbog osoba koje su uključene."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"Da li dozvoljavate aplikaciji <xliff:g id="APP">%1$s</xliff:g> da kreira novog korisnika s računom <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"Da li dozvoljavate da <xliff:g id="APP">%1$s</xliff:g> kreira novog korisnika za <xliff:g id="ACCOUNT">%2$s</xliff:g> (Korisnik sa ovim nalogom već postoji)?"</string>
- <string name="language_selection_title" msgid="2680677278159281088">"Dodaj jezik"</string>
+ <string name="language_selection_title" msgid="2680677278159281088">"Dodajte jezik"</string>
<string name="country_selection_title" msgid="2954859441620215513">"Izbor regije"</string>
<string name="search_language_hint" msgid="7042102592055108574">"Upišite ime jezika"</string>
<string name="language_picker_section_suggested" msgid="8414489646861640885">"Predloženo"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index b7e9ef0c86f2..5fa9e1d12861 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1199,7 +1199,7 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTEIX"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"REBUTJA"</string>
<string name="select_input_method" msgid="8547250819326693584">"Canvia el teclat"</string>
- <string name="show_ime" msgid="2506087537466597099">"El deixa a la pantalla mentre el teclat físic està actiu"</string>
+ <string name="show_ime" msgid="2506087537466597099">"Mantén-lo a la pantalla mentre el teclat físic està actiu"</string>
<string name="hardware" msgid="194658061510127999">"Mostra el teclat virtual"</string>
<string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configura el teclat físic"</string>
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca per seleccionar l\'idioma i el disseny"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 0c27c9a0c606..3f49aa8ef91c 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1199,7 +1199,7 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"COMPARTIR"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"RECHAZAR"</string>
<string name="select_input_method" msgid="8547250819326693584">"Cambiar teclado"</string>
- <string name="show_ime" msgid="2506087537466597099">"Debe seguir en pantalla mientras el teclado físico esté activo"</string>
+ <string name="show_ime" msgid="2506087537466597099">"Sigue en pantalla mientras el teclado físico está activo"</string>
<string name="hardware" msgid="194658061510127999">"Mostrar teclado virtual"</string>
<string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"Configura el teclado físico"</string>
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"Toca para seleccionar el idioma y el diseño"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 4f8b5ed82e50..ea93ca46f6e6 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -315,7 +315,7 @@
<string name="permlab_receiveMms" msgid="1821317344668257098">"recibir mensaxes de texto (MMS)"</string>
<string name="permdesc_receiveMms" msgid="533019437263212260">"Permite á aplicación recibir e procesar mensaxes MMS. Isto significa que a aplicación pode supervisar ou eliminar mensaxes enviadas ao teu dispositivo sen mostrarchas."</string>
<string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"ler mensaxes de difusión móbil"</string>
- <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Permite á aplicación ler mensaxes de difusión móbil recibidas polo teu dispositivo. As alertas de difusión móbil entréganse nalgunhas situacións para avisar de situacións de emerxencia. É posible que aplicacións maliciosas afecten ao rendemento ou funcionamento do teu dispositivo cando se recibe unha difusión móbil de emerxencia."</string>
+ <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Permite á aplicación ler mensaxes de difusión móbil recibidas polo teu dispositivo. As alertas de difusión móbil envíanse nalgunhas localizacións para avisar de situacións de emerxencia. É posible que aplicacións maliciosas afecten ao rendemento ou funcionamento do teu dispositivo cando se recibe unha difusión móbil de emerxencia."</string>
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"ler feeds subscritos"</string>
<string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Permite á aplicación obter detalles acerca dos feeds sincronizados actualmente."</string>
<string name="permlab_sendSms" msgid="7544599214260982981">"enviar e consultar mensaxes de SMS"</string>
@@ -382,7 +382,7 @@
<string name="permdesc_writeCalendar" product="tablet" msgid="1675270619903625982">"Esta aplicación pode engadir, quitar ou cambiar eventos do calendario almacenados na túa tableta. Tamén pode enviar mensaxes que parezan dos propietarios do calendario e cambiar eventos sen comunicárllelo aos propietarios."</string>
<string name="permdesc_writeCalendar" product="tv" msgid="9017809326268135866">"Esta aplicación pode engadir, quitar ou cambiar eventos do calendario almacenados na túa televisión. Tamén pode enviar mensaxes que parezan dos propietarios do calendario e cambiar eventos sen comunicárllelo aos propietarios."</string>
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"Esta aplicación pode engadir, quitar ou cambiar eventos do calendario almacenados no teu teléfono. Tamén pode enviar mensaxes que parezan dos propietarios do calendario e cambiar eventos sen comunicárllelo aos propietarios."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"acceder a comandos adicionais do provedor de situación"</string>
+ <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"acceder a comandos adicionais do provedor de localización"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Permite á aplicación acceder a comandos adicionais de fornecedor de localizacións. É posible que isto provoque que a aplicación interfira co funcionamento do GPS ou doutras fontes da localización."</string>
<string name="permlab_accessFineLocation" msgid="251034415460950944">"acceder á localización precisa (baseada no GPS e na rede)"</string>
<string name="permdesc_accessFineLocation" msgid="5821994817969957884">"Esta aplicación pode obter a túa localización a partir do GPS ou de fontes de localización de rede como torres de telecomunicacións e redes wifi. Para que a aplicación poida utilizar os servizos de localización, deben estar activados e dispoñibles no teu teléfono. Ten en conta que con esta acción pode aumentar o consumo de batería."</string>
@@ -580,7 +580,7 @@
<string name="policylab_disableKeyguardFeatures" msgid="8552277871075367771">"Desactivar algunhas funcións de bloqueo da pantalla"</string>
<string name="policydesc_disableKeyguardFeatures" msgid="2044755691354158439">"Impide o uso dalgunhas funcións de bloqueo da pantalla."</string>
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"Particular"</item>
+ <item msgid="8901098336658710359">"Casa"</item>
<item msgid="869923650527136615">"Móbil"</item>
<item msgid="7897544654242874543">"Traballo"</item>
<item msgid="1103601433382158155">"Fax do traballo"</item>
@@ -590,7 +590,7 @@
<item msgid="9192514806975898961">"Personalizado"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"Particular"</item>
+ <item msgid="8073994352956129127">"Casa"</item>
<item msgid="7084237356602625604">"Traballo"</item>
<item msgid="1112044410659011023">"Outros"</item>
<item msgid="2374913952870110618">"Personalizado"</item>
@@ -602,7 +602,7 @@
<item msgid="4932682847595299369">"Personalizado"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"Particular"</item>
+ <item msgid="1738585194601476694">"Casa"</item>
<item msgid="1359644565647383708">"Traballo"</item>
<item msgid="7868549401053615677">"Outros"</item>
<item msgid="3145118944639869809">"Personalizado"</item>
@@ -623,7 +623,7 @@
<item msgid="1648797903785279353">"Jabber"</item>
</string-array>
<string name="phoneTypeCustom" msgid="1644738059053355820">"Personalizado"</string>
- <string name="phoneTypeHome" msgid="2570923463033985887">"Particular"</string>
+ <string name="phoneTypeHome" msgid="2570923463033985887">"Casa"</string>
<string name="phoneTypeMobile" msgid="6501463557754751037">"Móbil"</string>
<string name="phoneTypeWork" msgid="8863939667059911633">"Traballo"</string>
<string name="phoneTypeFaxWork" msgid="3517792160008890912">"Fax do traballo"</string>
@@ -648,16 +648,16 @@
<string name="eventTypeAnniversary" msgid="3876779744518284000">"Aniversario"</string>
<string name="eventTypeOther" msgid="7388178939010143077">"Outros"</string>
<string name="emailTypeCustom" msgid="8525960257804213846">"Personalizado"</string>
- <string name="emailTypeHome" msgid="449227236140433919">"Particular"</string>
+ <string name="emailTypeHome" msgid="449227236140433919">"Casa"</string>
<string name="emailTypeWork" msgid="3548058059601149973">"Traballo"</string>
<string name="emailTypeOther" msgid="2923008695272639549">"Outro"</string>
<string name="emailTypeMobile" msgid="119919005321166205">"Móbil"</string>
<string name="postalTypeCustom" msgid="8903206903060479902">"Personalizado"</string>
- <string name="postalTypeHome" msgid="8165756977184483097">"Particular"</string>
+ <string name="postalTypeHome" msgid="8165756977184483097">"Casa"</string>
<string name="postalTypeWork" msgid="5268172772387694495">"Traballo"</string>
<string name="postalTypeOther" msgid="2726111966623584341">"Outro"</string>
<string name="imTypeCustom" msgid="2074028755527826046">"Personalizado"</string>
- <string name="imTypeHome" msgid="6241181032954263892">"Particular"</string>
+ <string name="imTypeHome" msgid="6241181032954263892">"Casa"</string>
<string name="imTypeWork" msgid="1371489290242433090">"Traballo"</string>
<string name="imTypeOther" msgid="5377007495735915478">"Outro"</string>
<string name="imProtocolCustom" msgid="6919453836618749992">"Personalizado"</string>
@@ -680,16 +680,16 @@
<string name="relationTypeDomesticPartner" msgid="6904807112121122133">"Parella de feito"</string>
<string name="relationTypeFather" msgid="5228034687082050725">"Pai"</string>
<string name="relationTypeFriend" msgid="7313106762483391262">"Amigo/a"</string>
- <string name="relationTypeManager" msgid="6365677861610137895">"Xestor"</string>
+ <string name="relationTypeManager" msgid="6365677861610137895">"Xefe/a"</string>
<string name="relationTypeMother" msgid="4578571352962758304">"Nai"</string>
- <string name="relationTypeParent" msgid="4755635567562925226">"Pai ou nai"</string>
- <string name="relationTypePartner" msgid="7266490285120262781">"Socio"</string>
+ <string name="relationTypeParent" msgid="4755635567562925226">"Pai/nai"</string>
+ <string name="relationTypePartner" msgid="7266490285120262781">"Socio/a"</string>
<string name="relationTypeReferredBy" msgid="101573059844135524">"Recomendado por"</string>
<string name="relationTypeRelative" msgid="1799819930085610271">"Parente"</string>
<string name="relationTypeSister" msgid="1735983554479076481">"Irmá"</string>
<string name="relationTypeSpouse" msgid="394136939428698117">"Cónxuxe"</string>
<string name="sipAddressTypeCustom" msgid="2473580593111590945">"Personalizado"</string>
- <string name="sipAddressTypeHome" msgid="6093598181069359295">"Particular"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"Casa"</string>
<string name="sipAddressTypeWork" msgid="6920725730797099047">"Traballo"</string>
<string name="sipAddressTypeOther" msgid="4408436162950119849">"Outro"</string>
<string name="quick_contacts_not_available" msgid="746098007828579688">"Non se atopou ningunha aplicación para ver este contacto."</string>
@@ -1266,7 +1266,7 @@
<string name="ime_action_send" msgid="2316166556349314424">"Enviar"</string>
<string name="ime_action_next" msgid="3138843904009813834">"Seguinte"</string>
<string name="ime_action_done" msgid="8971516117910934605">"Feito"</string>
- <string name="ime_action_previous" msgid="1443550039250105948">"Ant"</string>
+ <string name="ime_action_previous" msgid="1443550039250105948">"Ant."</string>
<string name="ime_action_default" msgid="2840921885558045721">"Executar"</string>
<string name="dial_number_using" msgid="5789176425167573586">"Marcar número\nutilizando o <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="create_contact_using" msgid="4947405226788104538">"Crear contacto\na partir de <xliff:g id="NUMBER">%s</xliff:g>"</string>
@@ -1725,7 +1725,7 @@
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"Toca para ver os ficheiros"</string>
<string name="pin_target" msgid="3052256031352291362">"Fixar"</string>
<string name="unpin_target" msgid="3556545602439143442">"Soltar"</string>
- <string name="app_info" msgid="6856026610594615344">"Información de aplicacións"</string>
+ <string name="app_info" msgid="6856026610594615344">"Info. da aplicación"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="5268556852031489931">"Iniciando demostración…"</string>
<string name="demo_restarting_message" msgid="952118052531642451">"Restablecendo dispositivo…"</string>
@@ -1747,7 +1747,7 @@
<string name="time_picker_header_text" msgid="143536825321922567">"Definir hora"</string>
<string name="time_picker_input_error" msgid="7574999942502513765">"Introduce unha hora válida"</string>
<string name="time_picker_prompt_label" msgid="7588093983899966783">"Escribe a hora"</string>
- <string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Cambia ao modo de entrada de texto para introducir a hora."</string>
+ <string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Cambia ao modo de introdución de texto para introducir a hora."</string>
<string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Cambiar ao modo de reloxo para introducir a hora."</string>
<string name="autofill_picker_accessibility_title" msgid="8469043291648711535">"Opcións de autocompletar"</string>
<string name="autofill_save_accessibility_title" msgid="7244365268417107822">"Garda a información no servizo Autocompletar"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index c6998ebc819f..c7d8b1fe6b48 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -120,7 +120,7 @@
<item msgid="3910386316304772394">"वाई-फ़ाई से फ़ोन करने और मैसेज भेजने के लिए, सबसे पहले अपनी मोबाइल और इंटरनेट सेवा देने वाली कंपनी से इस सेवा को सेट अप करने के लिए कहें. उसके बाद सेटिंग से वाई-फ़ाई कॉलिंग को फिर से चालू करें. (गड़बड़ी कोड: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
</string-array>
<string-array name="wfcOperatorErrorNotificationMessages">
- <item msgid="7472393097168811593">"अपनी मोबाइल और इंटरनेट सेवा देने वाली कंपनी से पंजीकृत करें (गड़बड़ी कोड: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
+ <item msgid="7472393097168811593">"अपनी मोबाइल और इंटरनेट सेवा देने वाली कंपनी के साथ रजिस्टर करें (गड़बड़ी कोड: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
</string-array>
<string-array name="wfcSpnFormats">
<item msgid="6830082633573257149">"%s"</item>
@@ -146,7 +146,7 @@
<string name="httpErrorConnect" msgid="8714273236364640549">"सर्वर से कनेक्ट नहीं किया जा सका."</string>
<string name="httpErrorIO" msgid="2340558197489302188">"सर्वर से संचार नहीं किया जा सका. बाद में पुन: प्रयास करें."</string>
<string name="httpErrorTimeout" msgid="4743403703762883954">"सर्वर से कनेक्‍शन का समय समाप्त हुआ."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"पेज में कई सर्वर रीडायरेक्‍ट हैं."</string>
+ <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"पेज में कई ऐसे कई वेबलिंक हैं जो दूसरे सर्वर पर ले जाते हैं."</string>
<string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"प्रोटोकॉल समर्थित नहीं है."</string>
<string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"सुरक्षित कनेक्शन स्थापित नहीं किया जा सका."</string>
<string name="httpErrorBadUrl" msgid="3636929722728881972">"यूआरएल गलत होने की वजह से पेज नहीं खोला जा सका."</string>
@@ -162,8 +162,8 @@
<string name="low_memory" product="tv" msgid="516619861191025923">"टीवी की मेमोरी पूरी हो गई है. स्‍थान खाली करने के लिए कुछ फ़ाइलें हटाएं."</string>
<string name="low_memory" product="default" msgid="3475999286680000541">"फ़ोन मेमोरी भर गया है. स्‍थान खाली करने के लिए कुछ फ़ाइलें हटाएं."</string>
<plurals name="ssl_ca_cert_warning" formatted="false" msgid="5106721205300213569">
- <item quantity="one">प्रमाणपत्र प्राधिकरण इंस्टॉल किए हुए हैं</item>
- <item quantity="other">प्रमाणपत्र प्राधिकरण इंस्टॉल किए हुए हैं</item>
+ <item quantity="one">प्रमाणपत्र अनुमतियों को इंस्टॉल किया गया</item>
+ <item quantity="other">प्रमाणपत्र अनुमतियों को इंस्टॉल किया गया</item>
</plurals>
<string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"किसी अज्ञात तृतीय पक्ष के द्वारा"</string>
<string name="ssl_ca_cert_noti_by_administrator" msgid="3541729986326153557">"आपकी कार्य प्रोफ़ाइल का व्यवस्थापक करता है"</string>
@@ -210,16 +210,16 @@
<string name="global_action_lock" msgid="2844945191792119712">"स्‍क्रीन लॉक"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"पावर बंद"</string>
<string name="global_action_emergency" msgid="7112311161137421166">"आपातकाल"</string>
- <string name="global_action_bug_report" msgid="7934010578922304799">"बग रिपोर्ट"</string>
- <string name="bugreport_title" msgid="2667494803742548533">"बग रिपोर्ट प्राप्त करें"</string>
+ <string name="global_action_bug_report" msgid="7934010578922304799">"गड़बड़ी की रिपोर्ट"</string>
+ <string name="bugreport_title" msgid="2667494803742548533">"गड़बड़ी की रिपोर्ट लें"</string>
<string name="bugreport_message" msgid="398447048750350456">"इससे ईमेल भेजने के लिए, आपके डिवाइस की मौजूदा स्थिति से जुड़ी जानकारी इकट्ठा की जाएगी. गड़बड़ी की रिपोर्ट बनना शुरू होने से लेकर भेजने के लिए तैयार होने तक कुछ समय लगेगा; कृपया इंतज़ार करें."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"सहभागी रिपोर्ट"</string>
<string name="bugreport_option_interactive_summary" msgid="229299488536107968">"अधिकांश परिस्थितियों में इसका उपयोग करें. यह आपको रिपोर्ट की प्रगति ट्रैक करने देता है, समस्या के बारे में अधिक विवरण डालने देता है और स्क्रीनशॉट लेने देता है. यह आपको ऐसे कम उपयोग किए गए अनुभाग मिटाने दे सकता है जिनकी रिपोर्ट करने में अधिक समय लगता है."</string>
<string name="bugreport_option_full_title" msgid="6354382025840076439">"पूर्ण रिपोर्ट"</string>
<string name="bugreport_option_full_summary" msgid="7210859858969115745">"जब आपका डिवाइस ठीक से काम नहीं कर रहा हो या बहुत धीमा हो या जब आपको रिपोर्ट के सभी भागों की ज़रूरत हो, तो सिस्टम से कम से कम रोक-टोक के लिए इस विकल्प का इस्तेमाल करें. यह आपको ज़्यादा जानकारी डालने या अतिरिक्त स्क्रीनशॉट लेने नहीं देता."</string>
<plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
- <item quantity="one">बग रिपोर्ट के लिए <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में स्‍क्रीनशॉट लिया जा रहा है.</item>
- <item quantity="other">बग रिपोर्ट के लिए <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में स्‍क्रीनशॉट लिया जा रहा है.</item>
+ <item quantity="one">गड़बड़ी की रिपोर्ट के लिए <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में स्‍क्रीनशॉट लिया जा रहा है.</item>
+ <item quantity="other">गड़बड़ी की रिपोर्ट के लिए <xliff:g id="NUMBER_1">%d</xliff:g> सेकंड में स्‍क्रीनशॉट लिया जा रहा है.</item>
</plurals>
<string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"साइलेंट मोड (खामोश)"</string>
<string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"ध्‍वनि बंद है"</string>
@@ -232,7 +232,7 @@
<string name="global_action_voice_assist" msgid="7751191495200504480">"आवाज़ से डिवाइस का इस्तेमाल"</string>
<string name="global_action_lockdown" msgid="8751542514724332873">"अभी लॉक करें"</string>
<string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
- <string name="notification_hidden_text" msgid="6351207030447943784">"नया नोटिफ़िकेशन"</string>
+ <string name="notification_hidden_text" msgid="6351207030447943784">"नई सूचना"</string>
<string name="notification_channel_virtual_keyboard" msgid="6969925135507955575">"वर्चुअल कीबोर्ड"</string>
<string name="notification_channel_physical_keyboard" msgid="7297661826966861459">"भौतिक कीबोर्ड"</string>
<string name="notification_channel_security" msgid="7345516133431326347">"सुरक्षा"</string>
@@ -249,8 +249,8 @@
<string name="notification_channel_retail_mode" msgid="6088920674914038779">"खुदरा डेमो"</string>
<string name="notification_channel_usb" msgid="9006850475328924681">"USB कनेक्शन"</string>
<string name="notification_channel_foreground_service" msgid="3931987440602669158">"बैटरी की खपत करने वाले ऐप"</string>
- <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> बैटरी का उपयोग कर रहा है"</string>
- <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> ऐप बैटरी का उपयोग कर रहे हैं"</string>
+ <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> बैटरी का इस्तेमाल कर रहा है"</string>
+ <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> ऐप बैटरी का इस्तेमाल कर रहे हैं"</string>
<string name="foreground_service_tap_for_details" msgid="372046743534354644">"बैटरी और डेटा खर्च की जानकारी के लिए छूएं"</string>
<string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
<string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
@@ -290,8 +290,8 @@
<string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"टैप किए गए आइटम ज़ोर से बोले जाएंगे और स्क्रीन को जेस्चर के ज़रिए एक्सप्लोर किया जा सकता है."</string>
<string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"आपके द्वारा लिखे हुए लेख को ध्यान से देखें"</string>
<string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"क्रेडिट कार्ड नंबर और पासवर्ड जैसा व्यक्तिगत डेटा शामिल होता है."</string>
- <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"प्रदर्शन आवर्धन नियंत्रित करें"</string>
- <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"प्रदर्शन का ज़ूम स्‍तर और स्‍थिति निर्धारण नियंत्रित करें."</string>
+ <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"डिसप्ले को बड़ा-छोटा करने की सुविधा को नियंत्रित करें"</string>
+ <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"डिसप्ले के ज़ूम का स्‍तर और पोज़िशनिंग नियंत्रित करें."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"जेस्चर करें"</string>
<string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"इस सेवा के ज़रिए टैप, स्वाइप, पिंच और बाकी जेस्चर किए जा सकते हैं."</string>
<string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"फ़िंगरप्रिंट जेस्चर"</string>
@@ -504,9 +504,9 @@
<string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"ऐप्स को SD कार्ड पर लिखने देता है."</string>
<string name="permlab_use_sip" msgid="2052499390128979920">"SIP कॉल करें/प्राप्‍त करें"</string>
<string name="permdesc_use_sip" msgid="2297804849860225257">"ऐप्स को SIP कॉल करने और प्राप्‍त करने देती है."</string>
- <string name="permlab_register_sim_subscription" msgid="3166535485877549177">"नए टेलिकॉम सिम कनेक्‍शन पंजीकृत करें"</string>
+ <string name="permlab_register_sim_subscription" msgid="3166535485877549177">"नए टेलिकॉम सिम कनेक्‍शन रजिस्टर करें"</string>
<string name="permdesc_register_sim_subscription" msgid="2138909035926222911">"ऐप को नए टेलिकॉम सिम कनेक्‍शन पंजीकृत करने देती है."</string>
- <string name="permlab_register_call_provider" msgid="108102120289029841">"नए टेलिकॉम कनेक्‍शन पंजीकृत करें"</string>
+ <string name="permlab_register_call_provider" msgid="108102120289029841">"नए टेलिकॉम कनेक्‍शन रजिस्टर करें"</string>
<string name="permdesc_register_call_provider" msgid="7034310263521081388">"ऐप को नए टेलिकॉम कनेक्शन पंजीकृत करने देती है."</string>
<string name="permlab_connection_manager" msgid="1116193254522105375">"टेलीकॉम कनेक्शन प्रबंधित करें"</string>
<string name="permdesc_connection_manager" msgid="5925480810356483565">"ऐप को टेलीकॉम कनेक्शन प्रबंधित करने देती है."</string>
@@ -523,9 +523,9 @@
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"नेटवर्क उपयोग हिसाब बदलें"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"ऐप्स को यह संशोधित करने देता है कि ऐप्स की तुलना में नेटवर्क उपयोग का मूल्यांकन कैसे किया जाता है. सामान्‍य ऐप्स द्वारा उपयोग करने के लिए नहीं."</string>
<string name="permlab_accessNotifications" msgid="7673416487873432268">"सूचना तक पहुंचें"</string>
- <string name="permdesc_accessNotifications" msgid="458457742683431387">"ऐप को सूचना पाने, जांच करने और साफ़ करने देता है, जिनमें अन्य ऐप के ज़रिए पोस्ट की गई सूचनाएं भी शामिल हैं."</string>
- <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"नोटिफ़िकेशन श्रवणकर्ता सेवा से जुड़ें"</string>
- <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"धारक को नोटिफ़िकेशन श्रवणकर्ता सेवा के शीर्ष स्तरीय इंटरफ़ेस से जुड़ने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होनी चाहिए."</string>
+ <string name="permdesc_accessNotifications" msgid="458457742683431387">"ऐप को सूचना पाने, जांच करने और साफ़ करने देता है, जिनमें अन्य ऐप के ज़रिए पोस्ट की गई सूचनाएं भी शामिल हैं."</string>
+ <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"सूचना श्रवणकर्ता सेवा से जुड़ें"</string>
+ <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"उपयोगकर्ता को सूचना सुनने वाली सेवा के सबसे बेहतर इंटरफ़ेस से जुड़ने देती है. सामान्य ऐप के लिए कभी भी इसकी ज़रुरत नहीं होगी."</string>
<string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"किसी स्थिति प्रदाता सेवा से आबद्ध हों"</string>
<string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"धारक को किसी स्थिति प्रदाता सेवा के शीर्ष-स्तर के इंटरफ़ेस से आबद्ध होने देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
<string name="permlab_bindDreamService" msgid="4153646965978563462">"भावी सेवा से आबद्ध करें"</string>
@@ -701,12 +701,12 @@
<string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"अनलॉक करने के लिए पासवर्ड लिखें"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"अनलॉक करने के लिए पिन लिखें"</string>
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"गलत पिन कोड."</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"अनलॉक करने के लिए, मेनू दबाएं और फिर 0 दबाएं."</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"लॉक खोलने के लिए, मेन्यू दबाएं और फिर 0 दबाएं."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"आपातकालीन नंबर"</string>
<string name="lockscreen_carrier_default" msgid="6169005837238288522">"कोई सेवा नहीं"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"स्‍क्रीन लॉक की गई है."</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"अनलॉक करने के लिए मेनू दबाएं या आपातलकालीन कॉल करें."</string>
- <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"अनलॉक करने के लिए मेनू दबाएं."</string>
+ <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"लॉक खोलने के लिए मेन्यू दबाएं या आपातलकालीन कॉल करें."</string>
+ <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"लॉक खोलने के लिए मेन्यू दबाएं."</string>
<string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"अनलॉक करने के लिए आकार आरेखित करें"</string>
<string name="lockscreen_emergency_call" msgid="5298642613417801888">"आपातकाल"</string>
<string name="lockscreen_return_to_call" msgid="5244259785500040021">"कॉल पर वापस लौटें"</string>
@@ -845,7 +845,7 @@
<string name="open_permission_deny" msgid="7374036708316629800">"आपके पास इस पेज को खोलने की अनुमति नहीं है."</string>
<string name="text_copied" msgid="4985729524670131385">"लेख को क्‍लिपबोर्ड पर कॉपी किया गया."</string>
<string name="more_item_label" msgid="4650918923083320495">"अधिक"</string>
- <string name="prepend_shortcut_label" msgid="2572214461676015642">"मेनू+"</string>
+ <string name="prepend_shortcut_label" msgid="2572214461676015642">"मेन्यू+"</string>
<string name="menu_space_shortcut_label" msgid="2410328639272162537">"space"</string>
<string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string>
<string name="menu_delete_shortcut_label" msgid="3658178007202748164">"हटाएं"</string>
@@ -982,7 +982,7 @@
<string name="browse" msgid="6993590095938149861">"ब्राउज़र"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"मेमोरी स्‍थान समाप्‍त हो रहा है"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"हो सकता है कुछ सिस्टम फ़ंक्शन कार्य न करें"</string>
- <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"सिस्टम के लिए पर्याप्त मेमोरी नहीं है. सुनिश्चित करें कि आपके पास 250MB का खाली स्थान है और फिर से प्रारंभ करें."</string>
+ <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"सिस्टम के लिए ज़रूरी मेमोरी नहीं है. पक्का करें कि आपके पास 250एमबी की खाली जगह है और फिर से शुरू करें."</string>
<string name="app_running_notification_title" msgid="8718335121060787914">"<xliff:g id="APP_NAME">%1$s</xliff:g> चल रहा है"</string>
<string name="app_running_notification_text" msgid="1197581823314971177">"अधिक जानकारी के लिए या ऐप्लिकेशन को रोकने के लिए छूएं."</string>
<string name="ok" msgid="5970060430562524910">"ठीक है"</string>
@@ -1039,7 +1039,7 @@
<string name="report" msgid="4060218260984795706">"रिपोर्ट करें"</string>
<string name="wait" msgid="7147118217226317732">"प्रतीक्षा करें"</string>
<string name="webpage_unresponsive" msgid="3272758351138122503">"पेज प्रतिसाद नहीं दे रहा है.\n\nक्‍या आप इसे बंद करना चाहते हैं?"</string>
- <string name="launch_warning_title" msgid="1547997780506713581">"एप्‍लि. रीडायरेक्‍ट किया गया"</string>
+ <string name="launch_warning_title" msgid="1547997780506713581">"ऐप को दूसरे वेबलिंक पर लॉन्च किया गया"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> अभी चल रहा है."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> को वास्‍तविक रूप से लॉन्‍च किया गया था."</string>
<string name="screen_compat_mode_scale" msgid="3202955667675944499">"स्केल"</string>
@@ -1065,7 +1065,7 @@
<string name="heavy_weight_switcher_text" msgid="7022631924534406403">"दूसरा ऐप्स पहले से चल रहा है जिसे किसी नए ऐप्स को प्रारंभ करने के पहले बंद किया जाना आवश्‍यक है."</string>
<string name="old_app_action" msgid="493129172238566282">"<xliff:g id="OLD_APP">%1$s</xliff:g> पर वापस लौटें"</string>
<string name="old_app_description" msgid="2082094275580358049">"नया ऐप्स प्रारंभ न करें."</string>
- <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> प्रारंभ करें"</string>
+ <string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> शुरू करें"</string>
<string name="new_app_description" msgid="1932143598371537340">"पुराने ऐप्स को बिना सहेजे बंद करें."</string>
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> मेमोरी सीमा को पार कर गई है"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"हीप डंप का संग्रह कर लिया गया है; शेयर करने के लिए टैप करें"</string>
@@ -1079,19 +1079,19 @@
<string name="volume_call" msgid="3941680041282788711">"कॉल के दौरान वॉल्‍यूम"</string>
<string name="volume_bluetooth_call" msgid="2002891926351151534">"ब्लूटूथ कॉल के दौरान वॉल्‍यूम"</string>
<string name="volume_alarm" msgid="1985191616042689100">"अलार्म वॉल्‍यूम"</string>
- <string name="volume_notification" msgid="2422265656744276715">"नोटिफ़िकेशन वॉल्‍यूम"</string>
+ <string name="volume_notification" msgid="2422265656744276715">"सूचना की आवाज़"</string>
<string name="volume_unknown" msgid="1400219669770445902">"आवाज़"</string>
<string name="volume_icon_description_bluetooth" msgid="6538894177255964340">"ब्लूटूथ वॉल्‍यूम"</string>
<string name="volume_icon_description_ringer" msgid="3326003847006162496">"रिंगटोन वॉल्‍यूम"</string>
<string name="volume_icon_description_incall" msgid="8890073218154543397">"कॉल वॉल्‍यूम"</string>
<string name="volume_icon_description_media" msgid="4217311719665194215">"मीडिया वॉल्‍यूम"</string>
- <string name="volume_icon_description_notification" msgid="7044986546477282274">"नोटिफ़िकेशन वॉल्‍यूम"</string>
+ <string name="volume_icon_description_notification" msgid="7044986546477282274">"सूचना की आवाज़"</string>
<string name="ringtone_default" msgid="3789758980357696936">"डिफ़ॉल्‍ट रिंगटोन"</string>
<string name="ringtone_default_with_actual" msgid="1767304850491060581">"डिफ़ॉल्ट (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="7937634392408977062">"कोई नहीं"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"रिंगटोन"</string>
<string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"अलार्म ध्वनियां"</string>
- <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"नोटिफ़िकेशन ध्‍वनि"</string>
+ <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"सूचना की आवाज़"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"अज्ञात"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
<item quantity="one">वाई-फ़ाई नेटवर्क उपलब्‍ध</item>
@@ -1131,7 +1131,7 @@
<string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s ऐप्‍लिकेशन %2$s वाई-फ़ाई नेटवर्क से कनेक्‍ट करना चाहता है"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"ऐप्लिकेशन"</string>
<string name="wifi_p2p_dialog_title" msgid="97611782659324517">"वाई-फ़ाई डायरेक्ट"</string>
- <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"वाई-फ़ाई डायरेक्ट प्रारंभ करें. इससे वाई-फ़ाई क्‍लाइंट/हॉटस्पॉट कार्यवाही बंद हो जाएगी."</string>
+ <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"वाई-फ़ाई डायरेक्ट चालू करें. इससे वाई-फ़ाई क्‍लाइंट/हॉटस्पॉट कार्यवाही बंद हो जाएगी."</string>
<string name="wifi_p2p_failed_message" msgid="3763669677935623084">"वाई-फ़ाई डायरेक्ट प्रारंभ नहीं किया जा सका."</string>
<string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"वाई-फ़ाई डायरेक्ट चालू है"</string>
<string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"सेटिंग के लिए टैप करें"</string>
@@ -1164,8 +1164,8 @@
<string name="sim_removed_message" msgid="2333164559970958645">"मान्‍य सि‍म कार्ड डालकर पुन: प्रारंभ करने तक मोबाइल नेटवर्क अनुपलब्‍ध रहेगा."</string>
<string name="sim_done_button" msgid="827949989369963775">"पूर्ण"</string>
<string name="sim_added_title" msgid="3719670512889674693">"सिम कार्ड जोड़ा गया"</string>
- <string name="sim_added_message" msgid="6599945301141050216">"मोबाइल नेटवर्क पर पहुंचने के लिए अपना डिवाइस पुन: प्रारंभ करें."</string>
- <string name="sim_restart_button" msgid="4722407842815232347">"पुन: प्रारंभ करें"</string>
+ <string name="sim_added_message" msgid="6599945301141050216">"मोबाइल नेटवर्क की पहुंच पाने लिए अपना डिवाइस फिर से चालू करें."</string>
+ <string name="sim_restart_button" msgid="4722407842815232347">"फिर से शुरू करें"</string>
<string name="carrier_app_dialog_message" msgid="7066156088266319533">"आपका नया SIM ठीक से काम करे, इसके लिए आपको अपनी मोबाइल और इंटरनेट सेवा देने वाली कंपनी से कोई ऐप इंस्टॉल करना होगा और उसे खोलना होगा."</string>
<string name="carrier_app_dialog_button" msgid="7900235513678617329">"ऐप प्राप्त करें"</string>
<string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"रद्द करें"</string>
@@ -1192,9 +1192,9 @@
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB डीबग कनेक्ट किया गया"</string>
<string name="adb_active_notification_message" msgid="4948470599328424059">"USB डीबग करना अक्षम करने के लिए टैप करें."</string>
<string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB डीबग करना अक्षम करने के लिए चुनें."</string>
- <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"बग रिपोर्ट प्राप्त की जा रही है…"</string>
- <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"बग रिपोर्ट साझा करें?"</string>
- <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"बग रिपोर्ट साझा की जा रही है…"</string>
+ <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"गड़बड़ी की रिपोर्ट ली जा रही है…"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"गड़बड़ी की रिपोर्ट शेयर करें?"</string>
+ <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"गड़बड़ी की रिपोर्ट शेयर की जा रही है…"</string>
<string name="share_remote_bugreport_notification_message_finished" msgid="6029609949340992866">"आपके एडमिन ने इस डिवाइस की समस्या को हल करने में सहायता के लिए एक गड़बड़ी की रिपोर्ट का अनुरोध किया है. ऐप्लिकेशन और डेटा शेयर किए जा सकते हैं."</string>
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"साझा करें"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"अस्वीकार करें"</string>
@@ -1284,10 +1284,10 @@
<string name="accessibility_binding_label" msgid="4148120742096474641">"सरल उपयोग"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"वॉलपेपर"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"वॉलपेपर बदलें"</string>
- <string name="notification_listener_binding_label" msgid="2014162835481906429">"नोटिफ़िकेशन श्रवणकर्ता"</string>
+ <string name="notification_listener_binding_label" msgid="2014162835481906429">"सूचना को सुनने की सुविधा"</string>
<string name="vr_listener_binding_label" msgid="4316591939343607306">"VR श्रोता"</string>
<string name="condition_provider_service_binding_label" msgid="1321343352906524564">"स्थिति प्रदाता"</string>
- <string name="notification_ranker_binding_label" msgid="774540592299064747">"नोटिफ़िकेशन रैंकर सेवा"</string>
+ <string name="notification_ranker_binding_label" msgid="774540592299064747">"सूचना रैंकर सेवा"</string>
<string name="vpn_title" msgid="19615213552042827">"VPN सक्रिय"</string>
<string name="vpn_title_long" msgid="6400714798049252294">"VPN को <xliff:g id="APP">%s</xliff:g> द्वारा सक्रिय किया गया है"</string>
<string name="vpn_text" msgid="1610714069627824309">"नेटवर्क प्रबंधित करने के लिए टैप करें."</string>
@@ -1368,8 +1368,8 @@
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> के साथ साझा करें"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"स्लाइडिंग हैंडल. दबाकर रखें."</string>
<string name="description_target_unlock_tablet" msgid="3833195335629795055">"अनलॉक करने के लिए स्‍वाइप करें."</string>
- <string name="action_bar_home_description" msgid="5293600496601490216">"होम पर नेविगेट करें"</string>
- <string name="action_bar_up_description" msgid="2237496562952152589">"ऊपर नेविगेट करें"</string>
+ <string name="action_bar_home_description" msgid="5293600496601490216">"होम पेज पर जाएं"</string>
+ <string name="action_bar_up_description" msgid="2237496562952152589">"ऊपर जाएं"</string>
<string name="action_menu_overflow_description" msgid="2295659037509008453">"ज़्यादा विकल्प"</string>
<string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
<string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
@@ -1425,7 +1425,7 @@
<string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
<string name="default_audio_route_category_name" msgid="3722811174003886946">"सिस्‍टम"</string>
<string name="bluetooth_a2dp_audio_route_name" msgid="8575624030406771015">"ब्लूटूथ ऑडियो"</string>
- <string name="wireless_display_route_description" msgid="9070346425023979651">"वायरलेस प्रदर्शन"</string>
+ <string name="wireless_display_route_description" msgid="9070346425023979651">"वायरलेस डिसप्ले"</string>
<string name="media_route_button_content_description" msgid="591703006349356016">"कास्ट करें"</string>
<string name="media_route_chooser_title" msgid="1751618554539087622">"डिवाइस से कनेक्ट करें"</string>
<string name="media_route_chooser_title_for_remote_display" msgid="3395541745872017583">"स्क्रीन को डिवाइस में कास्ट करें"</string>
@@ -1499,7 +1499,7 @@
<string name="error_message_title" msgid="4510373083082500195">"गड़बड़ी"</string>
<string name="error_message_change_not_allowed" msgid="1238035947357923497">"आपका व्यवस्थापक इस बदलाव की अनुमति नहीं देता"</string>
<string name="app_not_found" msgid="3429141853498927379">"इस कार्यवाही को प्रबंधित करने के लिए कोई ऐप्स नहीं मिला"</string>
- <string name="revoke" msgid="5404479185228271586">"निरस्‍त करें"</string>
+ <string name="revoke" msgid="5404479185228271586">"रद्द करें"</string>
<string name="mediasize_iso_a0" msgid="1994474252931294172">"ISO A0"</string>
<string name="mediasize_iso_a1" msgid="3333060421529791786">"ISO A1"</string>
<string name="mediasize_iso_a2" msgid="3097535991925798280">"ISO A2"</string>
@@ -1627,7 +1627,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"आपके व्यवस्थापक ने इंस्टॉल किया है"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"आपके व्यवस्थापक ने अपडेट किया है"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"आपके व्यवस्थापक ने हटा दिया है"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"बैटरी लाइफ़ बेहतर बनाने में मदद के लिए, बैटरी सेवर आपके डिवाइस के प्रदर्शन को कम कर देता है और कंपन (वाइब्रेशन), स्‍थान सेवाओं और ज़्यादातर बैकग्राउंड डेटा को सीमित कर देता है. हो सकता है कि ईमेल, मैसेज सेवा और सिंक पर आधारित दूसरे ऐप तब तक ना खुलें जब तक कि आप उन्‍हें नहीं खोलते.\n\nजब आपका डिवाइस चार्ज हो रहा होता है तो बैटरी सेवर अपने आप बंद हो जाता है."</string>
+ <string name="battery_saver_description" msgid="1960431123816253034">"बैटरी लाइफ़ को बेहतर बनाने में मदद करने के लिए, बैटरी सेवर आपके डिवाइस के प्रदर्शन को कम कर देता है और कंपन (वाइब्रेशन), स्‍थान सेवाओं और ज़्यादातर बैकग्राउंड डेटा को सीमित कर देता है. हो सकता है कि ईमेल, मैसेज सेवा और सिंक पर आधारित अन्‍य ऐप तब तक ना खुलें जब तक कि आप उन्‍हें नहीं खोलते.\n\nजब आपका डिवाइस चार्ज हो रहा होता है तो बैटरी सेवर अपने आप बंद हो जाता है."</string>
<string name="data_saver_description" msgid="6015391409098303235">"डेटा खर्च, कम करने के लिए डेटा सेवर कुछ ऐप को बैकग्राउंड में डेटा भेजने या पाने से रोकता है. आप फ़िलहाल जिस एेप का इस्तेमाल कर रहे हैं वह डेटा एक्सेस कर सकता है, लेकिन ऐसा कभी-कभी ही हो पाएगा. उदाहरण के लिए, इसका मतलब है कि इमेज तब तक दिखाई नहीं देंगी जब तक कि आप उन्हें टैप नहीं करते."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"डेटा बचाने की सेटिंग चालू करें?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"चालू करें"</string>
@@ -1700,7 +1700,7 @@
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> चयनित</item>
</plurals>
<string name="default_notification_channel_label" msgid="5929663562028088222">"अवर्गीकृत"</string>
- <string name="importance_from_user" msgid="7318955817386549931">"आपने इन नोटिफ़िकेशन का महत्व सेट किया है."</string>
+ <string name="importance_from_user" msgid="7318955817386549931">"आपने इन सूचनाओं की अहमियत सेट की है."</string>
<string name="importance_from_person" msgid="9160133597262938296">"यह मौजूद व्यक्तियों के कारण महत्वपूर्ण है."</string>
<string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> को <xliff:g id="ACCOUNT">%2$s</xliff:g> के ज़रिये एक नया उपयोगकर्ता बनाने दें?"</string>
<string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> को <xliff:g id="ACCOUNT">%2$s</xliff:g> के ज़रिये एक नया उपयोगकर्ता बनाने दें (इस खाते वाले एक उपयोगकर्ता पहले से मौजूद हैं)?"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index ba5f7e382e62..e86d1141ad28 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -855,8 +855,8 @@
<string name="menu_space_shortcut_label" msgid="2410328639272162537">"רווח"</string>
<string name="menu_enter_shortcut_label" msgid="2743362785111309668">"Enter"</string>
<string name="menu_delete_shortcut_label" msgid="3658178007202748164">"מחק"</string>
- <string name="search_go" msgid="8298016669822141719">"חפש"</string>
- <string name="search_hint" msgid="1733947260773056054">"חפש…"</string>
+ <string name="search_go" msgid="8298016669822141719">"חיפוש"</string>
+ <string name="search_hint" msgid="1733947260773056054">"חיפוש…"</string>
<string name="searchview_description_search" msgid="6749826639098512120">"חיפוש"</string>
<string name="searchview_description_query" msgid="5911778593125355124">"שאילתת חיפוש"</string>
<string name="searchview_description_clear" msgid="1330281990951833033">"נקה שאילתה"</string>
@@ -1243,7 +1243,7 @@
<string name="share_remote_bugreport_action" msgid="6249476773913384948">"שתף"</string>
<string name="decline_remote_bugreport_action" msgid="6230987241608770062">"לא, אין מצב"</string>
<string name="select_input_method" msgid="8547250819326693584">"שינוי מקלדת"</string>
- <string name="show_ime" msgid="2506087537466597099">"תישאר במסך בזמן שהמקלדת הפיזית פעילה"</string>
+ <string name="show_ime" msgid="2506087537466597099">"להשאיר במסך בזמן שהמקלדת הפיזית פעילה"</string>
<string name="hardware" msgid="194658061510127999">"הצג מקלדת וירטואלית"</string>
<string name="select_keyboard_layout_notification_title" msgid="597189518763083494">"הגדרת מקלדת פיזית"</string>
<string name="select_keyboard_layout_notification_message" msgid="8084622969903004900">"הקש כדי לבחור שפה ופריסה"</string>
@@ -1306,7 +1306,7 @@
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"הקש פעמיים לבקרת מרחק מתצוגה"</string>
<string name="gadget_host_error_inflating" msgid="4882004314906466162">"‏לא ניתן להוסיף widget."</string>
<string name="ime_action_go" msgid="8320845651737369027">"התחל"</string>
- <string name="ime_action_search" msgid="658110271822807811">"חפש"</string>
+ <string name="ime_action_search" msgid="658110271822807811">"חיפוש"</string>
<string name="ime_action_send" msgid="2316166556349314424">"שלח"</string>
<string name="ime_action_next" msgid="3138843904009813834">"הבא"</string>
<string name="ime_action_done" msgid="8971516117910934605">"סיום"</string>
@@ -1545,7 +1545,7 @@
<string name="error_message_title" msgid="4510373083082500195">"שגיאה"</string>
<string name="error_message_change_not_allowed" msgid="1238035947357923497">"מנהל המערכת שלך אינו מתיר שינוי זה"</string>
<string name="app_not_found" msgid="3429141853498927379">"לא נמצאה אפליקציה שתומכת בפעולה זו"</string>
- <string name="revoke" msgid="5404479185228271586">"בטל"</string>
+ <string name="revoke" msgid="5404479185228271586">"ביטול"</string>
<string name="mediasize_iso_a0" msgid="1994474252931294172">"ISO A0"</string>
<string name="mediasize_iso_a1" msgid="3333060421529791786">"ISO A1"</string>
<string name="mediasize_iso_a2" msgid="3097535991925798280">"ISO A2"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 8efb68a9e8cc..bacf7317e04b 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -304,7 +304,7 @@
<string name="permdesc_expandStatusBar" msgid="6917549437129401132">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯನ್ನು ವಿಸ್ತರಿಸಲು ಅಥವಾ ಸಂಕುಚಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_install_shortcut" msgid="4279070216371564234">"ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ಸ್ಥಾಪಿಸಿ"</string>
<string name="permdesc_install_shortcut" msgid="8341295916286736996">"ಬಳಕೆದಾರರ ಮಧ್ಯಸ್ಥಿಕೆ ಇಲ್ಲದೆಯೇ ಹೋಮ್‌ಸ್ಕ್ರೀನ್ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ಸೇರಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ."</string>
- <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ಅಸ್ಥಾಪಿಸಿ"</string>
+ <string name="permlab_uninstall_shortcut" msgid="4729634524044003699">"ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ಅನ್‌ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
<string name="permdesc_uninstall_shortcut" msgid="6745743474265057975">"ಬಳಕೆದಾರರ ಮಧ್ಯಸ್ಥಿಕೆ ಇಲ್ಲದೆಯೇ ಹೋಮ್‌ಸ್ಕ್ರೀನ್ ಶಾರ್ಟ್‌ಕಟ್‌ಗಳನ್ನು ತೆಗೆದುಹಾಕಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"ಹೊರಹೋಗುವ ಕರೆಗಳ ಮಾರ್ಗ ಬದಲಿಸಿ"</string>
<string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"ಬೇರೊಂದು ಸಂಖ್ಯೆಗೆ ಕರೆಯನ್ನು ಮರುನಿರ್ದೇಶಿಸಲು ಆಯ್ಕೆಯ ಜೊತೆಗೆ ಹೊರ ಹೋಗುವ ಕರೆಯ ಸಮಯದಲ್ಲಿ ಡಯಲ್‌ ಮಾಡಿದ ಸಂಖ್ಯೆಯನ್ನು ನೋಡಲು ಅಪ್ಲಿಕೇಶನ್‌‌ಗೆ ಅವಕಾಶ ನೀಡುತ್ತದೆ."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index add982a54269..0063809b8a67 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1605,7 +1605,7 @@
</plurals>
<string name="restr_pin_try_later" msgid="973144472490532377">"Кийинчерээк кайталаңыз"</string>
<string name="immersive_cling_title" msgid="8394201622932303336">"Толук экран режими"</string>
- <string name="immersive_cling_description" msgid="3482371193207536040">"Чыгуу үчүн, жогурдан төмөн сүрүңүз."</string>
+ <string name="immersive_cling_description" msgid="3482371193207536040">"Чыгуу үчүн экранды ылдый сүрүп коюңуз."</string>
<string name="immersive_cling_positive" msgid="5016839404568297683">"Түшүндүм"</string>
<string name="done_label" msgid="2093726099505892398">"Даяр"</string>
<string name="hour_picker_description" msgid="6698199186859736512">"Саат жебеси"</string>
diff --git a/core/res/res/values-mcc302-mnc370-pa/strings.xml b/core/res/res/values-mcc302-mnc370-pa/strings.xml
index b93949e190c7..5d3f7aed6181 100644
--- a/core/res/res/values-mcc302-mnc370-pa/strings.xml
+++ b/core/res/res/values-mcc302-mnc370-pa/strings.xml
@@ -21,6 +21,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string-array name="wfcSpnFormats">
<item msgid="5022384999749536798">"%s"</item>
- <item msgid="8117276330682171665">"%s Wi-Fi"</item>
+ <item msgid="8117276330682171665">"%s ਵਾਈ-ਫਾਈ"</item>
</string-array>
</resources>
diff --git a/core/res/res/values-mcc302-mnc720-pa/strings.xml b/core/res/res/values-mcc302-mnc720-pa/strings.xml
index 9b2336d8006d..acf26555cbc8 100644
--- a/core/res/res/values-mcc302-mnc720-pa/strings.xml
+++ b/core/res/res/values-mcc302-mnc720-pa/strings.xml
@@ -21,6 +21,6 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string-array name="wfcSpnFormats">
<item msgid="2776657861851140021">"%s"</item>
- <item msgid="5094669985484060934">"%s Wi-Fi"</item>
+ <item msgid="5094669985484060934">"%s ਵਾਈ-ਫਾਈ"</item>
</string-array>
</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 35c9618e5266..3df154341f2e 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1764,7 +1764,7 @@
<string name="autofill_save_title_with_2types" msgid="5214035651838265325">"Да се зачуваат <xliff:g id="TYPE_0">%1$s</xliff:g> и <xliff:g id="TYPE_1">%2$s</xliff:g> во &lt;b&gt;<xliff:g id="LABEL">%3$s</xliff:g>&lt;/b&gt;?"</string>
<string name="autofill_save_title_with_3types" msgid="6943161834231458441">"Да се зачуваат <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> и <xliff:g id="TYPE_2">%3$s</xliff:g> во &lt;b&gt;<xliff:g id="LABEL">%4$s</xliff:g>&lt;/b&gt;?"</string>
<string name="autofill_save_yes" msgid="6398026094049005921">"Зачувај"</string>
- <string name="autofill_save_no" msgid="2625132258725581787">"Не, благодарам"</string>
+ <string name="autofill_save_no" msgid="2625132258725581787">"Не, фала"</string>
<string name="autofill_save_type_password" msgid="5288448918465971568">"лозинка"</string>
<string name="autofill_save_type_address" msgid="4936707762193009542">"адреса"</string>
<string name="autofill_save_type_credit_card" msgid="7127694776265563071">"кредитна картичка"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 1fd9f1124912..a30039eeef4e 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -549,7 +549,7 @@
<string name="permlab_access_notification_policy" msgid="4247510821662059671">"व्यत्यय आणू नका अॅक्सेस करा"</string>
<string name="permdesc_access_notification_policy" msgid="3296832375218749580">"व्यत्यय आणू नका कॉन्फिगरेशन वाचण्यासाठी आणि लिहिण्यासाठी अॅपला अनुमती देते."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"संकेतशब्द नियम सेट करा"</string>
- <string name="policydesc_limitPassword" msgid="2502021457917874968">"स्क्रीन लॉक संकेतशब्द आणि पिन मध्ये अनुमती दिलेली लांबी आणि वर्ण नियंत्रित करा."</string>
+ <string name="policydesc_limitPassword" msgid="2502021457917874968">"स्क्रीन लॉक पासवर्ड आणि पिन मध्ये अनुमती दिलेले लांबी आणि वर्ण नियंत्रित करा."</string>
<string name="policylab_watchLogin" msgid="5091404125971980158">"स्क्रीन अनलॉक प्रयत्नांचे परीक्षण करा"</string>
<string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"टाइप केलेल्या अयोग्य संकेतशब्दांच्या अंकांचे परीक्षण करा. स्क्रीन अनलॉक केली जाते, तेव्हा टॅबलेट लॉक करा किंवा बरेच संकेतशब्द टाइप केले असल्यास टॅबलेटचा सर्व डेटा मिटवा."</string>
<string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"स्क्रीन अनलॉक करताना टाइप केलेल्या चुकीच्या संकेतशब्दांच्या संख्येचे परीक्षण करा आणि टीव्ही लॉक करा किंवा अनेक चुकीचे संकेतशब्द टाइप केले असल्यास टीव्हीचा सर्व डेटा मिटवा."</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index e10420b41e68..bc7a65c1aed8 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -580,7 +580,7 @@
<string name="policylab_disableKeyguardFeatures" msgid="8552277871075367771">"ဖန်သားပြင်သော့ခတ်နိုင်သည့်အင်္ဂါရပ် အချို့အား ပိတ်ထားပါ"</string>
<string name="policydesc_disableKeyguardFeatures" msgid="2044755691354158439">"ဖန်သားပြင်သော့ခတ်နိုင်သည့်အင်္ဂါရပ် အချို့ အသုံးပြုမှုအား ကာကွယ်ပါ။"</string>
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"ပင်မစာမျက်နှာ"</item>
+ <item msgid="8901098336658710359">"အိမ်"</item>
<item msgid="869923650527136615">"မိုဘိုင်း"</item>
<item msgid="7897544654242874543">"အလုပ်"</item>
<item msgid="1103601433382158155">"အလုပ်ဖက်စ်"</item>
@@ -590,19 +590,19 @@
<item msgid="9192514806975898961">"မိမိစိတ်ကြိုက်"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"ပင်မစာမျက်နှာ"</item>
+ <item msgid="8073994352956129127">"အိမ်"</item>
<item msgid="7084237356602625604">"အလုပ်"</item>
<item msgid="1112044410659011023">"တခြား"</item>
<item msgid="2374913952870110618">"မိမိစိတ်ကြိုက်"</item>
</string-array>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"ပင်မစာမျက်နှာ"</item>
+ <item msgid="6880257626740047286">"အိမ်"</item>
<item msgid="5629153956045109251">"အလုပ်"</item>
<item msgid="4966604264500343469">"တခြား"</item>
<item msgid="4932682847595299369">"မိမိစိတ်ကြိုက်"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"ပင်မစာမျက်နှာ"</item>
+ <item msgid="1738585194601476694">"အိမ်"</item>
<item msgid="1359644565647383708">"အလုပ်"</item>
<item msgid="7868549401053615677">"တခြား"</item>
<item msgid="3145118944639869809">"မိမိစိတ်ကြိုက်"</item>
@@ -645,7 +645,7 @@
<string name="phoneTypeMms" msgid="7254492275502768992">"MMS"</string>
<string name="eventTypeCustom" msgid="7837586198458073404">"မိမိစိတ်ကြိုက်"</string>
<string name="eventTypeBirthday" msgid="2813379844211390740">"မွေးနေ့"</string>
- <string name="eventTypeAnniversary" msgid="3876779744518284000">"အထိမ်းအမှတ်"</string>
+ <string name="eventTypeAnniversary" msgid="3876779744518284000">"နှစ်ပတ်လည်နေ့"</string>
<string name="eventTypeOther" msgid="7388178939010143077">"တခြား"</string>
<string name="emailTypeCustom" msgid="8525960257804213846">"မိမိစိတ်ကြိုက်"</string>
<string name="emailTypeHome" msgid="449227236140433919">"အိမ်"</string>
@@ -653,11 +653,11 @@
<string name="emailTypeOther" msgid="2923008695272639549">"တခြား"</string>
<string name="emailTypeMobile" msgid="119919005321166205">"မိုဘိုင်း"</string>
<string name="postalTypeCustom" msgid="8903206903060479902">"မိမိစိတ်ကြိုက်"</string>
- <string name="postalTypeHome" msgid="8165756977184483097">"ပင်မစာမျက်နှာ"</string>
+ <string name="postalTypeHome" msgid="8165756977184483097">"အိမ်"</string>
<string name="postalTypeWork" msgid="5268172772387694495">"အလုပ်"</string>
<string name="postalTypeOther" msgid="2726111966623584341">"တခြား"</string>
<string name="imTypeCustom" msgid="2074028755527826046">"မိမိစိတ်ကြိုက်"</string>
- <string name="imTypeHome" msgid="6241181032954263892">"ပင်မစာမျက်နှာ"</string>
+ <string name="imTypeHome" msgid="6241181032954263892">"အိမ်"</string>
<string name="imTypeWork" msgid="1371489290242433090">"အလုပ်"</string>
<string name="imTypeOther" msgid="5377007495735915478">"တခြား"</string>
<string name="imProtocolCustom" msgid="6919453836618749992">"မိမိစိတ်ကြိုက်"</string>
@@ -689,7 +689,7 @@
<string name="relationTypeSister" msgid="1735983554479076481">"ညီအမ"</string>
<string name="relationTypeSpouse" msgid="394136939428698117">"အိမ်ထောင်ဖက်"</string>
<string name="sipAddressTypeCustom" msgid="2473580593111590945">"မိမိစိတ်ကြိုက်"</string>
- <string name="sipAddressTypeHome" msgid="6093598181069359295">"ပင်မစာမျက်နှာ"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"အိမ်"</string>
<string name="sipAddressTypeWork" msgid="6920725730797099047">"အလုပ်"</string>
<string name="sipAddressTypeOther" msgid="4408436162950119849">"တခြား"</string>
<string name="quick_contacts_not_available" msgid="746098007828579688">"ဤအဆက်အသွယ်အား ကြည့်ရှုရန် အပလီကေးရှင်းမတွေ့ပါ"</string>
@@ -755,7 +755,7 @@
<string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"သော့ဖွင့်ရန် Google အကောင့်ဖြင့် ဝင်ပါ"</string>
<string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"သုံးစွဲသူ အမှတ် (အီးမေးလ်)"</string>
<string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"စကားဝှက်"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"ဝင်ရန်"</string>
+ <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"လက်မှတ်ထိုးဝင်ရန်"</string>
<string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"အသုံးပြုသူအမည် သို့မဟုတ် လျို့ဝှက် နံပါတ် မှားယွင်းနေသည်"</string>
<string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"သုံးစွဲသူ အမည် သို့ စကားဝှင်ကို မေ့နေပါသလား။ \n"<b>"google.com/accounts/recovery"</b>" ကို သွားရောက်ပါ။"</string>
<string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"စစ်ဆေးနေပါသည်…"</string>
@@ -978,7 +978,7 @@
<string name="editTextMenuTitle" msgid="4909135564941815494">"စာတို လုပ်ဆောင်ချက်"</string>
<string name="email" msgid="4560673117055050403">"အီးမေးလ်"</string>
<string name="dial" msgid="4204975095406423102">"ဖုန်း"</string>
- <string name="map" msgid="6068210738233985748">"မြေပုံများ"</string>
+ <string name="map" msgid="6068210738233985748">"Maps"</string>
<string name="browse" msgid="6993590095938149861">"ဘရောင်ဇာ"</string>
<string name="low_internal_storage_view_title" msgid="5576272496365684834">"သိမ်းဆည်သော နေရာ နည်းနေပါသည်"</string>
<string name="low_internal_storage_view_text" msgid="6640505817617414371">"တချို့ စနစ်လုပ်ငန်းများ အလုပ် မလုပ်ခြင်း ဖြစ်နိုင်ပါသည်"</string>
@@ -1464,7 +1464,7 @@
<string name="kg_login_instructions" msgid="1100551261265506448">"သော့ဖွင့်ရန် သင့်ရဲ့ Google အကောင့်ဖြင့် ဝင်ပါ"</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"သုံးစွဲသူအမည် (အီးမေးလ်)"</string>
<string name="kg_login_password_hint" msgid="9057289103827298549">"စကားဝှက်"</string>
- <string name="kg_login_submit_button" msgid="5355904582674054702">"ဝင်ပါ"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"လက်မှတ်ထိုးဝင်ရန်"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"အသုံးပြုသူ အမည် သို့ စကားဝှက်မမှန်ကန်ပါ"</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"သင် သုံးစွဲသူ အမည် သို့ စကားဝှက်အားမေ့နေပါသလား။\n"<b>"google.com/accounts/recovery"</b>" သို့ သွားရောက်ပါ"</string>
<string name="kg_login_checking_password" msgid="1052685197710252395">"အကောင့်ကို စစ်ဆေးနေစဉ်..."</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 0d2822f2a2f9..326cc99f8c28 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -80,12 +80,12 @@
<string name="RestrictedStateContent" msgid="4278821484643362350">"ਤੁਹਾਡੇ ਟਿਕਾਣੇ \'ਤੇ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ ਵੱਲੋਂ ਉਪਲਬਧ ਨਹੀਂ ਕਰਵਾਈ ਗਈ"</string>
<string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"ਨੈੱਟਵਰਕ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ"</string>
<string name="NetworkPreferenceSwitchSummary" msgid="1203771446683319957">"ਸਿਗਨਲ ਪ੍ਰਾਪਤੀ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਲਈ, ਸੈਟਿੰਗਾਂ &gt; ਨੈੱਟਵਰਕ ਅਤੇ ਇੰਟਰਨੈੱਟ &gt; ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ &gt; ਤਰਜੀਹੀ ਨੈੱਟਵਰਕ ਦੀ ਕਿਸਮ \'ਤੇ ਜਾਓ ਅਤੇ ਚੁਣੀ ਗਈ ਕਿਸਮ ਨੂੰ ਬਦਲਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
- <string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"Wi‑Fi ਕਾਲਿੰਗ ਕਿਰਿਆਸ਼ੀਲ ਹੈ"</string>
+ <string name="EmergencyCallWarningTitle" msgid="4790413876281901612">"ਵਾਈ-ਫਾਈ ਕਾਲਿੰਗ ਕਿਰਿਆਸ਼ੀਲ ਹੈ"</string>
<string name="EmergencyCallWarningSummary" msgid="8973232888021643293">"ਸੰਕਟਕਾਲੀਨ ਕਾਲਾਂ ਲਈ ਕਿਸੇ ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ।"</string>
<string name="notification_channel_network_alert" msgid="4427736684338074967">"ਸੁਚੇਤਨਾਵਾਂ"</string>
<string name="notification_channel_call_forward" msgid="2419697808481833249">"ਕਾਲ ਫਾਰਵਰਡਿੰਗ"</string>
<string name="notification_channel_emergency_callback" msgid="6686166232265733921">"ਸੰਕਟਕਾਲੀਨ ਕਾਲਬੈਕ ਮੋਡ"</string>
- <string name="notification_channel_mobile_data_status" msgid="4575131690860945836">"ਮੋਬਾਈਲ ਡੈਟੇ ਦੀ ਅਵਸਥਾ"</string>
+ <string name="notification_channel_mobile_data_status" msgid="4575131690860945836">"ਮੋਬਾਈਲ ਡਾਟੇ ਦੀ ਸਥਿਤੀ"</string>
<string name="notification_channel_sms" msgid="3441746047346135073">"SMS ਸੁਨੇਹੇ"</string>
<string name="notification_channel_voice_mail" msgid="3954099424160511919">"ਵੌਇਸਮੇਲ ਸੁਨੇਹੇ"</string>
<string name="notification_channel_wfc" msgid="2130802501654254801">"ਵਾਈ-ਫਾਈ ਕਾਲਿੰਗ"</string>
@@ -117,7 +117,7 @@
<string name="roamingTextSearching" msgid="8360141885972279963">"ਸੇਵਾ ਦੀ ਖੋਜ ਕਰ ਰਿਹਾ ਹੈ"</string>
<string name="wfcRegErrorTitle" msgid="2301376280632110664">"ਵਾਈ-ਫਾਈ ਕਾਲਿੰਗ"</string>
<string-array name="wfcOperatorErrorAlertMessages">
- <item msgid="3910386316304772394">"ਵਾਈ-ਫਾਈ ਤੋਂ ਕਾਲਾਂ ਕਰਨ ਅਤੇ ਸੁਨੇਹੇ ਭੇਜਣ ਦੇ ਲਈ, ਸਭ ਤੋਂ ਪਹਿਲਾਂ ਆਪਣੇ ਕੈਰੀਅਰ ਨੂੰ ਇਸ ਸੇਵਾ ਦੀ ਸਥਾਪਨਾ ਕਰਨ ਲਈ ਕਹੋ। ਫਿਰ ਸੈਟਿੰਗਾਂ ਵਿੱਚੋਂ ਵਾਈ-ਫਾਈ ਕਾਲਿੰਗ ਨੂੰ ਦੁਬਾਰਾ ਚਾਲੂ ਕਰੋ। (ਗੜਬੜੀ ਕੋਡ: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
+ <item msgid="3910386316304772394">"ਵਾਈ-ਫਾਈ ਤੋਂ ਕਾਲਾਂ ਕਰਨ ਅਤੇ ਸੁਨੇਹੇ ਭੇਜਣ ਲਈ, ਸਭ ਤੋਂ ਪਹਿਲਾਂ ਆਪਣੇ ਕੈਰੀਅਰ ਨੂੰ ਇਸ ਸੇਵਾ ਦੀ ਸਥਾਪਨਾ ਕਰਨ ਲਈ ਕਹੋ। ਫਿਰ ਸੈਟਿੰਗਾਂ ਵਿੱਚੋਂ ਵਾਈ-ਫਾਈ ਕਾਲਿੰਗ ਨੂੰ ਦੁਬਾਰਾ ਚਾਲੂ ਕਰੋ। (ਗੜਬੜੀ ਕੋਡ: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
</string-array>
<string-array name="wfcOperatorErrorNotificationMessages">
<item msgid="7472393097168811593">"ਆਪਣੇ ਕੈਰੀਅਰ ਨਾਲ ਪੰਜੀਕਰਨ ਕਰੋ (ਗੜਬੜ ਕੋਡ: <xliff:g id="CODE">%1$s</xliff:g>)"</item>
@@ -127,9 +127,9 @@
<item msgid="4397097370387921767">"%s ਵਾਈ-ਫਾਈ ਕਾਲਿੰਗ"</item>
</string-array>
<string name="wifi_calling_off_summary" msgid="8720659586041656098">"ਬੰਦ"</string>
- <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"ਤਰਜੀਹੀ Wi-Fi"</string>
+ <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"ਤਰਜੀਹੀ ਵਾਈ-ਫਾਈ"</string>
<string name="wfc_mode_cellular_preferred_summary" msgid="1988279625335345908">"ਮੋਬਾਈਲ ਨੂੰ ਤਰਜੀਹ ਹੈ"</string>
- <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"ਕੇਵਲ Wi-Fi"</string>
+ <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"ਸਿਰਫ਼ ਵਾਈ-ਫਾਈ"</string>
<string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ਅੱਗੇ ਨਹੀਂ ਭੇਜਿਆ ਗਿਆ"</string>
<string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
<string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> ਸਕਿੰਟਾਂ ਬਾਅਦ"</string>
@@ -385,11 +385,11 @@
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"ਵਾਧੂ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਪ੍ਰਦਾਤਾ ਕਮਾਂਡਾਂ ਤੱਕ ਪਹੁੰਚ"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"ਐਪ ਨੂੰ ਵਾਧੂ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਪ੍ਰਦਾਤਾ ਕਮਾਂਡਾਂ ਤੱਕ ਪਹੁੰਚ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਐਪ ਨੂੰ GPS ਜਾਂ ਹੋਰ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਸਰੋਤਾਂ ਦੇ ਓਪਰੇਸ਼ਨ ਵਿੱਚ ਵਿਘਨ ਪਾਉਣ ਦੀ ਆਗਿਆ ਦੇ ਸਕਦਾ ਹੈ।"</string>
<string name="permlab_accessFineLocation" msgid="251034415460950944">"ਸਟੀਕ ਟਿਕਾਣੇ \'ਤੇ ਪਹੁੰਚ ਕਰੋ (GPS ਅਤੇ ਨੈੱਟਵਰਕ-ਆਧਾਰਿਤ)"</string>
- <string name="permdesc_accessFineLocation" msgid="5821994817969957884">"ਇਹ ਐਪ GPS ਜਾਂ ਨੈੱਟਵਰਕ ਸਰੋਤਾਂ ਜਿਵੇਂ ਕਿ ਸੈੱਲ ਟਾਵਰਾਂ ਅਤੇ Wi-Fi ਨੈੱਟਵਰਕਾਂ \'ਤੇ ਆਧਾਰਿਤ ਤੁਹਾਡਾ ਟਿਕਾਣਾ ਪਤਾ ਕਰ ਸਕਦੀ ਹੈ। ਐਪ ਦੁਆਰਾ ਟਿਕਾਣਾ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕੀਤੇ ਜਾਣ ਦੇ ਯੋਗ ਹੋਣ ਲਈ ਇਹ ਸੇਵਾਵਾਂ ਤੁਹਾਡੇ ਫ਼ੋਨ \'ਤੇ ਉਪਲਬਧ ਹੋਣੀਆਂ ਅਤੇ ਚਾਲੂ ਕੀਤੀਆਂ ਹੋਣੀਆਂ ਲਾਜ਼ਮੀ ਹਨ। ਇਸ ਨਾਲ ਬੈਟਰੀ ਦੀ ਖਪਤ ਵਧ ਸਕਦੀ ਹੈ।"</string>
+ <string name="permdesc_accessFineLocation" msgid="5821994817969957884">"ਇਹ ਐਪ GPS ਜਾਂ ਨੈੱਟਵਰਕ ਸਰੋਤਾਂ ਜਿਵੇਂ ਕਿ ਸੈੱਲ ਟਾਵਰਾਂ ਅਤੇ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕਾਂ \'ਤੇ ਆਧਾਰਿਤ ਤੁਹਾਡਾ ਟਿਕਾਣਾ ਪਤਾ ਕਰ ਸਕਦੀ ਹੈ। ਐਪ ਵੱਲੋਂ ਟਿਕਾਣਾ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕੀਤੇ ਜਾਣ ਦੇ ਯੋਗ ਹੋਣ ਲਈ ਇਹ ਸੇਵਾਵਾਂ ਤੁਹਾਡੇ ਫ਼ੋਨ \'ਤੇ ਉਪਲਬਧ ਹੋਣੀਆਂ ਅਤੇ ਚਾਲੂ ਕੀਤੀਆਂ ਹੋਣੀਆਂ ਲਾਜ਼ਮੀ ਹਨ। ਇਸ ਨਾਲ ਬੈਟਰੀ ਦੀ ਖਪਤ ਵਧ ਸਕਦੀ ਹੈ।"</string>
<string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"ਅੰਦਾਜ਼ਨ ਟਿਕਾਣੇ \'ਤੇ ਪਹੁੰਚ ਕਰੋ (ਨੈੱਟਵਰਕ-ਆਧਾਰਿਤ)"</string>
- <string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"ਇਹ ਐਪ ਨੈੱਟਵਰਕ ਸਰੋਤਾਂ ਜਿਵੇਂ ਕਿ ਸੈੱਲ ਟਾਵਰਾਂ ਅਤੇ Wi-Fi ਨੈੱਟਵਰਕਾਂ \'ਤੇ ਆਧਾਰਿਤ ਤੁਹਾਡਾ ਟਿਕਾਣਾ ਪਤਾ ਕਰ ਸਕਦੀ ਹੈ। ਐਪ ਦੁਆਰਾ ਟਿਕਾਣਾ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕੀਤੇ ਜਾਣ ਦੇ ਯੋਗ ਹੋਣ ਲਈ ਇਹ ਸੇਵਾਵਾਂ ਤੁਹਾਡੇ ਟੈਬਲੈੱਟ \'ਤੇ ਉਪਲਬਧ ਹੋਣੀਆਂ ਅਤੇ ਚਾਲੂ ਕੀਤੀਆਂ ਹੋਣੀਆਂ ਲਾਜ਼ਮੀ ਹਨ।"</string>
- <string name="permdesc_accessCoarseLocation" product="tv" msgid="1884022719818788511">"ਇਹ ਐਪ ਨੈੱਟਵਰਕ ਸਰੋਤਾਂ ਜਿਵੇਂ ਕਿ ਸੈੱਲ ਟਾਵਰਾਂ ਅਤੇ Wi-Fi ਨੈੱਟਵਰਕਾਂ \'ਤੇ ਆਧਾਰਿਤ ਤੁਹਾਡਾ ਟਿਕਾਣਾ ਪਤਾ ਕਰ ਸਕਦੀ ਹੈ। ਐਪ ਦੁਆਰਾ ਟਿਕਾਣਾ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕੀਤੇ ਜਾਣ ਦੇ ਯੋਗ ਹੋਣ ਲਈ ਇਹ ਸੇਵਾਵਾਂ ਤੁਹਾਡੇ ਟੀਵੀ \'ਤੇ ਉਪਲਬਧ ਹੋਣੀਆਂ ਅਤੇ ਚਾਲੂ ਕੀਤੀਆਂ ਹੋਣੀਆਂ ਲਾਜ਼ਮੀ ਹਨ।"</string>
- <string name="permdesc_accessCoarseLocation" product="default" msgid="7788009094906196995">"ਇਹ ਐਪ ਨੈੱਟਵਰਕ ਸਰੋਤਾਂ ਜਿਵੇਂ ਕਿ ਸੈੱਲ ਟਾਵਰਾਂ ਅਤੇ Wi-Fi ਨੈੱਟਵਰਕਾਂ \'ਤੇ ਆਧਾਰਿਤ ਤੁਹਾਡਾ ਟਿਕਾਣਾ ਪਤਾ ਕਰ ਸਕਦੀ ਹੈ। ਐਪ ਦੁਆਰਾ ਟਿਕਾਣਾ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕੀਤੇ ਜਾਣ ਦੇ ਯੋਗ ਹੋਣ ਲਈ ਇਹ ਸੇਵਾਵਾਂ ਤੁਹਾਡੇ ਫ਼ੋਨ \'ਤੇ ਉਪਲਬਧ ਹੋਣੀਆਂ ਅਤੇ ਚਾਲੂ ਕੀਤੀਆਂ ਹੋਣੀਆਂ ਲਾਜ਼ਮੀ ਹਨ।"</string>
+ <string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"ਇਹ ਐਪ ਨੈੱਟਵਰਕ ਸਰੋਤਾਂ ਜਿਵੇਂ ਕਿ ਸੈੱਲ ਟਾਵਰਾਂ ਅਤੇ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕਾਂ \'ਤੇ ਆਧਾਰਿਤ ਤੁਹਾਡਾ ਟਿਕਾਣਾ ਪਤਾ ਕਰ ਸਕਦੀ ਹੈ। ਐਪ ਵੱਲੋਂ ਟਿਕਾਣਾ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕੀਤੇ ਜਾਣ ਦੇ ਯੋਗ ਹੋਣ ਲਈ ਇਹ ਸੇਵਾਵਾਂ ਤੁਹਾਡੇ ਟੈਬਲੈੱਟ \'ਤੇ ਉਪਲਬਧ ਹੋਣੀਆਂ ਅਤੇ ਚਾਲੂ ਕੀਤੀਆਂ ਹੋਣੀਆਂ ਲਾਜ਼ਮੀ ਹਨ।"</string>
+ <string name="permdesc_accessCoarseLocation" product="tv" msgid="1884022719818788511">"ਇਹ ਐਪ ਨੈੱਟਵਰਕ ਸਰੋਤਾਂ ਜਿਵੇਂ ਕਿ ਸੈੱਲ ਟਾਵਰਾਂ ਅਤੇ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕਾਂ \'ਤੇ ਆਧਾਰਿਤ ਤੁਹਾਡਾ ਟਿਕਾਣਾ ਪਤਾ ਕਰ ਸਕਦੀ ਹੈ। ਐਪ ਵੱਲੋਂ ਟਿਕਾਣਾ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕੀਤੇ ਜਾਣ ਦੇ ਯੋਗ ਹੋਣ ਲਈ ਇਹ ਸੇਵਾਵਾਂ ਤੁਹਾਡੇ ਟੀਵੀ \'ਤੇ ਉਪਲਬਧ ਹੋਣੀਆਂ ਅਤੇ ਚਾਲੂ ਕੀਤੀਆਂ ਹੋਣੀਆਂ ਲਾਜ਼ਮੀ ਹਨ।"</string>
+ <string name="permdesc_accessCoarseLocation" product="default" msgid="7788009094906196995">"ਇਹ ਐਪ ਨੈੱਟਵਰਕ ਸਰੋਤਾਂ ਜਿਵੇਂ ਕਿ ਸੈੱਲ ਟਾਵਰਾਂ ਅਤੇ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕਾਂ \'ਤੇ ਆਧਾਰਿਤ ਤੁਹਾਡਾ ਟਿਕਾਣਾ ਪਤਾ ਕਰ ਸਕਦੀ ਹੈ। ਐਪ ਵੱਲੋਂ ਟਿਕਾਣਾ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕੀਤੇ ਜਾਣ ਦੇ ਯੋਗ ਹੋਣ ਲਈ ਇਹ ਸੇਵਾਵਾਂ ਤੁਹਾਡੇ ਫ਼ੋਨ \'ਤੇ ਉਪਲਬਧ ਹੋਣੀਆਂ ਅਤੇ ਚਾਲੂ ਕੀਤੀਆਂ ਹੋਣੀਆਂ ਲਾਜ਼ਮੀ ਹਨ।"</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"ਆਪਣੀਆਂ ਔਡੀਓ ਸੈਟਿੰਗਾਂ ਬਦਲੋ"</string>
<string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"ਔਪ ਨੂੰ ਗਲੋਬਲ ਔਡੀਓ ਸੈਟਿੰਗਾਂ ਸੰਸ਼ੋਧਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ ਜਿਵੇਂ ਵੌਲਿਊਮ ਅਤੇ ਆਊਟਪੁਟ ਲਈ ਕਿਹੜਾ ਸਪੀਕਰ ਵਰਤਿਆ ਜਾਂਦਾ ਹੈ।"</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"ਔਡੀਓ ਰਿਕਾਰਡ ਕਰਨ"</string>
@@ -440,14 +440,14 @@
<string name="permdesc_changeNetworkState" msgid="6789123912476416214">"ਐਪ ਨੂੰ ਨੈੱਟਵਰਕ ਕਨੈਕਟੀਵਿਟੀ ਦੀ ਸਥਿਤੀ ਬਦਲਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
<string name="permlab_changeTetherState" msgid="5952584964373017960">"ਟੀਥਰ ਕੀਤੀ ਕਨੈਕਟੀਵਿਟੀ ਬਦਲੋ"</string>
<string name="permdesc_changeTetherState" msgid="1524441344412319780">"ਐਪ ਨੂੰ ਟੀਥਰ ਕੀਤੀ ਨੈੱਟਵਰਕ ਕਨੈਕਟੀਵਿਟੀ ਦੀ ਸਥਿਤੀ ਬਦਲਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
- <string name="permlab_accessWifiState" msgid="5202012949247040011">"Wi-Fi ਕਨੈਕਸ਼ਨ ਦੇਖੋ"</string>
- <string name="permdesc_accessWifiState" msgid="5002798077387803726">"ਐਪ ਨੂੰ Wi-Fi ਨੈਟਵਰਕਿੰਗ ਬਾਰੇ ਜਾਣਕਾਰੀ ਦੇਖਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ, ਜਿਵੇਂ Wi-Fi ਸਮਰਥਿਤ ਹੈ ਜਾਂ ਨਹੀਂ ਅਤੇ ਕਨੈਕਟ ਕੀਤੀਆਂ Wi-Fi ਡਿਵਾਈਸਾਂ ਦਾ ਨਾਮ।"</string>
- <string name="permlab_changeWifiState" msgid="6550641188749128035">"Wi-Fi ਤੋਂ ਕਨੈਕਟ ਅਤੇ ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
- <string name="permdesc_changeWifiState" msgid="7137950297386127533">"ਐਪ ਨੂੰ ਵਾਈ-ਫਾਈ ਪਹੁੰਚ ਬਿੰਦੂਆਂ ਤੇ ਕਨੈਕਟ ਅਤੇ ਇਹਨਾਂ ਤੋਂ ਡਿਸਕਨੈਕਟ ਕਰਨ ਅਤੇ ਵਾਈ-ਫਾਈ ਨੈਟਵਰਕਾਂ ਲਈ ਡੀਵਾਈਸ ਸੰਰੂਪਣ ਵਿੱਚ ਬਦਲਾਵ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
- <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"Wi-Fi ਮਲਟੀਕਾਸਟ ਰਿਸੈਪਸ਼ਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
- <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"ਐਪ ਨੂੰ ਮਲਟੀਕਾਸਟ ਪਤੇ ਵਰਤਦੇ ਹੋਏ ਇੱਕ Wi-Fi ਨੈੱਟਵਰਕ ਤੇ ਸਾਰੀਆਂ ਡਿਵਾਈਸਾਂ ਤੇ ਭੇਜੇ ਗਏ ਪੈਕੇਟ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ, ਕੇਵਲ ਤੁਹਾਡੀ ਟੈਬਲੇਟ ਨਹੀਂ। ਇਹ ਗ਼ੈਰ-ਮਲਟੀਕਾਸਟ ਮੋਡ ਦੇ ਮੁਕਾਬਲੇ ਵੱਧ ਪਾਵਰ ਵਰਤਦਾ ਹੈ।"</string>
- <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"ਐਪ ਨੂੰ ਮਲਟੀਕਾਸਟ ਪਤੇ ਵਰਤਦੇ ਹੋਏ ਇੱਕ Wi-Fi ਨੈੱਟਵਰਕ ਤੇ ਸਾਰੀਆਂ ਡਿਵਾਈਸਾਂ ਤੇ ਭੇਜੇ ਗਏ ਪੈਕੇਟ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ, ਕੇਵਲ ਤੁਹਾਡਾ TV ਨਹੀਂ। ਇਹ ਗ਼ੈਰ-ਮਲਟੀਕਾਸਟ ਮੋਡ ਦੇ ਮੁਕਾਬਲੇ ਵੱਧ ਪਾਵਰ ਵਰਤਦਾ ਹੈ।"</string>
- <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"ਐਪ ਨੂੰ ਮਲਟੀਕਾਸਟ ਪਤੇ, ਵਰਤਦੇ ਹੋਏ ਇੱਕ Wi-Fi ਨੈੱਟਵਰਕ ਤੇ ਸਾਰੀਆਂ ਡਿਵਾਈਸਾਂ ਤੇ ਭੇਜੇ ਗਏ ਪੈਕੇਟ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ, ਕੇਵਲ ਤੁਹਾਡਾ ਫੋਨ ਨਹੀਂ। ਇਹ ਗ਼ੈਰ-ਮਲਟੀਕਾਸਟ ਮੋਡ ਦੇ ਮੁਕਾਬਲੇ ਵੱਧ ਪਾਵਰ ਵਰਤਦਾ ਹੈ।"</string>
+ <string name="permlab_accessWifiState" msgid="5202012949247040011">"ਵਾਈ-ਫਾਈ ਕਨੈਕਸ਼ਨ ਦੇਖੋ"</string>
+ <string name="permdesc_accessWifiState" msgid="5002798077387803726">"ਐਪ ਨੂੰ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕਿੰਗ ਬਾਰੇ ਜਾਣਕਾਰੀ ਦੇਖਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ, ਜਿਵੇਂ ਵਾਈ-ਫਾਈ ਸਮਰਥਿਤ ਹੈ ਜਾਂ ਨਹੀਂ ਅਤੇ ਕਨੈਕਟ ਕੀਤੇ ਵਾਈ-ਫਾਈ ਡੀਵਾਈਸਾਂ ਦਾ ਨਾਮ।"</string>
+ <string name="permlab_changeWifiState" msgid="6550641188749128035">"ਵਾਈ-ਫਾਈ ਤੋਂ ਕਨੈਕਟ ਅਤੇ ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
+ <string name="permdesc_changeWifiState" msgid="7137950297386127533">"ਐਪ ਨੂੰ ਵਾਈ-ਫਾਈ ਪਹੁੰਚ ਬਿੰਦੂਆਂ ਤੇ ਕਨੈਕਟ ਅਤੇ ਇਹਨਾਂ ਤੋਂ ਡਿਸਕਨੈਕਟ ਕਰਨ ਅਤੇ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕਾਂ ਲਈ ਡੀਵਾਈਸ ਸੰਰੂਪਣ ਵਿੱਚ ਬਦਲਾਵ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
+ <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"ਵਾਈ-ਫਾਈ ਮਲਟੀਕਾਸਟ ਰਿਸੈਪਸ਼ਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
+ <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"ਐਪ ਨੂੰ ਮਲਟੀਕਾਸਟ ਪਤੇ ਵਰਤਦੇ ਹੋਏ ਇੱਕ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਤੇ ਸਾਰੇ ਡੀਵਾਈਸਾਂ ਤੇ ਭੇਜੇ ਗਏ ਪੈਕੇਟ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ, ਸਿਰਫ਼ ਤੁਹਾਡਾ ਟੈਬਲੈੱਟ ਨਹੀਂ। ਇਹ ਗ਼ੈਰ-ਮਲਟੀਕਾਸਟ ਮੋਡ ਦੇ ਮੁਕਾਬਲੇ ਵੱਧ ਪਾਵਰ ਵਰਤਦਾ ਹੈ।"</string>
+ <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"ਐਪ ਨੂੰ ਮਲਟੀਕਾਸਟ ਪਤੇ ਵਰਤਦੇ ਹੋਏ ਇੱਕ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਤੇ ਸਾਰੇ ਡੀਵਾਈਸਾਂ ਤੇ ਭੇਜੇ ਗਏ ਪੈਕੇਟ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ, ਸਿਰਫ਼ ਤੁਹਾਡਾ ਟੀਵੀ ਨਹੀਂ। ਇਹ ਗ਼ੈਰ-ਮਲਟੀਕਾਸਟ ਮੋਡ ਦੇ ਮੁਕਾਬਲੇ ਵੱਧ ਪਾਵਰ ਵਰਤਦਾ ਹੈ।"</string>
+ <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"ਐਪ ਨੂੰ ਮਲਟੀਕਾਸਟ ਪਤੇ, ਵਰਤਦੇ ਹੋਏ ਇੱਕ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਤੇ ਸਾਰੇ ਡੀਵਾਈਸਾਂ ਤੇ ਭੇਜੇ ਗਏ ਪੈਕੇਟ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ, ਸਿਰਫ਼ ਤੁਹਾਡਾ ਫ਼ੋਨ ਨਹੀਂ। ਇਹ ਗ਼ੈਰ-ਮਲਟੀਕਾਸਟ ਮੋਡ ਦੇ ਮੁਕਾਬਲੇ ਵੱਧ ਪਾਵਰ ਵਰਤਦਾ ਹੈ।"</string>
<string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"Bluetooth ਸੈਟਿੰਗਾਂ ਤੱਕ ਪਹੁੰਚ"</string>
<string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"ਐਪ ਨੂੰ ਸਥਾਨਕ Bluetooth ਟੈਬਲੇਟ ਨੂੰ ਕੌਂਫਿਗਰ ਕਰਨ ਅਤੇ ਰਿਮੋਟ ਡਿਵਾਈਸਾਂ ਨੂੰ ਖੋਜਣ ਅਤੇ ਉਹਨਾਂ ਨਾਲ ਪੇਅਰ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
<string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"ਐਪ ਨੂੰ ਸਥਾਨਕ Bluetooth TV ਨੂੰ ਕੌਂਫਿਗਰ ਕਰਨ ਅਤੇ ਰਿਮੋਟ ਡਿਵਾਈਸਾਂ ਨੂੰ ਖੋਜਣ ਅਤੇ ਉਹਨਾਂ ਨਾਲ ਪੇਅਰ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
@@ -705,7 +705,7 @@
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"ਐਮਰਜੈਂਸੀ ਨੰਬਰ"</string>
<string name="lockscreen_carrier_default" msgid="6169005837238288522">"ਕੋਈ ਸੇਵਾ ਨਹੀਂ"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"ਸਕ੍ਰੀਨ ਲੌਕ ਕੀਤੀ।"</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"ਅਨਲੌਕ ਕਰਨ ਲਈ ਮੀਨੂ ਦਬਾਓ ਜਾਂ ਐਮਰਜੈਂਸੀ ਕਾਲ ਕਰੋ।"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"ਅਨਲੌਕ ਕਰਨ ਲਈ ਮੀਨੂ ਦਬਾਓ ਜਾਂ ਸੰਕਟਕਾਲੀਨ ਕਾਲ ਕਰੋ।"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"ਅਨਲੌਕ ਕਰਨ ਲਈ ਮੀਨੂ ਦਬਾਓ।"</string>
<string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"ਅਨਲੌਕ ਕਰਨ ਲਈ ਪੈਟਰਨ ਡ੍ਰਾ ਕਰੋ"</string>
<string name="lockscreen_emergency_call" msgid="5298642613417801888">"ਸੰਕਟਕਾਲ"</string>
@@ -827,17 +827,17 @@
<string name="autofill_area" msgid="3547409050889952423">"ਖੇਤਰ"</string>
<string name="autofill_emirate" msgid="2893880978835698818">"ਅਮੀਰਾਤ"</string>
<string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"ਆਪਣੇ ਵੈੱਬ ਬੁੱਕਮਾਰਕ ਅਤੇ ਇਤਿਹਾਸ ਪੜ੍ਹੋ"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"ਐਪ ਨੂੰ ਸਾਰੇ URL ਜਿਨ੍ਹਾਂ ਤੇ ਬ੍ਰਾਊਜ਼ਰ ਨੇ ਵਿਜਿਟ ਕੀਤਾ ਹੈ ਅਤੇ ਬ੍ਰਾਊਜ਼ਰ ਦੇ ਸਾਰੇ ਬੁੱਕਮਾਰਕਾਂ ਦਾ ਇਤਿਹਾਸ ਪੜ੍ਹਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਨੋਟ: ਇਹ ਅਨੁਮਤੀ ਤੀਜੀ-ਪਾਰਟੀ ਬ੍ਰਾਊਜ਼ਰਾਂ ਜਾਂ ਵੈੱਬ ਬ੍ਰਾਊਜ਼ਿੰਗ ਸਮਰੱਥਾ ਵਾਲੀਆਂ ਹੋਰਾਂ ਐਪਲੀਕੇਸ਼ਨਾਂ ਵੱਲੋਂ ਲਾਗੂ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।"</string>
+ <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"ਐਪ ਨੂੰ ਸਾਰੇ URL ਜਿਨ੍ਹਾਂ \'ਤੇ ਬ੍ਰਾਊਜ਼ਰ ਨੇ ਵਿਜਿਟ ਕੀਤਾ ਹੈ ਅਤੇ ਬ੍ਰਾਊਜ਼ਰ ਦੇ ਸਾਰੇ ਬੁੱਕਮਾਰਕਾਂ ਦਾ ਇਤਿਹਾਸ ਪੜ੍ਹਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਨੋਟ: ਇਹ ਇਜਾਜ਼ਤ ਤੀਜੀ-ਪਾਰਟੀ ਬ੍ਰਾਊਜ਼ਰਾਂ ਜਾਂ ਵੈੱਬ ਬ੍ਰਾਊਜ਼ਿੰਗ ਸਮਰੱਥਾ ਵਾਲੀਆਂ ਹੋਰਾਂ ਐਪਲੀਕੇਸ਼ਨਾਂ ਵੱਲੋਂ ਲਾਗੂ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।"</string>
<string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"ਵੈੱਬ ਬੁੱਕਮਾਰਕ ਅਤੇ ਇਤਿਹਾਸ ਲਿਖੋ"</string>
- <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"ਐਪ ਨੂੰ ਬ੍ਰਾਊਜ਼ਰ ਦਾ ਇਤਿਹਾਸ ਅਤੇ ਤੁਹਾਡੇ ਟੈਬਲੈੱਟ ਤੇ ਸਟੋਰ ਕੀਤੇ ਬੁੱਕਮਾਰਕਾਂ ਨੂੰ ਸੰਸ਼ੋਧਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਐਪ ਨੂੰ ਬ੍ਰਾਊਜ਼ਰ ਡਾਟਾ ਮਿਟਾਉਣ ਜਾਂ ਸੰਸ਼ੋਧਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇ ਸਕਦਾ ਹੈ। ਨੋਟ: ਇਹ ਅਨੁਮਤੀ ਤੀਜੀ-ਪਾਰਟੀ ਬ੍ਰਾਊਜ਼ਰਾਂ ਜਾਂ ਵੈੱਬ ਬ੍ਰਾਊਜ਼ਿੰਗ ਸਮਰੱਥਾ ਵਾਲੀਆਂ ਹੋਰਾਂ ਐਪਲੀਕੇਸ਼ਨਾਂ ਵੱਲੋਂ ਲਾਗੂ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।"</string>
- <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"ਐਪ ਨੂੰ ਬ੍ਰਾਊਜ਼ਰ ਦਾ ਇਤਿਹਾਸ ਅਤੇ ਤੁਹਾਡੇ TV ਤੇ ਸਟੋਰ ਕੀਤੇ ਬੁੱਕਮਾਰਕਾਂ ਨੂੰ ਸੰਸ਼ੋਧਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਐਪ ਨੂੰ ਬ੍ਰਾਊਜ਼ਰ ਡਾਟਾ ਮਿਟਾਉਣ ਜਾਂ ਸੰਸ਼ੋਧਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇ ਸਕਦਾ ਹੈ। ਨੋਟ: ਇਹ ਅਨੁਮਤੀ ਤੀਜੀ-ਪਾਰਟੀ ਬ੍ਰਾਊਜ਼ਰਾਂ ਜਾਂ ਵੈੱਬ ਬ੍ਰਾਊਜ਼ਿੰਗ ਸਮਰੱਥਾ ਵਾਲੀਆਂ ਹੋਰਾਂ ਐਪਲੀਕੇਸ਼ਨਾਂ ਵੱਲੋਂ ਲਾਗੂ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।"</string>
- <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"ਐਪ ਨੂੰ ਬ੍ਰਾਊਜ਼ਰ ਦਾ ਇਤਿਹਾਸ ਅਤੇ ਤੁਹਾਡੇ ਫ਼ੋਨ ਤੇ ਸਟੋਰ ਕੀਤੇ ਬੁੱਕਮਾਰਕਾਂ ਨੂੰ ਸੰਸ਼ੋਧਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਐਪ ਨੂੰ ਬ੍ਰਾਊਜ਼ਰ ਡਾਟਾ ਮਿਟਾਉਣ ਜਾਂ ਸੰਸ਼ੋਧਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇ ਸਕਦਾ ਹੈ। ਨੋਟ: ਇਹ ਅਨੁਮਤੀ ਤੀਜੀ-ਪਾਰਟੀ ਬ੍ਰਾਊਜ਼ਰਾਂ ਜਾਂ ਵੈੱਬ ਬ੍ਰਾਊਜ਼ਿੰਗ ਸਮਰੱਥਾ ਵਾਲੀਆਂ ਹੋਰਾਂ ਐਪਲੀਕੇਸ਼ਨਾਂ ਵੱਲੋਂ ਲਾਗੂ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।"</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"ਐਪ ਨੂੰ ਬ੍ਰਾਊਜ਼ਰ ਦਾ ਇਤਿਹਾਸ ਅਤੇ ਤੁਹਾਡੇ ਟੈਬਲੈੱਟ \'ਤੇ ਸਟੋਰ ਕੀਤੇ ਬੁੱਕਮਾਰਕਾਂ ਨੂੰ ਸੰਸ਼ੋਧਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਐਪ ਨੂੰ ਬ੍ਰਾਊਜ਼ਰ ਡਾਟਾ ਸਾਫ਼ ਕਰਨ ਜਾਂ ਸੰਸ਼ੋਧਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇ ਸਕਦਾ ਹੈ। ਨੋਟ: ਇਹ ਇਜਾਜ਼ਤ ਤੀਜੀ-ਪਾਰਟੀ ਬ੍ਰਾਊਜ਼ਰਾਂ ਜਾਂ ਵੈੱਬ ਬ੍ਰਾਊਜ਼ਿੰਗ ਸਮਰੱਥਾ ਵਾਲੀਆਂ ਹੋਰਾਂ ਐਪਲੀਕੇਸ਼ਨਾਂ ਵੱਲੋਂ ਲਾਗੂ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।"</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"ਐਪ ਨੂੰ ਬ੍ਰਾਊਜ਼ਰ ਦਾ ਇਤਿਹਾਸ ਅਤੇ ਤੁਹਾਡੇ TV \'ਤੇ ਸਟੋਰ ਕੀਤੇ ਬੁੱਕਮਾਰਕਾਂ ਨੂੰ ਸੰਸ਼ੋਧਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਐਪ ਨੂੰ ਬ੍ਰਾਊਜ਼ਰ ਡਾਟਾ ਸਾਫ਼ ਕਰਨ ਜਾਂ ਸੰਸ਼ੋਧਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇ ਸਕਦਾ ਹੈ। ਨੋਟ: ਇਹ ਇਜਾਜ਼ਤ ਤੀਜੀ-ਪਾਰਟੀ ਬ੍ਰਾਊਜ਼ਰਾਂ ਜਾਂ ਵੈੱਬ ਬ੍ਰਾਊਜ਼ਿੰਗ ਸਮਰੱਥਾ ਵਾਲੀਆਂ ਹੋਰਾਂ ਐਪਲੀਕੇਸ਼ਨਾਂ ਵੱਲੋਂ ਲਾਗੂ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।"</string>
+ <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"ਐਪ ਨੂੰ ਬ੍ਰਾਊਜ਼ਰ ਦਾ ਇਤਿਹਾਸ ਅਤੇ ਤੁਹਾਡੇ ਫ਼ੋਨ \'ਤੇ ਸਟੋਰ ਕੀਤੇ ਬੁੱਕਮਾਰਕਾਂ ਨੂੰ ਸੰਸ਼ੋਧਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਐਪ ਨੂੰ ਬ੍ਰਾਊਜ਼ਰ ਡਾਟਾ ਸਾਫ਼ ਕਰਨ ਜਾਂ ਸੰਸ਼ੋਧਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦੇ ਸਕਦਾ ਹੈ। ਨੋਟ: ਇਹ ਇਜਾਜ਼ਤ ਤੀਜੀ-ਪਾਰਟੀ ਬ੍ਰਾਊਜ਼ਰਾਂ ਜਾਂ ਵੈੱਬ ਬ੍ਰਾਊਜ਼ਿੰਗ ਸਮਰੱਥਾ ਵਾਲੀਆਂ ਹੋਰਾਂ ਐਪਲੀਕੇਸ਼ਨਾਂ ਵੱਲੋਂ ਲਾਗੂ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।"</string>
<string name="permlab_setAlarm" msgid="1379294556362091814">"ਇੱਕ ਅਲਾਰਮ ਸੈੱਟ ਕਰੋ"</string>
<string name="permdesc_setAlarm" msgid="316392039157473848">"ਐਪ ਨੂੰ ਇੱਕ ਇੰਸਟੌਲ ਕੀਤੀ ਅਲਾਰਮ ਘੜੀ ਐਪ ਵਿੱਚ ਇੱਕ ਅਲਾਰਮ ਸੈਟ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਕੁਝ ਅਲਾਰਮ ਘੜੀ ਐਪਲ ਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਲਾਗੂ ਨਹੀਂ ਵੀ ਕਰ ਸਕਦੇ।"</string>
<string name="permlab_addVoicemail" msgid="5525660026090959044">"ਵੌਇਸਮੇਲ ਜੋੜੋ"</string>
<string name="permdesc_addVoicemail" msgid="6604508651428252437">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਵੌਇਸਮੇਲ ਇਨਬੌਕਸ ਵਿੱਚ ਸੁਨੇਹੇ ਜੋੜਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
<string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"ਬ੍ਰਾਊਜ਼ਰ ਜਿਓਲੋਕੇਸ਼ਨ ਅਨੁਮਤੀਆਂ ਸੰਸ਼ੋਧਿਤ ਕਰੋ"</string>
- <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"ਐਪ ਨੂੰ ਬ੍ਰਾਊਜ਼ਰ ਦੀਆਂ ਜਿਓਲੋਕੇਸ਼ਨ ਅਨੁਮਤੀਆਂ ਸੰਸ਼ੋਧਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਖ਼ਰਾਬ ਐਪਾਂ ਇਸਦੀ ਵਰਤੋਂ ਆਰਬਿਟਰੇਰੀ ਵੈੱਬ ਸਾਈਟਾਂ ਨੂੰ ਟਿਕਾਣਾ ਜਾਣਕਾਰੀ ਭੇਜਣ ਦੀ ਆਗਿਆ ਦੇਣ ਲਈ ਕਰ ਸਕਦੀਆਂ ਹਨ।"</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"ਐਪ ਨੂੰ ਬ੍ਰਾਊਜ਼ਰ ਦੀਆਂ ਜਿਓਲੋਕੇਸ਼ਨ ਇਜਾਜ਼ਤਾਂ ਸੰਸ਼ੋਧਿਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਖਰਾਬ ਐਪਾਂ ਇਸਦੀ ਵਰਤੋਂ ਆਰਬਿਟਰੇਰੀ ਵੈੱਬ ਸਾਈਟਾਂ ਨੂੰ ਟਿਕਾਣਾ ਜਾਣਕਾਰੀ ਭੇਜਣ ਦੀ ਆਗਿਆ ਦੇਣ ਲਈ ਕਰ ਸਕਦੀਆਂ ਹਨ।"</string>
<string name="save_password_message" msgid="767344687139195790">"ਕੀ ਤੁਸੀਂ ਚਾਹੁੰਦੇ ਹੋ ਕਿ ਬ੍ਰਾਊਜ਼ਰ ਇਹ ਪਾਸਵਰਡ ਯਾਦ ਰੱਖੇ?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"ਅਜੇ ਨਹੀਂ"</string>
<string name="save_password_remember" msgid="6491879678996749466">"ਯਾਦ ਰੱਖੋ"</string>
@@ -1094,46 +1094,46 @@
<string name="ringtone_picker_title_notification" msgid="4837740874822788802">"ਸੂਚਨਾ ਧੁਨੀਆਂ"</string>
<string name="ringtone_unknown" msgid="3914515995813061520">"ਅਗਿਆਤ"</string>
<plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
- <item quantity="one">Wi-Fi ਨੈੱਟਵਰਕਸ ਉਪਲਬਧ</item>
- <item quantity="other">Wi-Fi ਨੈੱਟਵਰਕਸ ਉਪਲਬਧ</item>
+ <item quantity="one">ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਉਪਲਬਧ</item>
+ <item quantity="other">ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਉਪਲਬਧ</item>
</plurals>
<plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
- <item quantity="one">ਉਪਲਬਧ Wi-Fi ਨੈੱਟਵਰਕ ਖੋਲ੍ਹੋ</item>
- <item quantity="other">ਉਪਲਬਧ Wi-Fi ਨੈੱਟਵਰਕ ਖੋਲ੍ਹੋ</item>
+ <item quantity="one">ਉਪਲਬਧ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਖੋਲ੍ਹੋ</item>
+ <item quantity="other">ਉਪਲਬਧ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਖੋਲ੍ਹੋ</item>
</plurals>
- <string name="wifi_available_title" msgid="3817100557900599505">"ਖੁੱਲ੍ਹੇ Wi‑Fi ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਹੋਵੋ"</string>
- <string name="wifi_available_title_connecting" msgid="1557292688310330032">"ਖੁੱਲ੍ਹੇ Wi‑Fi ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
- <string name="wifi_available_title_connected" msgid="7542672851522241548">"Wi‑Fi ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
- <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Wi‑Fi ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ"</string>
+ <string name="wifi_available_title" msgid="3817100557900599505">"ਖੁੱਲ੍ਹੇ ਵਾਈ‑ਫਾਈ ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਹੋਵੋ"</string>
+ <string name="wifi_available_title_connecting" msgid="1557292688310330032">"ਖੁੱਲ੍ਹੇ ਵਾਈ‑ਫਾਈ ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
+ <string name="wifi_available_title_connected" msgid="7542672851522241548">"ਵਾਈ‑ਫਾਈ ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
+ <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"ਵਾਈ‑ਫਾਈ ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ"</string>
<string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"ਸਾਰੇ ਨੈੱਟਵਰਕਾਂ ਨੂੰ ਦੇਖਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="wifi_available_action_connect" msgid="2635699628459488788">"ਕਨੈਕਟ ਕਰੋ"</string>
<string name="wifi_available_action_all_networks" msgid="1100098935861622985">"ਸਾਰੇ ਨੈੱਟਵਰਕ"</string>
- <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi ਨੈੱਟਵਰਕ ਵਿੱਚ ਸਾਈਨ ਇਨ ਕਰੋ"</string>
+ <string name="wifi_available_sign_in" msgid="9157196203958866662">"ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਵਿੱਚ ਸਾਈਨ-ਇਨ ਕਰੋ"</string>
<string name="network_available_sign_in" msgid="1848877297365446605">"ਨੈੱਟਵਰਕ ਤੇ ਸਾਈਨ ਇਨ ਕਰੋ"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi ਦੀ ਕੋਈ ਇੰਟਰਨੈਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
+ <string name="wifi_no_internet" msgid="8451173622563841546">"ਵਾਈ-ਫਾਈ ਦੀ ਕੋਈ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ਵਿਕਲਪਾਂ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"ਬਦਲਕੇ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ਲਿਆਂਦਾ ਗਿਆ"</string>
<string name="network_switch_metered_detail" msgid="5325661434777870353">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ਦੀ ਇੰਟਰਨੈੱਟ \'ਤੇ ਪਹੁੰਚ ਨਾ ਹੋਣ \'ਤੇ ਡੀਵਾਈਸ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹੈ। ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ।"</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ਤੋਂ ਬਦਲਕੇ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> \'ਤੇ ਕੀਤਾ ਗਿਆ"</string>
<string-array name="network_switch_type_name">
- <item msgid="3979506840912951943">"ਮੋਬਾਈਲ ਡੈਟਾ"</item>
- <item msgid="75483255295529161">"Wi-Fi"</item>
+ <item msgid="3979506840912951943">"ਮੋਬਾਈਲ ਡਾਟਾ"</item>
+ <item msgid="75483255295529161">"ਵਾਈ-ਫਾਈ"</item>
<item msgid="6862614801537202646">"ਬਲੂਟੁੱਥ"</item>
<item msgid="5447331121797802871">"ਈਥਰਨੈੱਟ"</item>
<item msgid="8257233890381651999">"VPN"</item>
</string-array>
<string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ਇੱਕ ਅਗਿਆਤ ਨੈੱਟਵਰਕ ਕਿਸਮ"</string>
- <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਕਰ ਸਕਿਆ"</string>
+ <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ਵਾਈ-ਫਾਈ ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਹੋ ਸਕਿਆ"</string>
<string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ਇਸਦਾ ਇੱਕ ਖ਼ਰਾਬ ਇੰਟਰਨੈਟ ਕਨੈਕਸ਼ਨ ਹੈ।"</string>
<string name="wifi_connect_alert_title" msgid="8455846016001810172">"ਕੀ ਕਨੈਕਸ਼ਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
- <string name="wifi_connect_alert_message" msgid="6451273376815958922">"ਐਪਲੀਕੇਸ਼ਨ %1$s Wifi ਨੈੱਟਵਰਕ %2$s ਨਾਲ ਕਨੈਕਟ ਕਰਨਾ ਚਾਹੁੰਦਾ ਹੈ"</string>
+ <string name="wifi_connect_alert_message" msgid="6451273376815958922">"ਐਪਲੀਕੇਸ਼ਨ %1$s ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ %2$s ਨਾਲ ਕਨੈਕਟ ਕਰਨਾ ਚਾਹੁੰਦੀ ਹੈ"</string>
<string name="wifi_connect_default_application" msgid="7143109390475484319">"ਇੱਕ ਐਪਲੀਕੇਸ਼ਨ"</string>
- <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi ਡਾਇਰੈਕਟ"</string>
- <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi ਡਾਇਰੈਕਟ ਚਾਲੂ ਕਰੋ। ਇਹ Wi-Fi ਕਲਾਈਂਟ/ਹੌਟਸਪੌਟ ਨੂੰ ਬੰਦ ਕਰ ਦੇਵੇਗਾ।"</string>
- <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi ਡਾਇਰੈਕਟ ਚਾਲੂ ਨਹੀਂ ਕਰ ਸਕਿਆ।"</string>
- <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi ਡਾਇਰੈਕਟ ਚਾਲੂ ਹੈ।"</string>
+ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"ਵਾਈ-ਫਾਈ ਡਾਇਰੈਕਟ"</string>
+ <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ਵਾਈ-ਫਾਈ ਡਾਇਰੈਕਟ ਚਾਲੂ ਕਰੋ। ਇਹ ਵਾਈ-ਫਾਈ ਕਲਾਈਂਟ/ਹੌਟਸਪੌਟ ਨੂੰ ਬੰਦ ਕਰ ਦੇਵੇਗਾ।"</string>
+ <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"ਵਾਈ-ਫਾਈ ਡਾਇਰੈਕਟ ਚਾਲੂ ਨਹੀਂ ਹੋ ਸਕਿਆ।"</string>
+ <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"ਵਾਈ-ਫਾਈ ਡਾਇਰੈਕਟ ਚਾਲੂ ਹੈ।"</string>
<string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"ਸੈਟਿੰਗਾਂ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="accept" msgid="1645267259272829559">"ਸਵੀਕਾਰ ਕਰੋ"</string>
<string name="decline" msgid="2112225451706137894">"ਅਸਵੀਕਾਰ ਕਰੋ"</string>
@@ -1143,15 +1143,15 @@
<string name="wifi_p2p_to_message" msgid="248968974522044099">"ਵੱਲ:"</string>
<string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"ਲੋੜੀਂਦਾ ਪਿੰਨ ਟਾਈਪ ਕਰੋ:"</string>
<string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"ਪਿੰਨ:"</string>
- <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"ਟੈਬਲੇਟ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤੇ ਜਾਣ ਤੇ Wi-Fi ਤੋਂ ਅਸਥਾਈ ਤੌਰ ਤੇ ਡਿਸਕਨੈਕਟ ਹੋ ਜਾਏਗੀ"</string>
- <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="3087858235069421128">"TV <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤੇ ਜਾਣ ਤੇ Wi-Fi ਤੋਂ ਅਸਥਾਈ ਤੌਰ ਤੇ ਡਿਸਕਨੈਕਟ ਹੋ ਜਾਏਗਾ"</string>
- <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"ਫੋਨ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤੇ ਜਾਣ ਤੇ Wi-Fi ਤੋਂ ਅਸਥਾਈ ਤੌਰ ਤੇ ਡਿਸਕਨੈਕਟ ਹੋ ਜਾਏਗਾ"</string>
+ <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"ਟੈਬਲੈੱਟ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤੇ ਜਾਣ ਤੇ ਵਾਈ-ਫਾਈ ਤੋਂ ਅਸਥਾਈ ਤੌਰ ਤੇ ਡਿਸਕਨੈਕਟ ਹੋ ਜਾਏਗਾ"</string>
+ <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="3087858235069421128">"TV <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤੇ ਜਾਣ ਤੇ ਵਾਈ-ਫਾਈ ਤੋਂ ਅਸਥਾਈ ਤੌਰ ਤੇ ਡਿਸਕਨੈਕਟ ਹੋ ਜਾਏਗਾ"</string>
+ <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"ਫ਼ੋਨ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤੇ ਜਾਣ ਤੇ ਵਾਈ-ਫਾਈ ਤੋਂ ਅਸਥਾਈ ਤੌਰ ਤੇ ਡਿਸਕਨੈਕਟ ਹੋ ਜਾਏਗਾ"</string>
<string name="select_character" msgid="3365550120617701745">"ਅੱਖਰ ਦਾਖਲ ਕਰੋ"</string>
<string name="sms_control_title" msgid="7296612781128917719">"SMS ਸੁਨੇਹੇ ਭੇਜ ਰਿਹਾ ਹੈ"</string>
<string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਵੱਡੀ ਸੰਖਿਆ ਵਿੱਚ SMS ਸੁਨੇਹੇ ਭੇਜ ਰਿਹਾ ਹੈ। ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਸੁਨੇਹੇ ਭੇਜਣਾ ਜਾਰੀ ਰੱਖਣ ਦੀ ਆਗਿਆ ਦੇਣਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
<string name="sms_control_yes" msgid="3663725993855816807">"ਆਗਿਆ ਦਿਓ"</string>
<string name="sms_control_no" msgid="625438561395534982">"ਅਸਵੀਕਾਰ ਕਰੋ"</string>
- <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਇਹ &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt; ਨੂੰ ਇੱਕ ਸੁਨੇਹਾ ਭੇਜਣਾ ਚਾਹੁੰਦਾ ਹੈ।"</string>
+ <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਇਹ &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt; ਨੂੰ ਇੱਕ ਸੁਨੇਹਾ ਭੇਜਣਾ ਚਾਹੁੰਦੀ ਹੈ।"</string>
<string name="sms_short_code_details" msgid="5873295990846059400">"ਇਸ ਨਾਲ "<b>"ਤੁਹਾਡੇ ਮੋਬਾਈਲ ਖਾਤੇ ਤੇ ਖ਼ਰਚੇ"</b>" ਪੈ ਸਕਦੇ ਹਨ।"</string>
<string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"ਇਸ ਨਾਲ ਤੁਹਾਡੇ ਮੋਬਾਈਲ ਖਾਤੇ ਤੇ ਖ਼ਰਚੇ ਪੈਣਗੇ।"</b></string>
<string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"ਭੇਜੋ"</string>
@@ -1384,13 +1384,13 @@
<string name="data_usage_warning_body" msgid="6660692274311972007">"ਵਰਤੋਂ ਅਤੇ ਸੈਟਿੰਗਾਂ ਨੂੰ ਵੇਖਣ ਲਈ ਟੈਪ ਕਰੋ।"</string>
<string name="data_usage_3g_limit_title" msgid="4361523876818447683">"2G-3G ਡੈਟਾ ਸੀਮਾ ਪੂਰੀ ਹੋ ਗਈ"</string>
<string name="data_usage_4g_limit_title" msgid="4609566827219442376">"4G ਡੈਟਾ ਸੀਮਾ ਪੂਰੀ ਹੋਈ"</string>
- <string name="data_usage_mobile_limit_title" msgid="6561099244084267376">"ਮੋਬਾਈਲ ਡੈਟਾ ਸੀਮਾ ਸਮਾਪਤ ਹੋਈ"</string>
- <string name="data_usage_wifi_limit_title" msgid="5803363779034792676">"Wi-Fi ਡੈਟਾ ਸੀਮਾ ਪੂਰੀ ਹੋ ਗਈ"</string>
+ <string name="data_usage_mobile_limit_title" msgid="6561099244084267376">"ਮੋਬਾਈਲ ਡਾਟਾ ਸੀਮਾ ਸਮਾਪਤ ਹੋਈ"</string>
+ <string name="data_usage_wifi_limit_title" msgid="5803363779034792676">"ਵਾਈ-ਫਾਈ ਡਾਟਾ ਸੀਮਾ ਪੂਰੀ ਹੋ ਗਈ"</string>
<string name="data_usage_limit_body" msgid="291731708279614081">"ਬਾਕੀ ਸਾਇਕਲ ਲਈ ਡੈਟਾ ਰੁਕ ਗਿਆ"</string>
<string name="data_usage_3g_limit_snoozed_title" msgid="7026739121138005231">"2G-3G ਡੈਟਾ ਸੀਮਾ ਵਧ ਗਈ"</string>
<string name="data_usage_4g_limit_snoozed_title" msgid="1106562779311209039">"4G ਡੈਟਾ ਸੀਮਾ ਵਧੀ"</string>
- <string name="data_usage_mobile_limit_snoozed_title" msgid="279240572165412168">"ਮੋਬਾਈਲ ਡੈਟਾ ਦੀ ਸੀਮਾ ਵਧ ਗਈ"</string>
- <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Wi-Fi ਡੈਟਾ ਸੀਮਾ ਵਧ ਗਈ"</string>
+ <string name="data_usage_mobile_limit_snoozed_title" msgid="279240572165412168">"ਮੋਬਾਈਲ ਡਾਟਾ ਦੀ ਸੀਮਾ ਵਧ ਗਈ"</string>
+ <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"ਵਾਈ-ਫਾਈ ਡਾਟਾ ਸੀਮਾ ਵਧ ਗਈ"</string>
<string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> ਤੋਂ ਵੱਧ ਨਿਰਦਿਸ਼ਟ ਸੀਮਾ।"</string>
<string name="data_usage_restricted_title" msgid="5965157361036321914">"ਪਿਛੋਕੜ ਡੈਟਾ ਪ੍ਰਤਿਬੰਧਿਤ"</string>
<string name="data_usage_restricted_body" msgid="469866376337242726">"ਪਾਬੰੰਦੀ ਹਟਾਉਣ ਲਈ ਟੈਪ ਕਰੋ।"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 397fd22140fd..685622a99fdd 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -150,7 +150,7 @@
<string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"ప్రోటోకాల్‌కి మద్దతు లేదు."</string>
<string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"సురక్షిత కనెక్షన్‌ను వ్యవస్థాపించడం సాధ్యపడలేదు."</string>
<string name="httpErrorBadUrl" msgid="3636929722728881972">"URL చెల్లనిది అయినందువలన పేజీని తెరవడం సాధ్యపడలేదు."</string>
- <string name="httpErrorFile" msgid="2170788515052558676">"ఫైల్‌ను ప్రాప్యత చేయడం సాధ్యపడలేదు."</string>
+ <string name="httpErrorFile" msgid="2170788515052558676">"ఫైల్‌ను యాక్సెస్ చేయడం సాధ్యపడలేదు."</string>
<string name="httpErrorFileNotFound" msgid="6203856612042655084">"అభ్యర్థించిన ఫైల్‌ను కనుగొనడం సాధ్యపడలేదు."</string>
<string name="httpErrorTooManyRequests" msgid="1235396927087188253">"చాలా ఎక్కువ అభ్యర్థనలు ప్రాసెస్ చేయబడుతున్నాయి. తర్వాత మళ్లీ ప్రయత్నించండి."</string>
<string name="notification_title" msgid="8967710025036163822">"<xliff:g id="ACCOUNT">%1$s</xliff:g>కు సైన్‌ఇన్ ఎర్రర్"</string>
@@ -258,20 +258,20 @@
<string name="user_owner_label" msgid="1119010402169916617">"వ్యక్తిగతానికి మార్చు"</string>
<string name="managed_profile_label" msgid="5289992269827577857">"కార్యాలయానికి మార్చు"</string>
<string name="permgrouplab_contacts" msgid="3657758145679177612">"పరిచయాలు"</string>
- <string name="permgroupdesc_contacts" msgid="6951499528303668046">"మీ పరిచయాలను ప్రాప్యత చేయడానికి"</string>
- <string name="permgrouprequest_contacts" msgid="1601591667800538208">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ని ఉపయోగించి, మీ పరిచయాలను ప్రాప్యత చేయండి"</string>
+ <string name="permgroupdesc_contacts" msgid="6951499528303668046">"మీ పరిచయాలను యాక్సెస్ చేయడానికి"</string>
+ <string name="permgrouprequest_contacts" msgid="1601591667800538208">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ని ఉపయోగించి, మీ పరిచయాలను యాక్సెస్ చేయండి"</string>
<string name="permgrouplab_location" msgid="7275582855722310164">"స్థానం"</string>
- <string name="permgroupdesc_location" msgid="1346617465127855033">"ఈ పరికర స్థానాన్ని ప్రాప్యత చేయడానికి"</string>
- <string name="permgrouprequest_location" msgid="8903573681261610809">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ని ఉపయోగించి, ఈ పరికరం యొక్క స్థానాన్ని ప్రాప్యత చేయండి"</string>
+ <string name="permgroupdesc_location" msgid="1346617465127855033">"ఈ పరికర స్థానాన్ని యాక్సెస్ చేయడానికి"</string>
+ <string name="permgrouprequest_location" msgid="8903573681261610809">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ని ఉపయోగించి, ఈ పరికరం యొక్క స్థానాన్ని యాక్సెస్ చేయండి"</string>
<string name="permgrouplab_calendar" msgid="5863508437783683902">"క్యాలెండర్"</string>
- <string name="permgroupdesc_calendar" msgid="3889615280211184106">"మీ క్యాలెండర్‌ను ప్రాప్యత చేయడానికి"</string>
- <string name="permgrouprequest_calendar" msgid="6704529828699071445">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ని ఉపయోగించి, మీ క్యాలెండర్‌ను ప్రాప్యత చేయండి"</string>
+ <string name="permgroupdesc_calendar" msgid="3889615280211184106">"మీ క్యాలెండర్‌ను యాక్సెస్ చేయడానికి"</string>
+ <string name="permgrouprequest_calendar" msgid="6704529828699071445">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ని ఉపయోగించి, మీ క్యాలెండర్‌ను యాక్సెస్ చేయండి"</string>
<string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
<string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS సందేశాలను పంపడం మరియు వీక్షించడం"</string>
<string name="permgrouprequest_sms" msgid="605618939583628306">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ని ఉపయోగించి, SMS సందేశాలను పంపండి మరియు వీక్షించండి"</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"నిల్వ"</string>
- <string name="permgroupdesc_storage" msgid="637758554581589203">"మీ పరికరంలోని ఫోటోలు, మీడియా మరియు ఫైల్‌లను ప్రాప్యత చేయడానికి"</string>
- <string name="permgrouprequest_storage" msgid="7429669910547860218">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ని ఉపయోగించి, మీ పరికరంలో ఫోటోలు, మీడియా మరియు ఫైల్‌లను ప్రాప్యత చేయండి"</string>
+ <string name="permgroupdesc_storage" msgid="637758554581589203">"మీ పరికరంలోని ఫోటోలు, మీడియా మరియు ఫైల్‌లను యాక్సెస్ చేయడానికి"</string>
+ <string name="permgrouprequest_storage" msgid="7429669910547860218">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ని ఉపయోగించి, మీ పరికరంలో ఫోటోలు, మీడియా మరియు ఫైల్‌లను యాక్సెస్ చేయండి"</string>
<string name="permgrouplab_microphone" msgid="171539900250043464">"మైక్రోఫోన్"</string>
<string name="permgroupdesc_microphone" msgid="4988812113943554584">"ఆడియోను రికార్డ్ చేయడానికి"</string>
<string name="permgrouprequest_microphone" msgid="8065941268709600606">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ని ఉపయోగించి, ఆడియోని రికార్డ్ చేయండి"</string>
@@ -282,8 +282,8 @@
<string name="permgroupdesc_phone" msgid="6234224354060641055">"ఫోన్ కాల్‌లు చేయడం మరియు నిర్వహించడం"</string>
<string name="permgrouprequest_phone" msgid="7084161459732093690">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ని ఉపయోగించి, ఫోన్ కాల్‌లను చేయండి మరియు నిర్వహించండి"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"శరీర సెన్సార్‌లు"</string>
- <string name="permgroupdesc_sensors" msgid="7147968539346634043">"మీ అత్యంత కీలకమైన గుర్తుల గురించి సెన్సార్ డేటాని ప్రాప్యత చేస్తుంది"</string>
- <string name="permgrouprequest_sensors" msgid="8631146669524259656">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ని ఉపయోగించి, మీ అత్యంత కీలకమైన గుర్తుల గురించి సెన్సార్ డేటాని ప్రాప్యత చేయండి"</string>
+ <string name="permgroupdesc_sensors" msgid="7147968539346634043">"మీ అత్యంత కీలకమైన గుర్తుల గురించి సెన్సార్ డేటాని యాక్సెస్ చేస్తుంది"</string>
+ <string name="permgrouprequest_sensors" msgid="8631146669524259656">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ని ఉపయోగించి, మీ అత్యంత కీలకమైన గుర్తుల గురించి సెన్సార్ డేటాని యాక్సెస్ చేయండి"</string>
<string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"విండో కంటెంట్‍ను తిరిగి పొందుతుంది"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"మీరు పరస్పర చర్య చేస్తున్న విండో కంటెంట్‌‍ను పరిశీలిస్తుంది."</string>
<string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"తాకడం ద్వారా విశ్లేషణను ప్రారంభిస్తుంది"</string>
@@ -372,8 +372,8 @@
<string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"ఇన్‌కమింగ్ మరియు అవుట్‌గోయింగ్ కాల్‌ల గురించిన డేటాతో సహా మీ టాబ్లెట్ యొక్క కాల్ లాగ్‌ను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. హానికరమైన యాప్‌లు మీ కాల్ లాగ్‌ను ఎరేజ్ చేయడానికి లేదా సవరించడానికి దీన్ని ఉపయోగించవచ్చు."</string>
<string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"ఇన్‌కమింగ్ మరియు అవుట్‌గోయింగ్ కాల్‌లకు సంబంధించిన డేటాతో సహా మీ టీవీ కాల్ లాగ్‌ను సవరించడానికి అనువర్తనాన్ని అనుమతిస్తుంది. హానికరమైన అనువర్తనాలు మీ కాల్ లాగ్‌ను తీసివేయడానికి లేదా సవరించడానికి దీన్ని ఉపయోగించవచ్చు."</string>
<string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"ఇన్‌కమింగ్ మరియు అవుట్‌గోయింగ్ కాల్‌ల గురించిన డేటాతో సహా మీ ఫోన్ యొక్క కాల్ లాగ్‌ను సవరించడానికి యాప్‌ను అనుమతిస్తుంది. హానికరమైన యాప్‌లు మీ కాల్ లాగ్‌ను ఎరేజ్ చేయడానికి లేదా సవరించడానికి దీన్ని ఉపయోగించవచ్చు."</string>
- <string name="permlab_bodySensors" msgid="4683341291818520277">"శరీర సెన్సార్‌లను (గుండె స్పందన రేటు మానిటర్‌ల వంటివి) ప్రాప్యత చేయడం"</string>
- <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"మీ శారీరక పరిస్థితిని అనగా మీ గుండె స్పందన రేటు వంటి వాటిని పర్యవేక్షించే సెన్సార్‌ల నుండి డేటాను ప్రాప్యత చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permlab_bodySensors" msgid="4683341291818520277">"శరీర సెన్సార్‌లను (గుండె స్పందన రేటు మానిటర్‌ల వంటివి) యాక్సెస్ చేయండి"</string>
+ <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"మీ శారీరక పరిస్థితిని అనగా మీ గుండె స్పందన రేటు వంటి వాటిని పర్యవేక్షించే సెన్సార్‌ల నుండి డేటాను యాక్సెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_readCalendar" msgid="6716116972752441641">"క్యాలెండర్ ఈవెంట్‌లు మరియు వివరాలను చదవడం"</string>
<string name="permdesc_readCalendar" product="tablet" msgid="4993979255403945892">"ఈ యాప్ మీ టాబ్లెట్‌లో నిల్వ చేసిన క్యాలెండర్ ఈవెంట్‌లన్నీ చదవగలదు మరియు మీ క్యాలెండర్ డేటాను షేర్ చేయగలదు లేదా సేవ్ చేయగలదు."</string>
<string name="permdesc_readCalendar" product="tv" msgid="8837931557573064315">"ఈ యాప్‌ మీ టీవీలో నిల్వ చేసిన క్యాలెండర్ ఈవెంట్‌లన్నీ చదవగలదు మరియు మీ క్యాలెండర్ డేటాను షేర్ చేయగలదు లేదా సేవ్ చేయగలదు."</string>
@@ -382,11 +382,11 @@
<string name="permdesc_writeCalendar" product="tablet" msgid="1675270619903625982">"ఈ యాప్ మీ టాబ్లెట్‌లో క్యాలెండర్ ఈవెంట్‌లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ యజమానుల నుండి వచ్చినట్లుగా సందేశాలను పంపగలదు లేదా ఈవెంట్‌లను వాటి యజమానులకు తెలియకుండానే మార్చగలదు."</string>
<string name="permdesc_writeCalendar" product="tv" msgid="9017809326268135866">"ఈ యాప్ మీ టీవీలో క్యాలెండర్ ఈవెంట్‌లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ యజమానుల నుండి వచ్చినట్లుగా సందేశాలను పంపగలదు లేదా ఈవెంట్‌లను వాటి యజమానులకు తెలియకుండానే మార్చగలదు."</string>
<string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"ఈ యాప్ మీ ఫోన్‌లో క్యాలెండర్ ఈవెంట్‌లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ యజమానుల నుండి వచ్చినట్లుగా సందేశాలను పంపగలదు లేదా ఈవెంట్‌లను వాటి యజమానులకు తెలియకుండానే మార్చగలదు."</string>
- <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"అదనపు స్థాన ప్రదాత ఆదేశాలను ప్రాప్యత చేయడం"</string>
+ <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"అదనపు స్థాన ప్రదాత ఆదేశాలను యాక్సెస్ చేయడం"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"అదనపు స్థాన ప్రదాత ఆదేశాలను యాక్సెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. ఇది GPS లేదా ఇతర స్థాన మూలాల నిర్వహణలో యాప్‌ ప్రమేయం ఉండేలా అనుమతించవచ్చు."</string>
- <string name="permlab_accessFineLocation" msgid="251034415460950944">"ఖచ్చితమైన స్థానాన్ని (GPS మరియు నెట్‌వర్క్-ఆధారితం) ప్రాప్యత చేయడం"</string>
+ <string name="permlab_accessFineLocation" msgid="251034415460950944">"ఖచ్చితమైన స్థానాన్ని (GPS మరియు నెట్‌వర్క్-ఆధారితం) యాక్సెస్ చేయడం"</string>
<string name="permdesc_accessFineLocation" msgid="5821994817969957884">"ఈ యాప్‌ GPS ఆధారంగా లేదా సెల్ టవర్‌లు, Wi-Fi నెట్‌వర్క్‌ల వంటి నెట్‌వర్క్ స్థాన మూలాధారాల ఆధారంగా మీ స్థానాన్ని తెలుసుకోగలదు. యాప్‌ ఉపయోగించడానికి మీ ఫోన్‌లో ఈ స్థాన సేవలను తప్పనిసరిగా ఆన్ చేయాలి మరియు అందుబాటులో ఉండాలి. ఇది బ్యాటరీ వినియోగాన్ని పెంచవచ్చు."</string>
- <string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"ఇంచుమించు స్థానాన్ని (నెట్‌వర్క్-ఆధారితం) ప్రాప్యత చేయడం"</string>
+ <string name="permlab_accessCoarseLocation" msgid="7715277613928539434">"ఇంచుమించు స్థానాన్ని (నెట్‌వర్క్-ఆధారితం) యాక్సెస్ చేయడం"</string>
<string name="permdesc_accessCoarseLocation" product="tablet" msgid="3373266766487862426">"ఈ యాప్‌ సెల్ టవర్‌లు మరియు Wi-Fi నెట్‌వర్క్‌ల వంటి నెట్‌వర్క్ మూలాధారాల ఆధారంగా మీ స్థానాన్ని తెలుసుకోగలదు. యాప్‌ ఉపయోగించడానికి మీ టాబ్లెట్‌లో ఈ స్థాన సేవలను తప్పనిసరిగా ఆన్ చేయాలి మరియు అందుబాటులో ఉండాలి."</string>
<string name="permdesc_accessCoarseLocation" product="tv" msgid="1884022719818788511">"ఈ యాప్‌ సెల్ టవర్‌లు మరియు Wi-Fi నెట్‌వర్క్‌ల వంటి నెట్‌వర్క్ మూలాధారాల ఆధారంగా మీ స్థానాన్ని తెలుసుకోగలదు. యాప్‌ ఉపయోగించడానికి మీ టీవీలో ఈ స్థాన సేవలను తప్పనిసరిగా ఆన్ చేయాలి మరియు అందుబాటులో ఉండాలి."</string>
<string name="permdesc_accessCoarseLocation" product="default" msgid="7788009094906196995">"ఈ యాప్‌ సెల్ టవర్‌లు మరియు Wi-Fi నెట్‌వర్క్‌ల వంటి నెట్‌వర్క్ మూలాధారాల ఆధారంగా మీ స్థానాన్ని తెలుసుకోగలదు. యాప్‌ ఉపయోగించడానికి మీ ఫోన్‌లో ఈ స్థాన సేవలను తప్పనిసరిగా ఆన్ చేయాలి మరియు అందుబాటులో ఉండాలి."</string>
@@ -402,14 +402,14 @@
<string name="permdesc_vibrate" msgid="6284989245902300945">"వైబ్రేటర్‌ను నియంత్రించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"నేరుగా కాల్ చేసే ఫోన్ నంబర్‌లు"</string>
<string name="permdesc_callPhone" msgid="3740797576113760827">"మీ ప్రమేయం లేకుండా ఫోన్ నంబర్‌లకు కాల్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. దీని వలన అనుకోని ఛార్జీలు విధించబడవచ్చు లేదా కాల్‌లు రావచ్చు. ఇది అత్యవసర నంబర్‌లకు కాల్ చేయడానికి యాప్‌ను అనుమతించదని గుర్తుంచుకోండి. హానికరమైన యాప్‌లు మీ నిర్ధారణ లేకుండానే కాల్‌లు చేయడం ద్వారా మీకు డబ్బు ఖర్చయ్యేలా చేయవచ్చు."</string>
- <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS కాల్ సేవ ప్రాప్యత అనుమతి"</string>
+ <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS కాల్ సేవ యాక్సెస్ అనుమతి"</string>
<string name="permdesc_accessImsCallService" msgid="8992884015198298775">"మీ ప్రమేయం లేకుండా కాల్‌లు చేయడం కోసం IMS సేవను ఉపయోగించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
<string name="permlab_readPhoneState" msgid="9178228524507610486">"ఫోన్ స్థితి మరియు గుర్తింపుని చదవడం"</string>
<string name="permdesc_readPhoneState" msgid="1639212771826125528">"పరికరం యొక్క ఫోన్ ఫీచర్‌లను యాక్సెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది. ఈ అనుమతి ఫోన్ నంబర్ మరియు పరికరం IDలను, కాల్ సక్రియంగా ఉందా లేదా అనే విషయాన్ని మరియు కాల్ ద్వారా కనెక్ట్ చేయబడిన రిమోట్ నంబర్‌ను కనుగొనడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_manageOwnCalls" msgid="1503034913274622244">"కాల్‌లను సిస్టమ్ ద్వారా వెళ్లేలా చేయి"</string>
<string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"కాలింగ్ అనుభవాన్ని మెరుగుపరచడం కోసం తన కాల్‌లను సిస్టమ్ ద్వారా వెళ్లేలా చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
<string name="permlab_readPhoneNumbers" msgid="6108163940932852440">"ఫోన్ నంబర్‌లను చదువు"</string>
- <string name="permdesc_readPhoneNumbers" msgid="8559488833662272354">"పరికరం యొక్క ఫోన్ నంబర్‌లను ప్రాప్యత చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+ <string name="permdesc_readPhoneNumbers" msgid="8559488833662272354">"పరికరం యొక్క ఫోన్ నంబర్‌లను యాక్సెస్ చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"టాబ్లెట్‌ను నిద్రావస్థకు వెళ్లనీయకుండా నిరోధించడం"</string>
<string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"టీవీ నిద్రావస్థకు వెళ్లకుండా నిరోధించడం"</string>
<string name="permlab_wakeLock" product="default" msgid="573480187941496130">"ఫోన్‌ను నిద్రావస్థకు వెళ్లనీయకుండా నిరోధించడం"</string>
@@ -448,7 +448,7 @@
<string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"మల్టీక్యాస్ట్ చిరునామాలను ఉపయోగించి మీ టాబ్లెట్‌కు మాత్రమే కాకుండా Wi-Fi నెట్‌వర్క్‌లోని అన్ని పరికరాలకు పంపబడిన ప్యాకెట్‌లను స్వీకరించడానికి యాప్‌ను అనుమతిస్తుంది. మల్టీక్యాస్ట్ యేతర మోడ్ కంటే ఇది ఎక్కువ పవర్ ఉపయోగిస్తుంది."</string>
<string name="permdesc_changeWifiMulticastState" product="tv" msgid="9031975661145014160">"మల్టీక్యాస్ట్ చిరునామాలను ఉపయోగించి మీ టీవీకి మాత్రమే కాకుండా Wi-Fi నెట్‌వర్క్‌లోని అన్ని పరికరాలకు పంపిన ప్యాకెట్‌లను స్వీకరించడానికి అనువర్తనాన్ని అనుమతిస్తుంది. ఇది మల్టీక్యాస్ట్ యేతర మోడ్ కంటే ఎక్కువ పవర్‌ను ఉపయోగిస్తుంది."</string>
<string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"మల్టీక్యాస్ట్ చిరునామాలను ఉపయోగించి మీ ఫోన్‌కు మాత్రమే కాకుండా Wi-Fi నెట్‌వర్క్‌లోని అన్ని పరికరాలకు పంపబడిన ప్యాకెట్‌లను స్వీకరించడానికి అనువర్తనాన్ని అనుమతిస్తుంది. మల్టీక్యాస్ట్ యేతర మోడ్ కంటే ఇది ఎక్కువ పవర్ ఉపయోగిస్తుంది."</string>
- <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"బ్లూటూత్ సెట్టింగ్‌లను ప్రాప్యత చేయడం"</string>
+ <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"బ్లూటూత్ సెట్టింగ్‌లను యాక్సెస్ చేయడం"</string>
<string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"స్థానిక బ్లూటూత్ టాబ్లెట్‌ను కాన్ఫిగర్ చేయడానికి మరియు రిమోట్ పరికరాలతో దాన్ని కనుగొనడానికి మరియు జత చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permdesc_bluetoothAdmin" product="tv" msgid="3373125682645601429">"స్థానిక బ్లూటూత్ టీవీని కాన్ఫిగర్ చేయడానికి మరియు రిమోట్ పరికరాలను గుర్తించి, వాటితో జత చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
<string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"స్థానిక బ్లూటూత్ ఫోన్‌ను కాన్ఫిగర్ చేయడానికి మరియు రిమోట్ పరికరాలతో దాన్ని కనుగొనడానికి మరియు జత చేయడానికి యాప్‌ను అనుమతిస్తుంది."</string>
@@ -522,7 +522,7 @@
<string name="permdesc_manageNetworkPolicy" msgid="7537586771559370668">"నెట్‌వర్క్ విధానాలను నిర్వహించడానికి మరియు యాప్-నిర్దిష్ట నిబంధనలను నిర్వచించడానికి యాప్‌ను అనుమతిస్తుంది."</string>
<string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"నెట్‌వర్క్ వినియోగ అకౌంటింగ్‌ను సవరించడం"</string>
<string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"యాప్‌లలో నెట్‌వర్క్ వినియోగం ఎలా గణించాలనే దాన్ని సవరించడానికి యాప్‌ను అనుమతిస్తుంది. సాధారణ యాప్‌ల ద్వారా ఉపయోగించడానికి ఉద్దేశించినది కాదు."</string>
- <string name="permlab_accessNotifications" msgid="7673416487873432268">"నోటిఫికేషన్‌లను ప్రాప్యత చేయడం"</string>
+ <string name="permlab_accessNotifications" msgid="7673416487873432268">"నోటిఫికేషన్‌లను యాక్సెస్ చేయడం"</string>
<string name="permdesc_accessNotifications" msgid="458457742683431387">"నోటిఫికేషన్‌లను, ఇతర అనువర్తనాల ద్వారా పోస్ట్ చేయబడిన వాటిని తిరిగి పొందడానికి, పరిశీలించడానికి మరియు క్లియర్ చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
<string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"నోటిఫికేషన్ పరిశీలన సేవకు అనుబంధించడం"</string>
<string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"నోటిఫికేషన్ పరిశీలన సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాల కోసం ఎప్పటికీ అవసరం ఉండకూడదు."</string>
@@ -536,7 +536,7 @@
<string name="permdesc_accessNetworkConditions" msgid="6899102075825272211">"నెట్‌వర్క్ పరిస్థితులపై పరిశీలనల గురించి తెలుసుకోవడానికి అనువర్తనాన్ని అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండకూడదు."</string>
<string name="permlab_setInputCalibration" msgid="4902620118878467615">"ఇన్‌పుట్ పరికరం క్రమాంకనాన్ని మార్చండి"</string>
<string name="permdesc_setInputCalibration" msgid="4527511047549456929">"టచ్ స్క్రీన్ యొక్క క్రమాంకన పరామితులను సవరించడానికి అనువర్తనాన్ని అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
- <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM ప్రమాణపత్రాలను ప్రాప్యత చేయడం"</string>
+ <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM ప్రమాణపత్రాలను యాక్సెస్ చేయడం"</string>
<string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"DRM ప్రమాణపత్రాలను కేటాయించడానికి మరియు ఉపయోగించడానికి అనువర్తనాన్ని అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
<string name="permlab_handoverStatus" msgid="7820353257219300883">"Android Beam బదిలీ స్థితిని స్వీకరించడం"</string>
<string name="permdesc_handoverStatus" msgid="4788144087245714948">"ప్రస్తుత Android Beam బదిలీలకు సంబంధించిన సమాచారాన్ని స్వీకరించడానికి ఈ అనువర్తనాన్ని అనుమతిస్తుంది"</string>
@@ -546,7 +546,7 @@
<string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"క్యారియర్ సందేశ సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
<string name="permlab_bindCarrierServices" msgid="3233108656245526783">"క్యారియర్ సేవలకు అనుబంధించడం"</string>
<string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"క్యారియర్ సేవలకు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
- <string name="permlab_access_notification_policy" msgid="4247510821662059671">"అంతరాయం కలిగించవద్దు ఎంపిక ప్రాప్యత"</string>
+ <string name="permlab_access_notification_policy" msgid="4247510821662059671">"అంతరాయం కలిగించవద్దును యాక్సెస్ చేయడం"</string>
<string name="permdesc_access_notification_policy" msgid="3296832375218749580">"అంతరాయం కలిగించవద్దు ఎంపిక కాన్ఫిగరేషన్ చదవడానికి మరియు వ్రాయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"పాస్‌వర్డ్ నియమాలను సెట్ చేయండి"</string>
<string name="policydesc_limitPassword" msgid="2502021457917874968">"స్క్రీన్ లాక్ పాస్‌వర్డ్‌లు మరియు PINల్లో అనుమతించబడిన పొడవు మరియు అక్షరాలను నియంత్రిస్తుంది."</string>
@@ -849,8 +849,8 @@
<string name="menu_space_shortcut_label" msgid="2410328639272162537">"space"</string>
<string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string>
<string name="menu_delete_shortcut_label" msgid="3658178007202748164">"delete"</string>
- <string name="search_go" msgid="8298016669822141719">"శోధించు"</string>
- <string name="search_hint" msgid="1733947260773056054">"శోధించు..."</string>
+ <string name="search_go" msgid="8298016669822141719">"వెతుకు"</string>
+ <string name="search_hint" msgid="1733947260773056054">"వెతుకు..."</string>
<string name="searchview_description_search" msgid="6749826639098512120">"శోధించండి"</string>
<string name="searchview_description_query" msgid="5911778593125355124">"ప్రశ్నను శోధించండి"</string>
<string name="searchview_description_clear" msgid="1330281990951833033">"ప్రశ్నను క్లియర్ చేయి"</string>
@@ -1112,10 +1112,10 @@
<string name="network_available_sign_in" msgid="1848877297365446605">"నెట్‌వర్క్‌కి సైన్ ఇన్ చేయండి"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
- <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fiకి ఇంటర్నెట్ ప్రాప్యత లేదు"</string>
+ <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fiకి ఇంటర్నెట్ యాక్సెస్ లేదు"</string>
<string name="wifi_no_internet_detailed" msgid="8083079241212301741">"ఎంపికల కోసం నొక్కండి"</string>
<string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>కి మార్చబడింది"</string>
- <string name="network_switch_metered_detail" msgid="5325661434777870353">"పరికరం <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>కి ఇంటర్నెట్ ప్రాప్యత లేనప్పుడు <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ని ఉపయోగిస్తుంది. ఛార్జీలు వర్తించవచ్చు."</string>
+ <string name="network_switch_metered_detail" msgid="5325661434777870353">"పరికరం <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>కి ఇంటర్నెట్ యాక్సెస్ లేనప్పుడు <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ని ఉపయోగిస్తుంది. ఛార్జీలు వర్తించవచ్చు."</string>
<string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> నుండి <xliff:g id="NEW_NETWORK">%2$s</xliff:g>కి మార్చబడింది"</string>
<string-array name="network_switch_type_name">
<item msgid="3979506840912951943">"మొబైల్ డేటా"</item>
@@ -1164,7 +1164,7 @@
<string name="sim_removed_message" msgid="2333164559970958645">"మీరు చెల్లుబాటు అయ్యే సిమ్ కార్డు‌ను చొప్పించి పునఃప్రారంభించే వరకు మొబైల్ నెట్‌వర్క్ అందుబాటులో ఉండదు."</string>
<string name="sim_done_button" msgid="827949989369963775">"పూర్తయింది"</string>
<string name="sim_added_title" msgid="3719670512889674693">"సిమ్ కార్డు జోడించబడింది"</string>
- <string name="sim_added_message" msgid="6599945301141050216">"మొబైల్ నెట్‌వర్క్‌ను ప్రాప్యత చేయడానికి మీ పరికరాన్ని పునఃప్రారంభించండి."</string>
+ <string name="sim_added_message" msgid="6599945301141050216">"మొబైల్ నెట్‌వర్క్‌ను యాక్సెస్ చేయడానికి మీ పరికరాన్ని పునఃప్రారంభించండి."</string>
<string name="sim_restart_button" msgid="4722407842815232347">"పునఃప్రారంభించు"</string>
<string name="carrier_app_dialog_message" msgid="7066156088266319533">"మీ SIM సక్రమంగా పని చేస్తుండటానికి, మీరు మీ క్యారియర్ నుండి ఒక అనువర్తనాన్ని ఇన్‌స్టాల్ చేసుకొని, తెరవాలి."</string>
<string name="carrier_app_dialog_button" msgid="7900235513678617329">"అనువర్తనాన్ని పొందండి"</string>
@@ -1262,7 +1262,7 @@
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"జూమ్ నియంత్రణ కోసం రెండుసార్లు నొక్కండి"</string>
<string name="gadget_host_error_inflating" msgid="4882004314906466162">"విడ్జెట్‌ను జోడించడం సాధ్యపడలేదు."</string>
<string name="ime_action_go" msgid="8320845651737369027">"వెళ్లు"</string>
- <string name="ime_action_search" msgid="658110271822807811">"శోధించు"</string>
+ <string name="ime_action_search" msgid="658110271822807811">"వెతుకు"</string>
<string name="ime_action_send" msgid="2316166556349314424">"పంపు"</string>
<string name="ime_action_next" msgid="3138843904009813834">"తదుపరి"</string>
<string name="ime_action_done" msgid="8971516117910934605">"పూర్తయింది"</string>
@@ -1270,9 +1270,9 @@
<string name="ime_action_default" msgid="2840921885558045721">"అమలు చేయి"</string>
<string name="dial_number_using" msgid="5789176425167573586">"<xliff:g id="NUMBER">%s</xliff:g>ని ఉపయోగించి\nనంబర్ డయల్ చేయండి"</string>
<string name="create_contact_using" msgid="4947405226788104538">"<xliff:g id="NUMBER">%s</xliff:g>ని ఉపయోగించి\nపరిచయాన్ని సృష్టించండి"</string>
- <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"క్రింది ఒకటి లేదా అంతకంటే ఎక్కువ అనువర్తనాలు మీ ఖాతాను ప్రాప్యత చేయడానికి ఇప్పుడే మరియు భవిష్యత్తులో అనుమతిని అభ్యర్థించవచ్చు."</string>
+ <string name="grant_credentials_permission_message_header" msgid="2106103817937859662">"క్రింది ఒకటి లేదా అంతకంటే ఎక్కువ యాప్‌లు మీ ఖాతాను యాక్సెస్ చేయడానికి ఇప్పుడే మరియు భవిష్యత్తులో అనుమతిని అభ్యర్థించవచ్చు."</string>
<string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"మీరు ఈ అభ్యర్థనను అనుమతించాలనుకుంటున్నారా?"</string>
- <string name="grant_permissions_header_text" msgid="6874497408201826708">"ప్రాప్యత అభ్యర్థన"</string>
+ <string name="grant_permissions_header_text" msgid="6874497408201826708">"యాక్సెస్ అభ్యర్థన"</string>
<string name="allow" msgid="7225948811296386551">"అనుమతించండి"</string>
<string name="deny" msgid="2081879885755434506">"తిరస్కరించండి"</string>
<string name="permission_request_notification_title" msgid="6486759795926237907">"అనుమతి అభ్యర్థించబడింది"</string>
@@ -1281,7 +1281,7 @@
<string name="forward_intent_to_work" msgid="621480743856004612">"మీరు మీ కార్యాలయ ప్రొఫైల్‌లో ఈ అనువర్తనాన్ని ఉపయోగిస్తున్నారు"</string>
<string name="input_method_binding_label" msgid="1283557179944992649">"ఇన్‌పుట్ పద్ధతి"</string>
<string name="sync_binding_label" msgid="3687969138375092423">"సమకాలీకరణ"</string>
- <string name="accessibility_binding_label" msgid="4148120742096474641">"ప్రాప్యత"</string>
+ <string name="accessibility_binding_label" msgid="4148120742096474641">"యాక్సెస్ సామర్థ్యం"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"వాల్‌పేపర్"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"వాల్‌పేపర్‌ను మార్చండి"</string>
<string name="notification_listener_binding_label" msgid="2014162835481906429">"నోటిఫికేషన్ పరిశీలన"</string>
@@ -1483,14 +1483,14 @@
<string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"తీసివేయి"</string>
<string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"వాల్యూమ్‌ను సిఫార్సు చేయబడిన స్థాయి కంటే ఎక్కువగా పెంచాలా?\n\nసుదీర్ఘ వ్యవధుల పాటు అధిక వాల్యూమ్‌లో వినడం వలన మీ వినికిడి శక్తి దెబ్బ తినవచ్చు."</string>
- <string name="accessibility_shortcut_warning_dialog_title" msgid="8404780875025725199">"ప్రాప్యత సత్వరమార్గాన్ని ఉపయోగించాలా?"</string>
- <string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"షార్ట్‌కట్ ఆన్‌లో ఉన్నప్పుడు, రెండు వాల్యూమ్ బటన్‌లను 3 సెకన్ల పాటు నొక్కితే యాక్సెస్ ఫీచర్ ప్రారంభం అవుతుంది.\n\n ప్రస్తుత యాక్సెస్ ఫీచర్:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n సెట్టింగ్‌లు &gt; యాక్సెస్‌లో మీరు ఫీచర్‌ను మార్చవచ్చు."</string>
+ <string name="accessibility_shortcut_warning_dialog_title" msgid="8404780875025725199">"యాక్సెస్ షార్ట్‌కట్ ఉపయోగించాలా?"</string>
+ <string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"షార్ట్‌కట్ ఆన్‌లో ఉన్నప్పుడు, రెండు వాల్యూమ్ బటన్‌లను 3 సెకన్ల పాటు నొక్కితే యాక్సెస్ ఫీచర్ ప్రారంభం అవుతుంది.\n\n ప్రస్తుత యాక్సెస్ ఫీచర్:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n సెట్టింగ్‌లు &gt; యాక్సెస్‌లో మీరు ఫీచర్‌ను మార్చవచ్చు."</string>
<string name="disable_accessibility_shortcut" msgid="627625354248453445">"సత్వరమార్గాన్ని ఆఫ్ చేయి"</string>
<string name="leave_accessibility_shortcut_on" msgid="7653111894438512680">"సత్వరమార్గాన్ని ఉపయోగించు"</string>
<string name="accessibility_shortcut_enabling_service" msgid="7771852911861522636">"యాక్సెస్ సామర్థ్య షార్ట్‌కట్ ద్వారా <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆన్ చేయబడింది"</string>
<string name="accessibility_shortcut_disabling_service" msgid="2747243438223109821">"యాక్సెస్ సామర్థ్య షార్ట్‌కట్ ద్వారా <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ఆఫ్ చేయబడింది"</string>
- <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"ప్రాప్యత బటన్‌ను మీరు నొక్కినప్పుడు ఉపయోగించాల్సిన ఒక లక్షణాన్ని ఎంచుకోండి:"</string>
- <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"లక్షణాలను మార్చడానికి, ప్రాప్యత బటన్‌ను నొక్కి &amp; పట్టుకోండి."</string>
+ <string name="accessibility_button_prompt_text" msgid="4234556536456854251">"యాక్సెస్ బటన్‌ను మీరు నొక్కినప్పుడు ఉపయోగించాల్సిన ఒక ఫీచర్‌ను ఎంచుకోండి:"</string>
+ <string name="accessibility_button_instructional_text" msgid="6942300463612999993">"ఫీచర్‌లను మార్చడానికి, యాక్సెస్ సామర్థ్య బటన్‌ను నొక్కి &amp; పట్టుకోండి."</string>
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"మాగ్నిఫికేషన్"</string>
<string name="user_switched" msgid="3768006783166984410">"ప్రస్తుత వినియోగదారు <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g>కి మారుస్తోంది…"</string>
@@ -1627,7 +1627,7 @@
<string name="package_installed_device_owner" msgid="6875717669960212648">"మీ నిర్వాహకులు ఇన్‌స్టాల్ చేసారు"</string>
<string name="package_updated_device_owner" msgid="1847154566357862089">"మీ నిర్వాహకులు నవీకరించారు"</string>
<string name="package_deleted_device_owner" msgid="2307122077550236438">"మీ నిర్వాహకులు తొలగించారు"</string>
- <string name="battery_saver_description" msgid="1960431123816253034">"బ్యాటరీ జీవితకాలాన్ని మెరుగుపరచడంలో సహాయపడటానికి, బ్యాటరీ సేవర్ మీ పరికరం పనితీరును తగ్గిస్తుంది మరియు వైబ్రేషన్‌ను, స్థాన సేవలను మరియు అత్యధిక నేపథ్య డేటాను పరిమితం చేస్తుంది. ఇమెయిల్, మెసేజింగ్ మరియు సమకాలీకరణపై ఆధారపడే ఇతర అనువర్తనాలు మీరు వాటిని తెరిస్తే మినహా నవీకరించబడవు.\n\nమీ పరికరం ఛార్జ్ అవుతున్నప్పుడు బ్యాటరీ సేవర్ స్వయంచాలకంగా ఆఫ్ అవుతుంది."</string>
+ <string name="battery_saver_description" msgid="1960431123816253034">"బ్యాటరీ జీవితకాలాన్ని మెరుగుపరచడంలో సహాయపడటానికి, బ్యాటరీ సేవర్ మీ పరికరం పనితీరును తగ్గిస్తుంది మరియు వైబ్రేషన్‌ను, స్థాన సేవలను మరియు అత్యధిక నేపథ్య డేటాను పరిమితం చేస్తుంది. ఇమెయిల్, మెసేజింగ్ మరియు సమకాలీకరణపై ఆధారపడే ఇతర యాప్‌లు మీరు వాటిని తెరిస్తే మినహా అప్‌డేట్ చేయబడవు.\n\nమీ పరికరం ఛార్జ్ అవుతున్నప్పుడు బ్యాటరీ సేవర్ స్వయంచాలకంగా ఆఫ్ అవుతుంది."</string>
<string name="data_saver_description" msgid="6015391409098303235">"డేటా వినియోగాన్ని తగ్గించడంలో సహాయకరంగా ఉండటానికి, డేటా సేవర్ కొన్ని యాప్‌లను నేపథ్యంలో డేటాను పంపకుండా లేదా స్వీకరించకుండా నిరోధిస్తుంది. మీరు ప్రస్తుతం ఉపయోగిస్తున్న యాప్‌ డేటాను యాక్సెస్ చేయగలదు కానీ అలా అరుదుగా చేయవచ్చు. అంటే, ఉదాహరణకు, మీరు ఆ చిత్రాలను నొక్కే వరకు అవి ప్రదర్శించబడవు."</string>
<string name="data_saver_enable_title" msgid="4674073932722787417">"డేటా సేవర్‌ను ఆన్ చేయాలా?"</string>
<string name="data_saver_enable_button" msgid="7147735965247211818">"ఆన్ చేయి"</string>
@@ -1710,7 +1710,7 @@
<string name="language_picker_section_suggested" msgid="8414489646861640885">"సూచించినవి"</string>
<string name="language_picker_section_all" msgid="3097279199511617537">"అన్ని భాషలు"</string>
<string name="region_picker_section_all" msgid="8966316787153001779">"అన్ని ప్రాంతాలు"</string>
- <string name="locale_search_menu" msgid="2560710726687249178">"శోధించు"</string>
+ <string name="locale_search_menu" msgid="2560710726687249178">"వెతుకు"</string>
<string name="work_mode_off_title" msgid="2615362773958585967">"కార్యాలయ మోడ్‌ని ఆన్ చేయాలా?"</string>
<string name="work_mode_off_message" msgid="2961559609199223594">"ఇది అనువర్తనాలు, నేపథ్య సమకాలీకరణ మరియు సంబంధిత లక్షణాలతో సహా మీ కార్యాలయ ప్రొఫైల్‌ను ఆన్ చేస్తుంది"</string>
<string name="work_mode_turn_on" msgid="2062544985670564875">"ఆన్ చేయి"</string>
@@ -1725,7 +1725,7 @@
<string name="usb_mtp_launch_notification_description" msgid="8541876176425411358">"ఫైల్‌లను వీక్షించడానికి నొక్కండి"</string>
<string name="pin_target" msgid="3052256031352291362">"పిన్ చేయి"</string>
<string name="unpin_target" msgid="3556545602439143442">"అన్‌‌పిన్‌ ‌చేయి"</string>
- <string name="app_info" msgid="6856026610594615344">"అనువర్తన సమాచారం"</string>
+ <string name="app_info" msgid="6856026610594615344">"యాప్ సమాచారం"</string>
<string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
<string name="demo_starting_message" msgid="5268556852031489931">"డెమోను ప్రారంభిస్తోంది..."</string>
<string name="demo_restarting_message" msgid="952118052531642451">"పరికరాన్ని రీసెట్ చేస్తోంది..."</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 3143b034548f..598b5861af15 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2087,6 +2087,16 @@
{@link android.R.attr#windowBackground}.
-->
<attr name="windowSplashscreenContent" format="reference" />
+
+ <!-- If set, the navigation bar will be drawn such that it is compatible with a light
+ navigation bar background.
+ <p>For this to take effect, the window must be drawing the system bar backgrounds with
+ {@link android.R.attr#windowDrawsSystemBarBackgrounds} and the navigation bar must not
+ have been requested to be translucent with
+ {@link android.R.attr#windowTranslucentNavigation}.
+ Corresponds to setting {@link android.view.View#SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR} on
+ the decor view. -->
+ <attr name="windowLightNavigationBar" format="boolean" />
</declare-styleable>
<!-- The set of attributes that describe a AlertDialog's theme. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 01212adc0f9d..05f3ff1279dd 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -893,6 +893,18 @@
<!-- Maximum color temperature, in Kelvin, supported by Night display. -->
<integer name="config_nightDisplayColorTemperatureMax">4082</integer>
+ <string-array name="config_nightDisplayColorTemperatureCoefficients">
+ <!-- R a-coefficient --> <item>0.0</item>
+ <!-- R b-coefficient --> <item>0.0</item>
+ <!-- R y-intercept --> <item>1.0</item>
+ <!-- G a-coefficient --> <item>-0.00000000962353339</item>
+ <!-- G b-coefficient --> <item>0.000153045476</item>
+ <!-- G y-intercept --> <item>0.390782778</item>
+ <!-- B a-coefficient --> <item>-0.0000000189359041</item>
+ <!-- B b-coefficient --> <item>0.000302412211</item>
+ <!-- B y-intercept --> <item>-0.198650895</item>
+ </string-array>
+
<!-- Indicate whether to allow the device to suspend when the screen is off
due to the proximity sensor. This resource should only be set to true
if the sensor HAL correctly handles the proximity sensor as a wake-up source.
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 634d79a92a4b..9b2f18511e83 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2858,6 +2858,27 @@
<public name="autofill"/>
</public-group>
+ <!-- ===============================================================
+ Resources added in version P of the platform
+
+ NOTE: add <public> elements within a <public-group> like so:
+
+ <public-group type="attr" first-id="0x01010531">
+ <public name="exampleAttr1" />
+ <public name="exampleAttr2" />
+ </public-group>
+
+ To add a new public-group block, choose an id value that is 1 greater
+ than the last of that item above. For example, the last "attr" id
+ value above is 0x01010530, so the public-group of attrs below has
+ the id value of 0x01010531.
+ =============================================================== -->
+ <eat-comment />
+
+ <public-group type="attr" first-id="0x0101056c">
+ <public name="windowLightNavigationBar" />
+ </public-group>
+
<!-- ===============================================================
DO NOT ADD UN-GROUPED ITEMS HERE
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index cca73ddeec00..9bd779e8cfb2 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3865,7 +3865,10 @@
<!-- Message shown when user enters wrong PIN -->
<string name="kg_wrong_pin">Wrong PIN</string>
<!-- Countdown message shown after too many failed unlock attempts -->
- <string name="kg_too_many_failed_attempts_countdown">Try again in <xliff:g id="number">%1$d</xliff:g> seconds.</string>
+ <plurals name="kg_too_many_failed_attempts_countdown">
+ <item quantity="one">Try again in 1 second.</item>
+ <item quantity="other">Try again in <xliff:g id="number">%d</xliff:g> seconds.</item>
+ </plurals>
<!-- Instructions for using the pattern unlock screen -->
<string name="kg_pattern_instructions">Draw your pattern</string>
<!-- Instructions for using the SIM PIN unlock screen -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index eb314399e822..927d9dcec002 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2820,6 +2820,7 @@
<java-symbol type="integer" name="config_nightDisplayColorTemperatureDefault" />
<java-symbol type="integer" name="config_nightDisplayColorTemperatureMin" />
<java-symbol type="integer" name="config_nightDisplayColorTemperatureMax" />
+ <java-symbol type="array" name="config_nightDisplayColorTemperatureCoefficients" />
<!-- Default first user restrictions -->
<java-symbol type="array" name="config_defaultFirstUserRestrictions" />
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 7e9f561e68d5..f5b350b053d4 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -181,7 +181,7 @@
<shortcode country="mk" pattern="\\d{1,6}" free="129005|122" />
<!-- Mexico: 4-5 digits (not confirmed), known premium codes listed -->
- <shortcode country="mx" pattern="\\d{4,5}" premium="53035|7766" free="46645|5050|26259|50025|50052|9963" />
+ <shortcode country="mx" pattern="\\d{4,5}" premium="53035|7766" free="46645|5050|26259|50025|50052|9963|76551" />
<!-- Malaysia: 5 digits: http://www.skmm.gov.my/attachment/Consumer_Regulation/Mobile_Content_Services_FAQs.pdf -->
<shortcode country="my" pattern="\\d{5}" premium="32298|33776" free="22099|28288" />
diff --git a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
index 335cea772a74..50e29c2863c2 100644
--- a/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
+++ b/core/tests/coretests/src/android/database/DatabaseGeneralTest.java
@@ -1221,4 +1221,19 @@ public class DatabaseGeneralTest extends AndroidTestCase implements PerformanceT
InstrumentationRegistry.getInstrumentation()).executeShellCommand(cmd);
}
+ @SmallTest
+ public void testSavepointRollbacks() {
+ try (SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(":memory:", null)) {
+ db.execSQL("drop table if exists data");
+ db.execSQL("create table if not exists data (id INTEGER PRIMARY KEY, val TEXT)");
+ db.execSQL("begin deferred transaction");
+ db.execSQL("insert into data (val) values('row 1')");
+ db.execSQL("savepoint foo");
+ db.execSQL("insert into data (val) values('row 2')");
+ db.execSQL("rollback to foo");
+ db.execSQL("commit transaction");
+ long rowCount = DatabaseUtils.longForQuery(db, "select count(*) from data", null);
+ assertEquals(1, rowCount);
+ }
+ }
}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 6848fce764bc..8a57ea9a9c13 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -99,6 +99,7 @@ public class SettingsBackupTest {
Settings.Global.ALARM_MANAGER_CONSTANTS,
Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED,
Settings.Global.ALWAYS_FINISH_ACTIVITIES,
+ Settings.Global.ALWAYS_ON_DISPLAY_CONSTANTS,
Settings.Global.ANIMATOR_DURATION_SCALE,
Settings.Global.ANOMALY_DETECTION_CONSTANTS,
Settings.Global.APN_DB_UPDATE_CONTENT_URL,
@@ -253,6 +254,7 @@ public class SettingsBackupTest {
Settings.Global.NETSTATS_GLOBAL_ALERT_BYTES,
Settings.Global.NETSTATS_POLL_INTERVAL,
Settings.Global.NETSTATS_SAMPLE_ENABLED,
+ Settings.Global.NETSTATS_AUGMENT_ENABLED,
Settings.Global.NETSTATS_TIME_CACHE_MAX_AGE,
Settings.Global.NETSTATS_UID_BUCKET_DURATION,
Settings.Global.NETSTATS_UID_DELETE_AGE,
diff --git a/core/tests/systemproperties/run_core_systemproperties_test.sh b/core/tests/systemproperties/run_core_systemproperties_test.sh
index d39adbbfa390..9b1fe4be666b 100755
--- a/core/tests/systemproperties/run_core_systemproperties_test.sh
+++ b/core/tests/systemproperties/run_core_systemproperties_test.sh
@@ -15,7 +15,7 @@ fi
if [[ $rebuild == true ]]; then
make -j4 FrameworksCoreSystemPropertiesTests
- TESTAPP=${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreSystemPropertiesTests.apk
+ TESTAPP=${ANDROID_PRODUCT_OUT}/data/app/FrameworksCoreSystemPropertiesTests/FrameworksCoreSystemPropertiesTests.apk
COMMAND="adb install -r $TESTAPP"
echo $COMMAND
$COMMAND
diff --git a/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java b/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
index 544a96727217..282b0011eede 100644
--- a/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
+++ b/core/tests/systemproperties/src/android/os/SystemPropertiesTest.java
@@ -51,6 +51,11 @@ public class SystemPropertiesTest extends TestCase {
value = SystemProperties.get(KEY, "default");
assertEquals("default", value);
+ // null default value is the same as "".
+ SystemProperties.set(KEY, null);
+ value = SystemProperties.get(KEY, "default");
+ assertEquals("default", value);
+
SystemProperties.set(KEY, "SA");
value = SystemProperties.get(KEY, "default");
assertEquals("SA", value);
@@ -62,7 +67,78 @@ public class SystemPropertiesTest extends TestCase {
value = SystemProperties.get(KEY, "default");
assertEquals("default", value);
+ // null value is the same as "".
+ SystemProperties.set(KEY, "SA");
+ SystemProperties.set(KEY, null);
+ value = SystemProperties.get(KEY, "default");
+ assertEquals("default", value);
+
value = SystemProperties.get(KEY);
assertEquals("", value);
}
+
+ private static void testInt(String setVal, int defValue, int expected) {
+ SystemProperties.set(KEY, setVal);
+ int value = SystemProperties.getInt(KEY, defValue);
+ assertEquals(expected, value);
+ }
+
+ private static void testLong(String setVal, long defValue, long expected) {
+ SystemProperties.set(KEY, setVal);
+ long value = SystemProperties.getLong(KEY, defValue);
+ assertEquals(expected, value);
+ }
+
+ @SmallTest
+ public void testIntegralProperties() throws Exception {
+ testInt("", 123, 123);
+ testInt("", 0, 0);
+ testInt("", -123, -123);
+
+ testInt("123", 124, 123);
+ testInt("0", 124, 0);
+ testInt("-123", 124, -123);
+
+ testLong("", 3147483647L, 3147483647L);
+ testLong("", 0, 0);
+ testLong("", -3147483647L, -3147483647L);
+
+ testLong("3147483647", 124, 3147483647L);
+ testLong("0", 124, 0);
+ testLong("-3147483647", 124, -3147483647L);
+ }
+
+ @SmallTest
+ @SuppressWarnings("null")
+ public void testNullKey() throws Exception {
+ try {
+ SystemProperties.get(null);
+ fail("Expected NullPointerException");
+ } catch (NullPointerException npe) {
+ }
+
+ try {
+ SystemProperties.get(null, "default");
+ fail("Expected NullPointerException");
+ } catch (NullPointerException npe) {
+ }
+
+ try {
+ SystemProperties.set(null, "value");
+ fail("Expected NullPointerException");
+ } catch (NullPointerException npe) {
+ }
+
+ try {
+ SystemProperties.getInt(null, 0);
+ fail("Expected NullPointerException");
+ } catch (NullPointerException npe) {
+ }
+
+ try {
+ SystemProperties.getLong(null, 0);
+ fail("Expected NullPointerException");
+ } catch (NullPointerException npe) {
+ }
+ }
}
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
index bdd828fd5127..c4bf9d3123bf 100644
--- a/graphics/java/android/graphics/Color.java
+++ b/graphics/java/android/graphics/Color.java
@@ -73,7 +73,7 @@ import java.util.function.DoubleUnaryOperator;
* <h4>Encoding</h4>
* <p>The four components of a color int are encoded in the following way:</p>
* <pre class="prettyprint">
- * int color = (A & 0xff) << 24 | (R & 0xff) << 16 | (G & 0xff) << 16 | (B & 0xff);
+ * int color = (A & 0xff) << 24 | (R & 0xff) << 16 | (G & 0xff) << 8 | (B & 0xff);
* </pre>
*
* <p>Because of this encoding, color ints can easily be described as an integer
diff --git a/graphics/java/android/graphics/pdf/PdfEditor.java b/graphics/java/android/graphics/pdf/PdfEditor.java
index 245d76917453..0c509b77bad8 100644
--- a/graphics/java/android/graphics/pdf/PdfEditor.java
+++ b/graphics/java/android/graphics/pdf/PdfEditor.java
@@ -39,7 +39,7 @@ public final class PdfEditor {
private final CloseGuard mCloseGuard = CloseGuard.get();
- private final long mNativeDocument;
+ private long mNativeDocument;
private int mPageCount;
@@ -77,12 +77,17 @@ public final class PdfEditor {
} catch (ErrnoException ee) {
throw new IllegalArgumentException("file descriptor not seekable");
}
-
mInput = input;
synchronized (PdfRenderer.sPdfiumLock) {
mNativeDocument = nativeOpen(mInput.getFd(), size);
- mPageCount = nativeGetPageCount(mNativeDocument);
+ try {
+ mPageCount = nativeGetPageCount(mNativeDocument);
+ } catch (Throwable t) {
+ nativeClose(mNativeDocument);
+ mNativeDocument = 0;
+ throw t;
+ }
}
mCloseGuard.open("close");
@@ -274,20 +279,24 @@ public final class PdfEditor {
mCloseGuard.warnIfOpen();
}
- if (mInput != null) {
- doClose();
- }
+ doClose();
} finally {
super.finalize();
}
}
private void doClose() {
- synchronized (PdfRenderer.sPdfiumLock) {
- nativeClose(mNativeDocument);
+ if (mNativeDocument != 0) {
+ synchronized (PdfRenderer.sPdfiumLock) {
+ nativeClose(mNativeDocument);
+ }
+ mNativeDocument = 0;
+ }
+
+ if (mInput != null) {
+ IoUtils.closeQuietly(mInput);
+ mInput = null;
}
- IoUtils.closeQuietly(mInput);
- mInput = null;
mCloseGuard.close();
}
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
index b7b81aef36fd..c82ab0dd5cc7 100644
--- a/graphics/java/android/graphics/pdf/PdfRenderer.java
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -29,6 +29,8 @@ import android.system.ErrnoException;
import android.system.OsConstants;
import com.android.internal.util.Preconditions;
import dalvik.system.CloseGuard;
+
+import libcore.io.IoUtils;
import libcore.io.Libcore;
import java.io.IOException;
@@ -110,7 +112,7 @@ public final class PdfRenderer implements AutoCloseable {
private final Point mTempPoint = new Point();
- private final long mNativeDocument;
+ private long mNativeDocument;
private final int mPageCount;
@@ -159,7 +161,6 @@ public final class PdfRenderer implements AutoCloseable {
} catch (ErrnoException ee) {
throw new IllegalArgumentException("file descriptor not seekable");
}
-
mInput = input;
synchronized (sPdfiumLock) {
@@ -168,6 +169,7 @@ public final class PdfRenderer implements AutoCloseable {
mPageCount = nativeGetPageCount(mNativeDocument);
} catch (Throwable t) {
nativeClose(mNativeDocument);
+ mNativeDocument = 0;
throw t;
}
}
@@ -234,9 +236,7 @@ public final class PdfRenderer implements AutoCloseable {
mCloseGuard.warnIfOpen();
}
- if (mInput != null) {
- doClose();
- }
+ doClose();
} finally {
super.finalize();
}
@@ -245,16 +245,20 @@ public final class PdfRenderer implements AutoCloseable {
private void doClose() {
if (mCurrentPage != null) {
mCurrentPage.close();
+ mCurrentPage = null;
}
- synchronized (sPdfiumLock) {
- nativeClose(mNativeDocument);
+
+ if (mNativeDocument != 0) {
+ synchronized (sPdfiumLock) {
+ nativeClose(mNativeDocument);
+ }
+ mNativeDocument = 0;
}
- try {
- mInput.close();
- } catch (IOException ioe) {
- /* ignore - best effort */
+
+ if (mInput != null) {
+ IoUtils.closeQuietly(mInput);
+ mInput = null;
}
- mInput = null;
mCloseGuard.close();
}
@@ -451,19 +455,20 @@ public final class PdfRenderer implements AutoCloseable {
mCloseGuard.warnIfOpen();
}
- if (mNativePage != 0) {
- doClose();
- }
+ doClose();
} finally {
super.finalize();
}
}
private void doClose() {
- synchronized (sPdfiumLock) {
- nativeClosePage(mNativePage);
+ if (mNativePage != 0) {
+ synchronized (sPdfiumLock) {
+ nativeClosePage(mNativePage);
+ }
+ mNativePage = 0;
}
- mNativePage = 0;
+
mCloseGuard.close();
mCurrentPage = null;
}
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index 4e59baa48983..3c3b3177159b 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -216,10 +216,7 @@ void BakedOpRenderer::drawRects(const float* rects, int count, const SkPaint* pa
.setTransform(Matrix4::identity(), TransformFlags::None)
.setModelViewIdentityEmptyBounds()
.build();
- // Disable blending if this is the first draw to the main framebuffer, in case app has defined
- // transparency where it doesn't make sense - as first draw in opaque window.
- bool overrideDisableBlending = !mHasDrawn && mOpaque && !mRenderTarget.frameBufferId;
- mRenderState.render(glop, mRenderTarget.orthoMatrix, overrideDisableBlending);
+ mRenderState.render(glop, mRenderTarget.orthoMatrix, false);
mHasDrawn = true;
}
@@ -350,8 +347,14 @@ void BakedOpRenderer::renderGlopImpl(const Rect* dirtyBounds, const ClipBase* cl
const Glop& glop) {
prepareRender(dirtyBounds, clip);
// Disable blending if this is the first draw to the main framebuffer, in case app has defined
- // transparency where it doesn't make sense - as first draw in opaque window.
- bool overrideDisableBlending = !mHasDrawn && mOpaque && !mRenderTarget.frameBufferId;
+ // transparency where it doesn't make sense - as first draw in opaque window. Note that we only
+ // apply this improvement when the blend mode is SRC_OVER - other modes (e.g. CLEAR) can be
+ // valid draws that affect other content (e.g. draw CLEAR, then draw DST_OVER)
+ bool overrideDisableBlending = !mHasDrawn
+ && mOpaque
+ && !mRenderTarget.frameBufferId
+ && glop.blend.src == GL_ONE
+ && glop.blend.dst == GL_ONE_MINUS_SRC_ALPHA;
mRenderState.render(glop, mRenderTarget.orthoMatrix, overrideDisableBlending);
if (!mRenderTarget.frameBufferId) mHasDrawn = true;
}
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 61b3876cd095..36a747519c37 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -32,6 +32,7 @@
#include "protos/hwui.pb.h"
#include "protos/ProtoHelpers.h"
+#include <SkPathOps.h>
#include <algorithm>
#include <sstream>
#include <string>
@@ -555,5 +556,23 @@ void RenderNode::computeOrderingImpl(
}
}
+const SkPath* RenderNode::getClippedOutline(const SkRect& clipRect) const {
+ const SkPath* outlinePath = properties().getOutline().getPath();
+ const uint32_t outlineID = outlinePath->getGenerationID();
+
+ if (outlineID != mClippedOutlineCache.outlineID || clipRect != mClippedOutlineCache.clipRect) {
+ // update the cache keys
+ mClippedOutlineCache.outlineID = outlineID;
+ mClippedOutlineCache.clipRect = clipRect;
+
+ // update the cache value by recomputing a new path
+ SkPath clipPath;
+ clipPath.addRect(clipRect);
+ Op(*outlinePath, clipPath, kIntersect_SkPathOp, &mClippedOutlineCache.clippedOutline);
+
+ }
+ return &mClippedOutlineCache.clippedOutline;
+}
+
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index c4ae82af430c..89e022f5e68d 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -365,6 +365,17 @@ public:
return mSkiaLayer.get();
}
+ /**
+ * Returns the path that represents the outline of RenderNode intersected with
+ * the provided rect. This call will internally cache the resulting path in
+ * order to potentially return that path for subsequent calls to this method.
+ * By reusing the same path we get better performance on the GPU backends since
+ * those resources are cached in the hardware based on the path's genID.
+ *
+ * The returned path is only guaranteed to be valid until this function is called
+ * again or the RenderNode's outline is mutated.
+ */
+ const SkPath* getClippedOutline(const SkRect& clipRect) const;
private:
/**
* If this RenderNode has been used in a previous frame then the SkiaDisplayList
@@ -380,6 +391,16 @@ private:
* when it has been set to draw as a LayerType::RenderLayer.
*/
std::unique_ptr<skiapipeline::SkiaLayer> mSkiaLayer;
+
+ struct ClippedOutlineCache {
+ // keys
+ uint32_t outlineID = 0;
+ SkRect clipRect;
+
+ // value
+ SkPath clippedOutline;
+ };
+ mutable ClippedOutlineCache mClippedOutlineCache;
}; // class RenderNode
class MarkAndSweepRemoved : public TreeObserver {
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index f4ce864e83e1..e0373cae9923 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -511,25 +511,19 @@ void Tree::updateCache(sp<skiapipeline::VectorDrawableAtlas>& atlas, GrContext*
}
}
if (!canReuseSurface || mCache.dirty) {
- draw(surface.get(), dst);
+ if (surface) {
+ Bitmap& bitmap = getBitmapUpdateIfDirty();
+ SkBitmap skiaBitmap;
+ bitmap.getSkBitmap(&skiaBitmap);
+ if (!surface->getCanvas()->writePixels(skiaBitmap, dst.fLeft, dst.fTop)) {
+ ALOGD("VectorDrawable caching failed to efficiently upload");
+ surface->getCanvas()->drawBitmap(skiaBitmap, dst.fLeft, dst.fTop);
+ }
+ }
mCache.dirty = false;
}
}
-void Tree::draw(SkSurface* surface, const SkRect& dst) {
- if (surface) {
- SkCanvas* canvas = surface->getCanvas();
- float scaleX = dst.width() / mProperties.getViewportWidth();
- float scaleY = dst.height() / mProperties.getViewportHeight();
- SkAutoCanvasRestore acr(canvas, true);
- canvas->translate(dst.fLeft, dst.fTop);
- canvas->clipRect(SkRect::MakeWH(dst.width(), dst.height()));
- canvas->clear(SK_ColorTRANSPARENT);
- canvas->scale(scaleX, scaleY);
- mRootNode->draw(canvas, false);
- }
-}
-
void Tree::Cache::setAtlas(sp<skiapipeline::VectorDrawableAtlas> newAtlas,
skiapipeline::AtlasKey newAtlasKey) {
LOG_ALWAYS_FATAL_IF(newAtlasKey == INVALID_ATLAS_KEY);
@@ -570,22 +564,15 @@ void Tree::draw(SkCanvas* canvas) {
// Handle the case when VectorDrawableAtlas has been destroyed, because of memory pressure.
// We render the VD into a temporary standalone buffer and mark the frame as dirty. Next
// frame will be cached into the atlas.
+ Bitmap& bitmap = getBitmapUpdateIfDirty();
+ SkBitmap skiaBitmap;
+ bitmap.getSkBitmap(&skiaBitmap);
+
int scaledWidth = SkScalarCeilToInt(mProperties.getScaledWidth());
int scaledHeight = SkScalarCeilToInt(mProperties.getScaledHeight());
- SkRect src = SkRect::MakeWH(scaledWidth, scaledHeight);
-#ifndef ANDROID_ENABLE_LINEAR_BLENDING
- sk_sp<SkColorSpace> colorSpace = nullptr;
-#else
- sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeSRGB();
-#endif
- SkImageInfo info = SkImageInfo::MakeN32(scaledWidth, scaledHeight, kPremul_SkAlphaType,
- colorSpace);
- sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(canvas->getGrContext(),
- SkBudgeted::kYes, info);
- draw(surface.get(), src);
+ canvas->drawBitmapRect(skiaBitmap, SkRect::MakeWH(scaledWidth, scaledHeight),
+ mutateProperties()->getBounds(), getPaint(), SkCanvas::kFast_SrcRectConstraint);
mCache.clear();
- canvas->drawImageRect(surface->makeImageSnapshot().get(), mutateProperties()->getBounds(),
- getPaint(), SkCanvas::kFast_SrcRectConstraint);
markDirty();
}
}
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index efbb695a14dd..10d3e05c067f 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -738,11 +738,6 @@ private:
bool canReuseBitmap(Bitmap*, int width, int height);
void updateBitmapCache(Bitmap& outCache, bool useStagingData);
- /**
- * Draws the root node into "surface" at a given "dst" position.
- */
- void draw(SkSurface* surface, const SkRect& dst);
-
// Cap the bitmap size, such that it won't hurt the performance too much
// and it won't crash due to a very large scale.
// The drawable will look blurry above this size.
diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp
index 5577bbf2bfc9..7da7f3876a3d 100644
--- a/libs/hwui/hwui/MinikinUtils.cpp
+++ b/libs/hwui/hwui/MinikinUtils.cpp
@@ -68,7 +68,8 @@ float MinikinUtils::measureText(const Paint* paint, int bidiFlags, const Typefac
minikin::FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, paint, typeface);
const Typeface* resolvedTypeface = Typeface::resolveDefault(typeface);
return minikin::Layout::measureText(buf, start, count, bufSize, bidiFlags, minikinStyle,
- minikinPaint, resolvedTypeface->fFontCollection, advances, nullptr /* extent */);
+ minikinPaint, resolvedTypeface->fFontCollection, advances, nullptr /* extent */,
+ nullptr /* overhangs */);
}
bool MinikinUtils::hasVariationSelector(const Typeface* typeface, uint32_t codepoint, uint32_t vs) {
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
index 374d364787de..c8207bc70dd4 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
@@ -163,28 +163,22 @@ void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable*
hwuiMatrix.copyTo(shadowMatrix);
canvas->concat(shadowMatrix);
- const SkPath* casterOutlinePath = casterProperties.getOutline().getPath();
- // holds temporary SkPath to store the result of intersections
- SkPath tmpPath;
- const SkPath* casterPath = casterOutlinePath;
+ // default the shadow-casting path to the outline of the caster
+ const SkPath* casterPath = casterProperties.getOutline().getPath();
+
+ // intersect the shadow-casting path with the clipBounds, if present
+ if (clippedToBounds && !casterClipRect.contains(casterPath->getBounds())) {
+ casterPath = caster->getRenderNode()->getClippedOutline(casterClipRect);
+ }
- // TODO: In to following course of code that calculates the final shape, is there an optimal
- // of doing the Op calculations?
// intersect the shadow-casting path with the reveal, if present
+ SkPath tmpPath; // holds temporary SkPath to store the result of intersections
if (revealClipPath) {
Op(*casterPath, *revealClipPath, kIntersect_SkPathOp, &tmpPath);
tmpPath.setIsVolatile(true);
casterPath = &tmpPath;
}
- // intersect the shadow-casting path with the clipBounds, if present
- if (clippedToBounds) {
- SkPath clipBoundsPath;
- clipBoundsPath.addRect(casterClipRect);
- Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, &tmpPath);
- tmpPath.setIsVolatile(true);
- casterPath = &tmpPath;
- }
const Vector3 lightPos = SkiaPipeline::getLightCenter();
SkPoint3 skiaLightPos = SkPoint3::Make(lightPos.x, lightPos.y, lightPos.z);
SkPoint3 zParams;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index a8463ecc44d8..742f14d04db4 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -118,6 +118,8 @@ void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers,
return;
}
+ ATRACE_FORMAT("drawLayer [%s] %.1f x %.1f", layerNode->getName(), bounds.width(), bounds.height());
+
layerNode->getSkiaLayer()->hasRenderedSinceRepaint = false;
layerCanvas->clear(SK_ColorTRANSPARENT);
@@ -143,7 +145,6 @@ bool SkiaPipeline::createOrUpdateLayer(RenderNode* node,
}
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
SkASSERT(mRenderThread.getGrContext() != nullptr);
- // TODO: Handle wide color gamut requests
node->setLayerSurface(
SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes,
info, 0, &props));
@@ -194,10 +195,10 @@ void SkiaPipeline::renderVectorDrawableCache() {
sp<VectorDrawableAtlas> atlas = mRenderThread.cacheManager().acquireVectorDrawableAtlas();
auto grContext = mRenderThread.getGrContext();
atlas->prepareForDraw(grContext);
+ ATRACE_NAME("Update VectorDrawables");
for (auto vd : mVectorDrawables) {
vd->updateCache(atlas, grContext);
}
- grContext->flush();
mVectorDrawables.clear();
}
}
diff --git a/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp b/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp
index 23969908ff4d..9c9e17d600bf 100644
--- a/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp
+++ b/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp
@@ -270,7 +270,10 @@ sk_sp<SkSurface> VectorDrawableAtlas::createSurface(int width, int height, GrCon
sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeSRGB();
#endif
SkImageInfo info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType, colorSpace);
- return SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info);
+ // This must have a top-left origin so that calls to surface->canvas->writePixels
+ // performs a basic texture upload instead of a more complex drawing operation
+ return SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 0,
+ kTopLeft_GrSurfaceOrigin, nullptr);
}
void VectorDrawableAtlas::setStorageMode(StorageMode mode) {
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 16d77364942e..87e5bfdc8ca5 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -138,7 +138,7 @@ void EglManager::initialize() {
LOG_ALWAYS_FATAL_IF(!glInterface.get());
GrContextOptions options;
- options.fGpuPathRenderers &= ~GrContextOptions::GpuPathRenderers::kDistanceField;
+ options.fDisableDistanceFieldPaths = true;
mRenderThread.cacheManager().configureContext(&options);
mRenderThread.setGrContext(GrContext::Create(GrBackend::kOpenGL_GrBackend,
(GrBackendContext)glInterface.get(), options));
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index f4039889aded..3b9a5de00707 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -842,8 +842,8 @@ public final class AudioAttributes implements Parcelable {
@Override
public String toString () {
return new String("AudioAttributes:"
- + " usage=" + mUsage
- + " content=" + mContentType
+ + " usage=" + usageToString()
+ + " content=" + contentTypeToString()
+ " flags=0x" + Integer.toHexString(mFlags).toUpperCase()
+ " tags=" + mFormattedTags
+ " bundle=" + (mBundle == null ? "null" : mBundle.toString()));
@@ -894,6 +894,19 @@ public final class AudioAttributes implements Parcelable {
}
}
+ /** @hide */
+ public String contentTypeToString() {
+ switch(mContentType) {
+ case CONTENT_TYPE_UNKNOWN:
+ return new String("CONTENT_TYPE_UNKNOWN");
+ case CONTENT_TYPE_SPEECH: return new String("CONTENT_TYPE_SPEECH");
+ case CONTENT_TYPE_MUSIC: return new String("CONTENT_TYPE_MUSIC");
+ case CONTENT_TYPE_MOVIE: return new String("CONTENT_TYPE_MOVIE");
+ case CONTENT_TYPE_SONIFICATION: return new String("CONTENT_TYPE_SONIFICATION");
+ default: return new String("unknown content type " + mContentType);
+ }
+ }
+
private static int usageForStreamType(int streamType) {
switch(streamType) {
case AudioSystem.STREAM_VOICE_CALL:
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index eea4628e83af..157545746c21 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1248,7 +1248,7 @@ public class AudioManager {
//====================================================================
// Bluetooth SCO control
/**
- * Sticky broadcast intent action indicating that the bluetoooth SCO audio
+ * Sticky broadcast intent action indicating that the Bluetooth SCO audio
* connection state has changed. The intent contains on extra {@link #EXTRA_SCO_AUDIO_STATE}
* indicating the new state which is either {@link #SCO_AUDIO_STATE_DISCONNECTED}
* or {@link #SCO_AUDIO_STATE_CONNECTED}
@@ -1262,7 +1262,7 @@ public class AudioManager {
"android.media.SCO_AUDIO_STATE_CHANGED";
/**
- * Sticky broadcast intent action indicating that the bluetoooth SCO audio
+ * Sticky broadcast intent action indicating that the Bluetooth SCO audio
* connection state has been updated.
* <p>This intent has two extras:
* <ul>
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 4c3e261242eb..1f5edfa07c66 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -442,6 +442,10 @@ public class ExifInterface {
private static final int RAF_INFO_SIZE = 160;
private static final int RAF_JPEG_LENGTH_VALUE_SIZE = 4;
+ private static final byte[] HEIF_TYPE_FTYP = new byte[] {'f', 't', 'y', 'p'};
+ private static final byte[] HEIF_BRAND_MIF1 = new byte[] {'m', 'i', 'f', '1'};
+ private static final byte[] HEIF_BRAND_HEIC = new byte[] {'h', 'e', 'i', 'c'};
+
// See http://fileformats.archiveteam.org/wiki/Olympus_ORF
private static final short ORF_SIGNATURE_1 = 0x4f52;
private static final short ORF_SIGNATURE_2 = 0x5352;
@@ -1264,6 +1268,7 @@ public class ExifInterface {
private static final int IMAGE_TYPE_RAF = 9;
private static final int IMAGE_TYPE_RW2 = 10;
private static final int IMAGE_TYPE_SRW = 11;
+ private static final int IMAGE_TYPE_HEIF = 12;
static {
sFormatter = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
@@ -1691,6 +1696,10 @@ public class ExifInterface {
getRafAttributes(inputStream);
break;
}
+ case IMAGE_TYPE_HEIF: {
+ getHeifAttributes(inputStream);
+ break;
+ }
case IMAGE_TYPE_ORF: {
getOrfAttributes(inputStream);
break;
@@ -2108,6 +2117,8 @@ public class ExifInterface {
return IMAGE_TYPE_JPEG;
} else if (isRafFormat(signatureCheckBytes)) {
return IMAGE_TYPE_RAF;
+ } else if (isHeifFormat(signatureCheckBytes)) {
+ return IMAGE_TYPE_HEIF;
} else if (isOrfFormat(signatureCheckBytes)) {
return IMAGE_TYPE_ORF;
} else if (isRw2Format(signatureCheckBytes)) {
@@ -2146,6 +2157,78 @@ public class ExifInterface {
return true;
}
+ private boolean isHeifFormat(byte[] signatureCheckBytes) throws IOException {
+ ByteOrderedDataInputStream signatureInputStream = null;
+ try {
+ signatureInputStream = new ByteOrderedDataInputStream(signatureCheckBytes);
+ signatureInputStream.setByteOrder(ByteOrder.BIG_ENDIAN);
+
+ long chunkSize = signatureInputStream.readInt();
+ byte[] chunkType = new byte[4];
+ signatureInputStream.read(chunkType);
+
+ if (!Arrays.equals(chunkType, HEIF_TYPE_FTYP)) {
+ return false;
+ }
+
+ long chunkDataOffset = 8;
+ if (chunkSize == 1) {
+ // This indicates that the next 8 bytes represent the chunk size,
+ // and chunk data comes after that.
+ chunkSize = signatureInputStream.readLong();
+ if (chunkSize < 16) {
+ // The smallest valid chunk is 16 bytes long in this case.
+ return false;
+ }
+ chunkDataOffset += 8;
+ }
+
+ // only sniff up to signatureCheckBytes.length
+ if (chunkSize > signatureCheckBytes.length) {
+ chunkSize = signatureCheckBytes.length;
+ }
+
+ long chunkDataSize = chunkSize - chunkDataOffset;
+
+ // It should at least have major brand (4-byte) and minor version (4-byte).
+ // The rest of the chunk (if any) is a list of (4-byte) compatible brands.
+ if (chunkDataSize < 8) {
+ return false;
+ }
+
+ byte[] brand = new byte[4];
+ boolean isMif1 = false;
+ boolean isHeic = false;
+ for (long i = 0; i < chunkDataSize / 4; ++i) {
+ if (signatureInputStream.read(brand) != brand.length) {
+ return false;
+ }
+ if (i == 1) {
+ // Skip this index, it refers to the minorVersion, not a brand.
+ continue;
+ }
+ if (Arrays.equals(brand, HEIF_BRAND_MIF1)) {
+ isMif1 = true;
+ } else if (Arrays.equals(brand, HEIF_BRAND_HEIC)) {
+ isHeic = true;
+ }
+ if (isMif1 && isHeic) {
+ return true;
+ }
+ }
+ } catch (Exception e) {
+ if (DEBUG) {
+ Log.d(TAG, "Exception parsing HEIF file type box.", e);
+ }
+ } finally {
+ if (signatureInputStream != null) {
+ signatureInputStream.close();
+ signatureInputStream = null;
+ }
+ }
+ return false;
+ }
+
/**
* ORF has a similar structure to TIFF but it contains a different signature at the TIFF Header.
* This method looks at the 2 bytes following the Byte Order bytes to determine if this file is
@@ -2438,6 +2521,101 @@ public class ExifInterface {
}
}
+ private void getHeifAttributes(ByteOrderedDataInputStream in) throws IOException {
+ MediaMetadataRetriever retriever = new MediaMetadataRetriever();
+ try {
+ if (mSeekableFileDescriptor != null) {
+ retriever.setDataSource(mSeekableFileDescriptor);
+ } else {
+ retriever.setDataSource(new MediaDataSource() {
+ long mPosition;
+
+ @Override
+ public void close() throws IOException {}
+
+ @Override
+ public int readAt(long position, byte[] buffer, int offset, int size)
+ throws IOException {
+ if (size == 0) {
+ return 0;
+ }
+ if (position < 0) {
+ return -1;
+ }
+ if (mPosition != position) {
+ in.seek(position);
+ mPosition = position;
+ }
+
+ int bytesRead = in.read(buffer, offset, size);
+ if (bytesRead < 0) {
+ mPosition = -1; // need to seek on next read
+ return -1;
+ }
+
+ mPosition += bytesRead;
+ return bytesRead;
+ }
+
+ @Override
+ public long getSize() throws IOException {
+ return -1;
+ }
+ });
+ }
+
+ String hasVideo = retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO);
+
+ final String METADATA_HAS_VIDEO_VALUE_YES = "yes";
+ if (METADATA_HAS_VIDEO_VALUE_YES.equals(hasVideo)) {
+ String width = retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
+ String height = retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
+
+ if (width != null) {
+ mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_WIDTH,
+ ExifAttribute.createUShort(Integer.parseInt(width), mExifByteOrder));
+ }
+
+ if (height != null) {
+ mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_LENGTH,
+ ExifAttribute.createUShort(Integer.parseInt(height), mExifByteOrder));
+ }
+
+ // Note that the rotation angle from MediaMetadataRetriever for heif images
+ // are CCW, while rotation in ExifInterface orientations are CW.
+ String rotation = retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
+ if (rotation != null) {
+ int orientation = ExifInterface.ORIENTATION_NORMAL;
+
+ switch (Integer.parseInt(rotation)) {
+ case 90:
+ orientation = ExifInterface.ORIENTATION_ROTATE_270;
+ break;
+ case 180:
+ orientation = ExifInterface.ORIENTATION_ROTATE_180;
+ break;
+ case 270:
+ orientation = ExifInterface.ORIENTATION_ROTATE_90;
+ break;
+ }
+
+ mAttributes[IFD_TYPE_PRIMARY].put(TAG_ORIENTATION,
+ ExifAttribute.createUShort(orientation, mExifByteOrder));
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "Heif meta: " + width + "x" + height + ", rotation " + rotation);
+ }
+ }
+ } finally {
+ retriever.release();
+ }
+ }
+
/**
* ORF files contains a primary image data and a MakerNote data that contains preview/thumbnail
* images. Both data takes the form of IFDs and can therefore be read with the
@@ -2678,7 +2856,7 @@ public class ExifInterface {
}
if (getAttribute(TAG_ORIENTATION) == null) {
mAttributes[IFD_TYPE_PRIMARY].put(TAG_ORIENTATION,
- ExifAttribute.createULong(0, mExifByteOrder));
+ ExifAttribute.createUShort(0, mExifByteOrder));
}
if (getAttribute(TAG_LIGHT_SOURCE) == null) {
mAttributes[IFD_TYPE_EXIF].put(TAG_LIGHT_SOURCE,
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 9c138e30e929..bb6ae9863d31 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -201,5 +201,7 @@ interface IAudioService {
int dispatchFocusChange(in AudioFocusInfo afi, in int focusChange,
in IAudioPolicyCallback pcb);
+ oneway void playerHasOpPlayAudio(in int piid, in boolean hasOpPlayAudio);
+
// WARNING: read warning at top of file, it is recommended to add new methods at the end
}
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index 3308fc929b03..dc7fa8c00f82 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -28,6 +28,7 @@ interface IMediaRouterService {
MediaRouterClientState getState(IMediaRouterClient client);
boolean isPlaybackActive(IMediaRouterClient client);
+ boolean isGlobalBluetoothA2doOn();
void setDiscoveryRequest(IMediaRouterClient client, int routeTypes, boolean activeScan);
void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit);
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 5a16c36545c8..0d99473c69b9 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -3408,7 +3408,7 @@ public class MediaPlayer extends PlayerBase
private static void postEventFromNative(Object mediaplayer_ref,
int what, int arg1, int arg2, Object obj)
{
- MediaPlayer mp = (MediaPlayer)((WeakReference)mediaplayer_ref).get();
+ final MediaPlayer mp = (MediaPlayer)((WeakReference)mediaplayer_ref).get();
if (mp == null) {
return;
}
@@ -3416,8 +3416,14 @@ public class MediaPlayer extends PlayerBase
switch (what) {
case MEDIA_INFO:
if (arg1 == MEDIA_INFO_STARTED_AS_NEXT) {
- // this acquires the wakelock if needed, and sets the client side state
- mp.start();
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ // this acquires the wakelock if needed, and sets the client side state
+ mp.start();
+ }
+ }).start();
+ Thread.yield();
}
break;
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 29b88a28294c..2894e8956c1c 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -88,7 +88,6 @@ public class MediaRouter {
RouteInfo mBluetoothA2dpRoute;
RouteInfo mSelectedRoute;
- RouteInfo mSystemAudioRoute;
final boolean mCanConfigureWifiDisplays;
boolean mActivelyScanningWifiDisplays;
@@ -150,7 +149,6 @@ public class MediaRouter {
}
addRouteStatic(mDefaultAudioVideo);
- mSystemAudioRoute = mDefaultAudioVideo;
// This will select the active wifi display route if there is one.
updateWifiDisplayStatus(mDisplayService.getWifiDisplayStatus());
@@ -185,7 +183,7 @@ public class MediaRouter {
}
void updateAudioRoutes(AudioRoutesInfo newRoutes) {
- boolean updated = false;
+ boolean audioRoutesChanged = false;
if (newRoutes.mainType != mCurAudioRoutesInfo.mainType) {
mCurAudioRoutesInfo.mainType = newRoutes.mainType;
int name;
@@ -201,11 +199,10 @@ public class MediaRouter {
}
mDefaultAudioVideo.mNameResId = name;
dispatchRouteChanged(mDefaultAudioVideo);
- updated = true;
+ audioRoutesChanged = true;
}
final int mainType = mCurAudioRoutesInfo.mainType;
-
if (!TextUtils.equals(newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) {
mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName;
if (mCurAudioRoutesInfo.bluetoothName != null) {
@@ -219,8 +216,6 @@ public class MediaRouter {
info.mDeviceType = RouteInfo.DEVICE_TYPE_BLUETOOTH;
mBluetoothA2dpRoute = info;
addRouteStatic(mBluetoothA2dpRoute);
- mSystemAudioRoute = mBluetoothA2dpRoute;
- selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mSystemAudioRoute, false);
} else {
mBluetoothA2dpRoute.mName = mCurAudioRoutesInfo.bluetoothName;
dispatchRouteChanged(mBluetoothA2dpRoute);
@@ -229,30 +224,32 @@ public class MediaRouter {
// BT disconnected
removeRouteStatic(mBluetoothA2dpRoute);
mBluetoothA2dpRoute = null;
- mSystemAudioRoute = mDefaultAudioVideo;
- selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mSystemAudioRoute, false);
- }
- updated = true;
- }
-
- if (mBluetoothA2dpRoute != null) {
- final boolean a2dpEnabled = isBluetoothA2dpOn();
- if (mSelectedRoute == mBluetoothA2dpRoute && !a2dpEnabled) {
- // A2DP off
- mSystemAudioRoute = mDefaultAudioVideo;
- updated = true;
- } else if ((mSelectedRoute == mDefaultAudioVideo || mSelectedRoute == null) &&
- a2dpEnabled) {
- // A2DP on or BT connected
- mSystemAudioRoute = mBluetoothA2dpRoute;
- updated = true;
}
+ audioRoutesChanged = true;
}
- if (updated) {
+
+ if (audioRoutesChanged) {
+ selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, getDefaultSystemAudioRoute(), false);
Log.v(TAG, "Audio routes updated: " + newRoutes + ", a2dp=" + isBluetoothA2dpOn());
}
}
+ RouteInfo getDefaultSystemAudioRoute() {
+ boolean globalBluetoothA2doOn = false;
+ try {
+ globalBluetoothA2doOn = mMediaRouterService.isGlobalBluetoothA2doOn();
+ } catch (RemoteException ex) {
+ Log.e(TAG, "Unable to call isSystemBluetoothA2doOn.", ex);
+ }
+ return (globalBluetoothA2doOn && mBluetoothA2dpRoute != null)
+ ? mBluetoothA2dpRoute : mDefaultAudioVideo;
+ }
+
+ RouteInfo getCurrentSystemAudioRoute() {
+ return (isBluetoothA2dpOn() && mBluetoothA2dpRoute != null)
+ ? mBluetoothA2dpRoute : mDefaultAudioVideo;
+ }
+
boolean isBluetoothA2dpOn() {
try {
return mAudioService.isBluetoothA2dpOn();
@@ -603,15 +600,13 @@ public class MediaRouter {
@Override
public void onRestoreRoute() {
+ // Skip restoring route if the selected route is not a system audio route, or
+ // MediaRouter is initializing.
if ((mSelectedRoute != mDefaultAudioVideo && mSelectedRoute != mBluetoothA2dpRoute)
- || mSelectedRoute == mSystemAudioRoute) {
+ || mSelectedRoute == null) {
return;
}
- try {
- sStatic.mAudioService.setBluetoothA2dpOn(mSelectedRoute == mBluetoothA2dpRoute);
- } catch (RemoteException e) {
- Log.e(TAG, "Error changing Bluetooth A2DP state", e);
- }
+ mSelectedRoute.select();
}
}
}
@@ -946,7 +941,7 @@ public class MediaRouter {
boolean wasDefaultOrBluetoothRoute = (oldRoute == sStatic.mDefaultAudioVideo
|| oldRoute == sStatic.mBluetoothA2dpRoute);
if (oldRoute == route
- && (!wasDefaultOrBluetoothRoute || oldRoute == sStatic.mSystemAudioRoute)) {
+ && (!wasDefaultOrBluetoothRoute || route == sStatic.getCurrentSystemAudioRoute())) {
return;
}
if (!route.matchesTypes(types)) {
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index 9bd93aa31abf..4808d7a5aa6a 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -276,6 +276,7 @@ public abstract class PlayerBase {
// volume used by the player
try {
if (oldHasAppOpsPlayAudio != mHasAppOpsPlayAudio) {
+ getService().playerHasOpPlayAudio(mPlayerIId, mHasAppOpsPlayAudio);
if (mHasAppOpsPlayAudio) {
if (DEBUG_APP_OPS) {
Log.v(TAG, "updateAppOpsPlayAudio: unmuting player, vol=" + mLeftVolume
diff --git a/packages/PrintSpooler/res/values-hi/strings.xml b/packages/PrintSpooler/res/values-hi/strings.xml
index c9bc285a49b5..454834cc1898 100644
--- a/packages/PrintSpooler/res/values-hi/strings.xml
+++ b/packages/PrintSpooler/res/values-hi/strings.xml
@@ -31,7 +31,7 @@
<string name="template_all_pages" msgid="3322235982020148762">"सभी <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
<string name="template_page_range" msgid="428638530038286328">"पेज संख्या <xliff:g id="PAGE_COUNT">%1$s</xliff:g>"</string>
<string name="pages_range_example" msgid="8558694453556945172">"उदाहरण 1—5,8,11—13"</string>
- <string name="print_preview" msgid="8010217796057763343">"प्रिंट पूर्वावलोकन"</string>
+ <string name="print_preview" msgid="8010217796057763343">"प्रिंट की झलक"</string>
<string name="install_for_print_preview" msgid="6366303997385509332">"झलक के लिए पीडीएफ़ व्यूअर इंस्टॉल करें"</string>
<string name="printing_app_crashed" msgid="854477616686566398">"प्रिंटिंग ऐप्लिकेशन क्रैश हो गया"</string>
<string name="generating_print_job" msgid="3119608742651698916">"प्रिंट कार्य जनरेट हो रहा है"</string>
@@ -106,6 +106,6 @@
<string name="print_error_default_message" msgid="8602678405502922346">"क्षमा करें, उससे बात नहीं बनी. पुन: प्रयास करें."</string>
<string name="print_error_retry" msgid="1426421728784259538">"फिर से प्रयास करें"</string>
<string name="print_error_printer_unavailable" msgid="8985614415253203381">"यह प्रिंटर इस समय उपलब्ध नहीं है."</string>
- <string name="print_cannot_load_page" msgid="6179560924492912009">"पूर्वावलोकन प्रदर्शित नहीं किया जा सकता"</string>
- <string name="print_preparing_preview" msgid="3939930735671364712">"पूर्वावलोकन तैयार हो रहा है..."</string>
+ <string name="print_cannot_load_page" msgid="6179560924492912009">"झलक नहीं दिखाई जा सकती"</string>
+ <string name="print_preparing_preview" msgid="3939930735671364712">"झलक तैयार हो रही है..."</string>
</resources>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
index f11a9cde9520..b6a003de0eb9 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java
@@ -136,7 +136,12 @@ public final class RemotePrintDocument {
mState = STATE_CANCELED;
notifyUpdateCanceled();
}
- runPendingCommand();
+ if (mNextCommand != null) {
+ runPendingCommand();
+ } else {
+ // The update was not performed, hence the spec is stale
+ mUpdateSpec.reset();
+ }
}
}
};
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 5a3bdf34ce64..44f68eca49a3 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -664,7 +664,9 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- mMediaSizeComparator.onConfigurationChanged(newConfig);
+ if (mMediaSizeComparator != null) {
+ mMediaSizeComparator.onConfigurationChanged(newConfig);
+ }
if (mPrintPreviewController != null) {
mPrintPreviewController.onOrientationChanged();
diff --git a/packages/SettingsLib/res/drawable/ic_info_outline_24dp.xml b/packages/SettingsLib/res/drawable/ic_info_outline_24dp.xml
index 3fe1e9e5ca9f..5a7f954e0dfd 100644
--- a/packages/SettingsLib/res/drawable/ic_info_outline_24dp.xml
+++ b/packages/SettingsLib/res/drawable/ic_info_outline_24dp.xml
@@ -21,6 +21,12 @@
android:viewportHeight="24.0"
android:tint="?android:attr/textColorSecondary">
<path
- android:fillColor="#000000"
- android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
+ android:fillColor="#FF000000"
+ android:pathData="M12,17L12,17c0.55,0 1,-0.45 1,-1v-4c0,-0.55 -0.45,-1 -1,-1l0,0c-0.55,0 -1,0.45 -1,1v4C11,16.55 11.45,17 12,17z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12,2c-5.52,0 -10,4.48 -10,10s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8s8,3.59 8,8S16.41,20 12,20z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M12,9.1L12,9.1c0.61,0 1.1,-0.49 1.1,-1.1l0,0c0,-0.61 -0.49,-1.1 -1.1,-1.1l0,0c-0.61,0 -1.1,0.49 -1.1,1.1l0,0C10.9,8.61 11.39,9.1 12,9.1z"/>
</vector>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index bd4062d9a0dd..2cb374a58386 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Laat altyd Wi-Fi-swerfskanderings toe"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Mobiele data is altyd aktief"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardewareversnelling vir verbinding"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Deaktiveer absolute volume"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Aktiveer inband-luitoon"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP-weergawe"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Hierdie instellings is bedoel net vir ontwikkelinggebruik. Dit kan jou toestel en die programme daarop breek of vreemde dinge laat doen."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifieer programme oor USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontroleer programme wat via ADB/ADT geïnstalleer is vir skadelike gedrag."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Deaktiveer die Bluetooth-kenmerk vir absolute volume indien daar volumeprobleme met afgeleë toestelle is, soos onaanvaarbare harde klank of geen beheer nie."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Laat toe dat luitone op die foon op Bluetooth-kopstukke gespeel word"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Plaaslike terminaal"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index b6fe78270339..c57f9b0d9339 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"ሁልጊዜ የWi‑Fi ማንቀሳቀስ ቅኝቶችን ይፍቀዱ"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"የተንቀሳቃሽ ስልክ ውሂብ ሁልጊዜ ገቢር ነው"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"የሃርድዌር ማቀላጠፊያን በማስተሳሰር ላይ"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ፍጹማዊ ድምፅን አሰናክል"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"የውስጠ-ሞገድ ማስጮህን አንቃ"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"የብሉቱዝ AVRCP ስሪት"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"እነዚህ ቅንብሮች የታሰቡት ለግንባታ አጠቃቀም ብቻ ናቸው። መሳሪያህን እና በሱ ላይ ያሉትን መተግበሪያዎች እንዲበለሹ ወይም በትክክል እንዳይሰሩ ሊያደርጉ ይችላሉ።"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"መተግበሪያዎች በUSB በኩል ያረጋግጡ"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"በADB/ADT በኩል የተጫኑ መተግበሪያዎች ጎጂ ባህሪ ካላቸው ያረጋግጡ።"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"እንደ ተቀባይነት በሌለው ደረጃ ድምፁ ከፍ ማለት ወይም መቆጣጠር አለመቻል ያሉ ከሩቅ መሣሪያዎች ጋር የድምፅ ችግር በሚኖርበት ጊዜ የብሉቱዝ ፍጹማዊ ድምፅን ባሕሪ ያሰናክላል።"</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"በስልኩ ላይ ያሉ የጥሪ ቅላጼዎች በብሉቱዝ ጆሮ ማዳመጫዎች ላይ እንዲጫወቱ ፍቀድ"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"አካባቢያዊ ተርሚናል"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index f8f39ce82fd6..e59ad8fe9767 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"‏السماح دائمًا بعمليات فحص Wi-Fi للتجوال"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"بيانات الجوّال نشطة دائمًا"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"تسريع الأجهزة للتوصيل"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"تعطيل مستوى الصوت المطلق"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"تمكين الرنين ضمن النطاق الأساسي"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"‏إصدار Bluetooth AVRCP"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"هذه الإعدادات مخصصة لاستخدام التطوير فقط. قد يتسبب هذا في حدوث أعطال أو خلل في أداء الجهاز والتطبيقات المثبتة عليه."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"‏التحقق من التطبيقات عبر USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"‏التحقق من التطبيقات المثبتة عبر ADB/ADT لكشف السلوك الضار"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"لتعطيل ميزة مستوى الصوت المطلق للبلوتوث في حالة حدوث مشكلات متعلقة بمستوى الصوت مع الأجهزة البعيدة مثل مستوى صوت عالٍ بشكل غير مقبول أو نقص إمكانية التحكم في الصوت."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"السماح بتشغيل نغمات الرنين على الهاتف من خلال سماعات الرأس البلوتوث"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"تطبيق طرفي محلي"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 8eb6d90460f7..1ec5d62e088d 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi axtarışlarına həmişə icazə verin"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Mobil data həmişə aktiv"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Birləşmə üçün avadanlıq akselerasiyası"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Mütləq səs həcmi deaktiv edin"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Diapazon daxili zəngi aktiv edin"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP Versiya"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Bu parametrlər yalnız inkişafetdirici istifadə üçün nəzərdə tutulub. Onlar cihaz və tətbiqlərinizin sınması və ya pis işləməsinə səbəb ola bilər."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB üzərindən tətbiqləri yoxlayın"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT vasitəsi ilə quraşdırılmış tətbiqləri zərərli davranış üzrə yoxlayın."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Uzaqdan idarə olunan cihazlarda dözülməz yüksək səs həcmi və ya nəzarət çatışmazlığı kimi səs problemləri olduqda Bluetooth mütləq səs həcmi xüsusiyyətini deaktiv edir."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Telefondakı bütün melodiyaların Bluetooth qulaqlıqlarında oxudulmasına icazə verin"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Yerli terminal"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 1f225907be42..d0427c9ecc5c 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Uvek dozvoli skeniranje Wi‑Fi-ja u romingu"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Mobilni podaci su uvek aktivni"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardversko ubrzanje privezivanja"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Onemogući glavno podešavanje jačine zvuka"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Omogućavanje zvonjave na istom kanalu"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Verzija Bluetooth AVRCP-a"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ova podešavanja su namenjena samo za programiranje. Mogu da izazovu prestanak funkcionisanja ili neočekivano ponašanje uređaja i aplikacija na njemu."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifikuj aplikacije preko USB-a"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Proverava da li su aplikacije instalirane preko ADB-a/ADT-a štetne."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Onemogućava glavno podešavanje jačine zvuka na Bluetooth uređaju u slučaju problema sa jačinom zvuka na daljinskim uređajima, kao što su izuzetno velika jačina zvuka ili nedostatak kontrole."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Omogućite da se melodija zvona na telefonu pušta preko Bluetooth slušalica"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokalni terminal"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 80dbab48680a..363a904cc9b2 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Заўсёды дазваляць роўмінгавае сканіраванне Wi‑Fi"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Мабільная перадача даных заўсёды актыўная"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Апаратнае паскарэнне ў рэжыме мадэма"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Адключыць абсалютны гук"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Уключыць унутрыпалосны празвон"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Версія Bluetooth AVRCP"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Гэтыя налады прызначаны толькi для распрацоўшыкаў. Яны могуць выклікаць збоi прылад i ўсталяваных на iх прыкладанняў, а таксама перашкаджаць iх працы."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Праверце прыкладаннi па USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Праверце прыкладаннi, усталяваныя з дапамогай ADB/ADT, на нестабiльныя паводзiны."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Адключыць функцыю абсалютнага гуку Bluetooth у выпадку праблем з гукам на аддаленых прыладах, напр., пры непрымальна высокай гучнасці або адсутнасці кіравання."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Дазволіць прайграванне рынгтонаў на тэлефоне праз гарнітуры Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Лакальны тэрмінал"</string>
diff --git a/packages/SettingsLib/res/values-bg/arrays.xml b/packages/SettingsLib/res/values-bg/arrays.xml
index 996067ee1bd3..2017886f929e 100644
--- a/packages/SettingsLib/res/values-bg/arrays.xml
+++ b/packages/SettingsLib/res/values-bg/arrays.xml
@@ -68,10 +68,26 @@
<item msgid="1913619118958233129">"avrcp15"</item>
<item msgid="7142710449249088270">"avrcp16"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (5254942598247222737) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:4 (2091430979086738145) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (7848030269621918608) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:4 (298198075927343893) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Използване на сист. избор (стандартно)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"Разширено аудиокодиране (AAC)"</item>
+ <item msgid="5254942598247222737">"Аудио: <xliff:g id="APTX">aptX™</xliff:g> от <xliff:g id="QUALCOMM">Qualcomm®</xliff:g>"</item>
+ <item msgid="2091430979086738145">"Аудио: <xliff:g id="APTX_HD">aptX™ HD</xliff:g> от <xliff:g id="QUALCOMM">Qualcomm®</xliff:g>"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ <item msgid="723675059572222462">"Активиране на кодеците по избор"</item>
+ <item msgid="3304843301758635896">"Деактивиране на кодеците по избор"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Използване на сист. избор (стандартно)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"Разширено аудиокодиране (AAC)"</item>
+ <item msgid="7848030269621918608">"Аудио: <xliff:g id="APTX">aptX™</xliff:g> от <xliff:g id="QUALCOMM">Qualcomm®</xliff:g>"</item>
+ <item msgid="298198075927343893">"Аудио: <xliff:g id="APTX_HD">aptX™ HD</xliff:g> от <xliff:g id="QUALCOMM">Qualcomm®</xliff:g>"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ <item msgid="2209680154067241740">"Активиране на кодеците по избор"</item>
+ <item msgid="741805482892725657">"Деактивиране на кодеците по избор"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="3093023430402746802">"Използване на сист. избор (стандартно)"</item>
<item msgid="8895532488906185219">"44,1 кХц"</item>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index ffe076b82c22..43859e0c87df 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Сканирането за роуминг на Wi-Fi да е разрешено винаги"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Винаги активни мобилни данни"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Хардуерно ускорение за тетъринга"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Деактивиране на пълната сила на звука"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Активиране на звъненето в една и съща честотна лента"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Версия на AVRCP за Bluetooth"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Тези настройки са предназначени само за програмиране. Те могат да доведат до прекъсване на работата или неправилно функциониране на устройството ви и приложенията в него."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Потвържд. на прил. през USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Проверка на инсталираните чрез ADB/ADT приложения за опасно поведение."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Деактивира функцията на Bluetooth за пълна сила на звука в случай на проблеми със звука на отдалечени устройства, като например неприемливо висока сила на звука или липса на управление."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Разрешаване на мелодиите на телефона да се възпроизвеждат на слушалките с Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Локален терминал"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index e9fae31e91cf..593f5ca5ad18 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"সর্বদা ওয়াই ফাই রোম স্ক্যানকে অনুমতি দিন"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"মোবাইল ডেটা সব সময় সক্রিয় থাক"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"টিথারিং হার্ডওয়্যার অ্যাক্সিলারেশন"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"চূড়ান্ত ভলিউম অক্ষম করুন"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"ইন-ব্যান্ড রিং করা সক্ষম করুন"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"ব্লুটুথ AVRCP সংস্করণ"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"এইসব সেটিংস কেবলমাত্র উন্নত করার উদ্দেশ্য। সেগুলি কারণে আপনার ডিভাইস ভেঙ্গে এবং অ্যাপ্লিকেশানগুলি ভালো ভাবে কাজ করা নাও কারতে পারে।"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB এর অ্যাপ্লিকেশনগুলি যাচাই করুন"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ক্ষতিকারক ক্রিয়াকলাপ করছে কিনা তার জন্য ADB/ADT মারফত ইনস্টল করা অ্যাপ্লিকেশানগুলি চেক করুন।"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"অপ্রত্যাশিত উচ্চ ভলিউম বা নিয়ন্ত্রণের অভাবের মত দূরবর্তী ডিভাইসের ভলিউম সমস্যাগুলির ক্ষেত্রে, ব্লুটুথ চুড়ান্ত ভলিউম বৈশিষ্ট্য অক্ষম করে৷"</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"ফোনের রিংটোন ব্লুটুথ হেডসেটে শোনা সক্ষম করুন"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"স্থানীয় টার্মিনাল"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 3986809da411..bbea335abf94 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Uvijek dopustiti Wi-Fi lutajuće skeniranje"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Mobilna mreža za prijenos podataka je uvijek aktivna"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardversko ubrzavanje dijeljenja veze"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Onemogućite apsolutnu jačinu zvuka"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Omogući zvono unutar pojasa"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP verzija"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ove postavke su namijenjene samo za svrhe razvoja. Mogu izazvati pogrešno ponašanje uređaja i aplikacija na njemu."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifikuj aplikacije putem USB-a"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Provjerava da li se u aplikacijama instaliranim putem ADB-a/ADT-a javlja zlonamerno ponašanje."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Onemogućava opciju Bluetooth apsolutne jačine zvuka u slučaju problema s jačinom zvuka na udaljenim uređajima, kao što je neprihvatljivo glasan zvuk ili nedostatak kontrole."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Dopusti da se melodije zvona reproduciranju na Bluetooth slušalicama"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokalni terminal"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 4ef2337239a3..a0261231b5a8 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permet sempre cerca de Wi-Fi en ininerància"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Dades mòbils sempre actives"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Acceleració per maquinari per compartir la xarxa"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desactiva el volum absolut"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Activa el so al mateix canal"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versió AVRCP de Bluetooth"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Aquesta configuració només està prevista per a usos de desenvolupament. Pot fer que el dispositiu i que les aplicacions s\'interrompin o tinguin un comportament inadequat."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifica aplicacions per USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Comprova les aplicacions instal·lades mitjançant ADB/ADT per detectar possibles comportaments perillosos"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desactiva la funció de volum absolut de Bluetooth en cas que es produeixin problemes de volum amb dispositius remots, com ara un volum massa alt o una manca de control."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Permet que els sons de trucada del telèfon es reprodueixin en auriculars amb Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 5158277e7613..e6e91cd9a20a 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Vždy povolit Wi-Fi roaming"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Mobilní data jsou vždy aktivní"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardwarová akcelerace tetheringu"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Zakázat absolutní hlasitost"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Povolit vyzvánění v hovorovém pásmu"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Verze profilu Bluetooth AVRCP"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Tato nastavení jsou určena pouze pro vývojáře. Mohou způsobit rozbití nebo nesprávné fungování zařízení a nainstalovaných aplikací."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Ověřit aplikace z USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrolovat škodlivost aplikací nainstalovaných pomocí nástroje ADB/ADT"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Zakáže funkci absolutní hlasitosti Bluetooth. Zabrání tak problémům s hlasitostí vzdálených zařízení (jako je příliš vysoká hlasitost nebo nemožnost ovládání)."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Umožňuje přehrávat vyzváněcí tóny z telefonu v náhlavní soupravě Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Místní terminál"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 830d086c7685..a18a4a452653 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Tillad altid scanning af Wi-Fi-roaming"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Mobildata er altid aktiveret"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardwareacceleration ved netdeling"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Deaktiver absolut lydstyrke"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Afspil ringetone via Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"AVRCP-version for Bluetooth"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Disse indstillinger er kun beregnet til brug i forbindelse med udvikling. De kan forårsage, at din enhed og dens applikationer går ned eller ikke fungerer korrekt."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificer apps via USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Tjek apps, der er installeret via ADB/ADT, for skadelig adfærd."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Deaktiverer funktionen til absolut lydstyrke via Bluetooth i tilfælde af problemer med lydstyrken på eksterne enheder, f.eks. uacceptabel høj lyd eller manglende kontrol."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Tillad, at ringetoner på telefonen kan afspilles i Bluetooth-headset"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokal terminal"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index 86fc43ff38f7..309b75b5d8c5 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"WLAN-Roamingsuchen immer zulassen"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Mobile Datennutzung immer aktiviert"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardwarebeschleunigung für Tethering"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Maximallautstärke deaktivieren"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"In-Band-Klingeln aktivieren"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP-Version"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Diese Einstellungen sind ausschließlich für Entwicklungszwecke gedacht. Sie können dein Gerät und die darauf installierten Apps beschädigen oder zu unerwünschtem Verhalten führen."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Apps über USB bestätigen"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Überprüft installierte Apps über ADB/ADT auf schädliches Verhalten"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Deaktiviert die Bluetooth-Maximallautstärkefunktion, falls auf Remote-Geräten Probleme mit der Lautstärke auftreten, wie beispielsweise übermäßig laute Wiedergabe oder fehlende Kontrolle bei der Steuerung."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Wiedergabe von Smartphone-Klingeltönen auf Bluetooth-Headsets zulassen"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokales Terminal"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 3a0c128e50ad..bfaa7789287c 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Να επιτρέπεται πάντα η σάρωση Wi-Fi κατά την περιαγωγή"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Πάντα ενεργά δεδομένα κινητής τηλεφωνίας"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Σύνδεση επιτάχυνσης υλικού"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Απενεργοποίηση απόλυτης έντασης"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Ενεργοποίηση κλήσης εντός εύρους"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Έκδοση AVRCP Bluetooth"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Αυτές οι ρυθμίσεις προορίζονται για χρήση κατά την ανάπτυξη. Μπορούν να προκαλέσουν προβλήματα στη λειτουργία της συσκευής και των εφαρμογών σας."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Επαλήθευση εφαρμογών μέσω USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Έλεγχος εφαρμογών που έχουν εγκατασταθεί μέσω ADB/ADT για επιβλαβή συμπεριφορά."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Απενεργοποιεί τη δυνατότητα απόλυτης έντασης του Bluetooth σε περίπτωση προβλημάτων έντασης με απομακρυσμένες συσκευές, όπως όταν υπάρχει μη αποδεκτά υψηλή ένταση ή απουσία ελέγχου."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Να επιτρέπεται η αναπαραγωγή των ήχων κλήσης του τηλεφώνου στα ακουστικά Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Τοπική τερματική εφαρμογή"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/arrays.xml b/packages/SettingsLib/res/values-en-rAU/arrays.xml
index 3eec9e8800fb..55feafa87a95 100644
--- a/packages/SettingsLib/res/values-en-rAU/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rAU/arrays.xml
@@ -68,10 +68,26 @@
<item msgid="1913619118958233129">"avrcp15"</item>
<item msgid="7142710449249088270">"avrcp16"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (5254942598247222737) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:4 (2091430979086738145) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (7848030269621918608) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:4 (298198075927343893) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Use System Selection (Default)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="5254942598247222737">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+ <item msgid="2091430979086738145">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ <item msgid="723675059572222462">"Enable Optional Codecs"</item>
+ <item msgid="3304843301758635896">"Disable Optional Codecs"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Use System Selection (Default)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="7848030269621918608">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+ <item msgid="298198075927343893">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ <item msgid="2209680154067241740">"Enable Optional Codecs"</item>
+ <item msgid="741805482892725657">"Disable Optional Codecs"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="3093023430402746802">"Use System Selection (Default)"</item>
<item msgid="8895532488906185219">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index b427efe4a070..db8cfa1fa436 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Always allow Wi‑Fi Roam Scans"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Mobile data always active"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Tethering hardware acceleration"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Disable absolute volume"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Enable in-band ringing"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP Version"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"These settings are intended for development use only. They can cause your device and the applications on it to break or misbehave."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verify apps over USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Check apps installed via ADB/ADT for harmful behaviour."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Disables the Bluetooth absolute volume feature in case of volume issues with remote devices such as unacceptably loud volume or lack of control."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Allow ringtones on the phone to be played on Bluetooth headsets"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Local terminal"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/arrays.xml b/packages/SettingsLib/res/values-en-rCA/arrays.xml
index 3eec9e8800fb..55feafa87a95 100644
--- a/packages/SettingsLib/res/values-en-rCA/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rCA/arrays.xml
@@ -68,10 +68,26 @@
<item msgid="1913619118958233129">"avrcp15"</item>
<item msgid="7142710449249088270">"avrcp16"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (5254942598247222737) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:4 (2091430979086738145) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (7848030269621918608) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:4 (298198075927343893) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Use System Selection (Default)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="5254942598247222737">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+ <item msgid="2091430979086738145">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ <item msgid="723675059572222462">"Enable Optional Codecs"</item>
+ <item msgid="3304843301758635896">"Disable Optional Codecs"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Use System Selection (Default)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="7848030269621918608">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+ <item msgid="298198075927343893">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ <item msgid="2209680154067241740">"Enable Optional Codecs"</item>
+ <item msgid="741805482892725657">"Disable Optional Codecs"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="3093023430402746802">"Use System Selection (Default)"</item>
<item msgid="8895532488906185219">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index b427efe4a070..db8cfa1fa436 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Always allow Wi‑Fi Roam Scans"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Mobile data always active"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Tethering hardware acceleration"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Disable absolute volume"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Enable in-band ringing"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP Version"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"These settings are intended for development use only. They can cause your device and the applications on it to break or misbehave."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verify apps over USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Check apps installed via ADB/ADT for harmful behaviour."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Disables the Bluetooth absolute volume feature in case of volume issues with remote devices such as unacceptably loud volume or lack of control."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Allow ringtones on the phone to be played on Bluetooth headsets"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Local terminal"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/arrays.xml b/packages/SettingsLib/res/values-en-rGB/arrays.xml
index 3eec9e8800fb..55feafa87a95 100644
--- a/packages/SettingsLib/res/values-en-rGB/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rGB/arrays.xml
@@ -68,10 +68,26 @@
<item msgid="1913619118958233129">"avrcp15"</item>
<item msgid="7142710449249088270">"avrcp16"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (5254942598247222737) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:4 (2091430979086738145) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (7848030269621918608) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:4 (298198075927343893) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Use System Selection (Default)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="5254942598247222737">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+ <item msgid="2091430979086738145">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ <item msgid="723675059572222462">"Enable Optional Codecs"</item>
+ <item msgid="3304843301758635896">"Disable Optional Codecs"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Use System Selection (Default)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="7848030269621918608">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+ <item msgid="298198075927343893">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ <item msgid="2209680154067241740">"Enable Optional Codecs"</item>
+ <item msgid="741805482892725657">"Disable Optional Codecs"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="3093023430402746802">"Use System Selection (Default)"</item>
<item msgid="8895532488906185219">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index b427efe4a070..db8cfa1fa436 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Always allow Wi‑Fi Roam Scans"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Mobile data always active"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Tethering hardware acceleration"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Disable absolute volume"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Enable in-band ringing"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP Version"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"These settings are intended for development use only. They can cause your device and the applications on it to break or misbehave."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verify apps over USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Check apps installed via ADB/ADT for harmful behaviour."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Disables the Bluetooth absolute volume feature in case of volume issues with remote devices such as unacceptably loud volume or lack of control."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Allow ringtones on the phone to be played on Bluetooth headsets"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Local terminal"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/arrays.xml b/packages/SettingsLib/res/values-en-rIN/arrays.xml
index 3eec9e8800fb..55feafa87a95 100644
--- a/packages/SettingsLib/res/values-en-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-en-rIN/arrays.xml
@@ -68,10 +68,26 @@
<item msgid="1913619118958233129">"avrcp15"</item>
<item msgid="7142710449249088270">"avrcp16"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (5254942598247222737) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:4 (2091430979086738145) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (7848030269621918608) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:4 (298198075927343893) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Use System Selection (Default)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="5254942598247222737">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+ <item msgid="2091430979086738145">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ <item msgid="723675059572222462">"Enable Optional Codecs"</item>
+ <item msgid="3304843301758635896">"Disable Optional Codecs"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Use System Selection (Default)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="7848030269621918608">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> audio"</item>
+ <item msgid="298198075927343893">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> audio"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ <item msgid="2209680154067241740">"Enable Optional Codecs"</item>
+ <item msgid="741805482892725657">"Disable Optional Codecs"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="3093023430402746802">"Use System Selection (Default)"</item>
<item msgid="8895532488906185219">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index b427efe4a070..db8cfa1fa436 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Always allow Wi‑Fi Roam Scans"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Mobile data always active"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Tethering hardware acceleration"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Disable absolute volume"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Enable in-band ringing"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP Version"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"These settings are intended for development use only. They can cause your device and the applications on it to break or misbehave."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verify apps over USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Check apps installed via ADB/ADT for harmful behaviour."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Disables the Bluetooth absolute volume feature in case of volume issues with remote devices such as unacceptably loud volume or lack of control."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Allow ringtones on the phone to be played on Bluetooth headsets"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Local terminal"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 4cf842b7cfbd..01809e766d5d 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‎‎‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‎‎‏‎‎‏‎‏‏‎‎‏‏‏‏‎‎‏‏‎‎‎‏‏‎‏‏‎‏‏‎‎‎‏‎‏‏‏‎‏‎‎Always allow Wi‑Fi Roam Scans‎‏‎‎‏‎"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‏‏‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‎‏‎‏‏‎‎‎‏‏‏‏‏‎‎‎‏‏‏‎‎‏‏‎‏‏‏‎‎‏‎‎Mobile data always active‎‏‎‎‏‎"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‏‎‏‏‎‎‎‎‏‏‎‎‎‎‏‏‎‏‎‎‏‎‏‎‎‎‎‎‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‎‏‏‎‏‏‎‎Tethering hardware acceleration‎‏‎‎‏‎"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‎‏‏‎‎‏‎‎‏‏‏‎‎‏‎‏‏‏‎‎‏‏‏‎‏‏‏‎‎‎‏‎‎‏‎‏‎‏‏‏‎‎‎‏‏‏‎‏‏‏‎‎‏‎Disable absolute volume‎‏‎‎‏‎"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‎‏‏‎‏‎‏‏‏‎‎‏‏‎‏‎‏‏‎‏‎‎‏‏‏‏‎‏‏‏‏‎‎‎‎‏‏‏‎‎‏‎‏‏‎‎‎‎‏‏‎‏‏‏‎‏‎‎‎Enable in-band ringing‎‏‎‎‏‎"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‎‎‎‎‎‎‏‎‏‎‏‏‏‎‎‎‏‏‏‎‏‎‎‎‏‏‏‎‎‎‎‎‎‎‏‏‎‏‏‎‎‏‏‏‎‏‎‏‏‏‎‎‎‎‎‎‎‏‎Bluetooth AVRCP Version‎‏‎‎‏‎"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‏‎‏‏‎‎‎‎‎‏‎‎‎‏‏‏‎‏‎‏‎‏‎‏‎‎‏‏‏‏‏‎‎‏‎‎‏‎‏‏‎‏‏‎‎‎These settings are intended for development use only. They can cause your device and the applications on it to break or misbehave.‎‏‎‎‏‎"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‎‎‎‎‎‏‎‎‎‏‎‏‏‏‎‏‎‎‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‎Verify apps over USB‎‏‎‎‏‎"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‏‏‎‏‎‎‏‏‎‏‎‎‏‎‎‎‎‎‎‎‎‏‏‏‎‎‏‎‏‎‏‏‏‎‎‏‏‎‎‎‎‏‏‎‎‎‎‎Check apps installed via ADB/ADT for harmful behavior.‎‏‎‎‏‎"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‏‎‏‏‎‏‏‎‏‎‎‏‏‎‏‏‏‎‏‏‎‏‏‎‎‎‏‎‎‏‎‎‎‏‎‎‎‎‎‎‏‎‎‏‎‎‏‎‏‎Disables the Bluetooth absolute volume feature in case of volume issues with remote devices such as unacceptably loud volume or lack of control.‎‏‎‎‏‎"</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‏‏‎‏‎‏‏‎‎‎‎‎‏‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‎‏‏‎‏‎‎‏‎‏‏‎‎‎‏‏‎‎‎‎‎‏‏‎‎‎‏‏‏‏‎Allow ringtones on the phone to be played on Bluetooth headsets‎‏‎‎‏‎"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‎‏‏‎‏‎‏‎‎‏‏‏‎‎‎‏‎‏‎‎‏‎‏‎‎‎‎‎‎‏‏‏‏‏‎‏‎‎‎‏‎‎‎‎‏‏‎‎‎‎‎‎‏‏‎‏‎‎‎‎Local terminal‎‏‎‎‏‎"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 5869d13dfcee..2290a7ec3915 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permitir siempre búsquedas de Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Datos móviles siempre activados"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleración de hardware de conexión mediante dispositivo portátil"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Inhabilitar volumen absoluto"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Habilitar sonido dentro de banda"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versión de AVRCP del Bluetooth"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Estos parámetros de configuración están destinados únicamente a los programadores. Pueden hacer que el dispositivo o sus aplicaciones no funcionen correctamente."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificar aplicaciones por USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Comprobar que las aplicaciones instaladas mediante ADB/ADT no ocasionen daños"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Inhabilita la función de volumen absoluto de Bluetooth si se producen problemas de volumen con dispositivos remotos (por ejemplo, volumen demasiado alto o falta de control)."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Permite que los tonos del teléfono suenen en auriculares Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index f57d70360188..2819d4104fb7 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permitir siempre búsquedas de Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Datos móviles siempre activos"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleración por hardware para conexión compartida"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Inhabilitar volumen absoluto"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Habilitar tono de llamada por Bluetooth"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versión AVRCP del Bluetooth"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Estos ajustes están destinados únicamente a los desarrolladores. Pueden provocar que el dispositivo o las aplicaciones no funcionen correctamente."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificar aplicaciones por USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Comprueba las aplicaciones instaladas mediante ADB/ADT para detectar comportamientos dañinos"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Inhabilita la función de volumen absoluto de Bluetooth si se producen problemas de volumen con dispositivos remotos (por ejemplo, volumen demasiado alto o falta de control)."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Permite que los tonos de llamada del teléfono se reproduzcan en auriculares Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index 156bca4db077..a5299c2ca80f 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Luba alati WiFi-rändluse skannimine"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Mobiilne andmeside on alati aktiivne"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Jagamise riistvaraline kiirendus"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Keela absoluutne helitugevus"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Luba ribasisene helisemine"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetoothi AVRCP versioon"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Need seaded on mõeldud ainult arendajatele. Need võivad põhjustada seadme ja seadmes olevate rakenduste rikkeid või valesti toimimist."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Kinnita rakendus USB kaudu"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrolli, kas ADB/ADT-ga installitud rakendused on ohtlikud."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Keelatakse Bluetoothi absoluutse helitugevuse funktsioon, kui kaugseadmetega on helitugevuse probleeme (nt liiga vali heli või juhitavuse puudumine)."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Lubab telefonis olevaid helinaid esitada Bluetoothi peakomplektides"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Kohalik terminal"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 831718cf3257..1629e41026fb 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Onartu beti ibiltaritzan Wi-Fi sareak bilatzea"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Datu mugikorrak beti aktibo"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Konexioa partekatzeko hardwarearen azelerazioa"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desgaitu bolumen absolutua"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Gaitu tonuak audio-kanal berean erreproduzitzeko aukera"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP bertsioa"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ezarpen hauek garapen-xedeetarako pentsatu dira soilik. Baliteke ezarpenen eraginez gailua matxuratzea edo funtzionamendu okerra izatea."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Egiaztatu USBko aplikazioak."</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Egiaztatu ADB/ADT bidez instalatutako aplikazioak portaera kaltegarriak antzemateko."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desgaitu egiten du Bluetooth bidezko bolumen absolutuaren eginbidea urruneko gailuetan arazoak hautematen badira; esaterako, bolumena ozenegia bada edo ezin bada kontrolatu."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Onartu telefonoko tonuak Bluetooth entzungailuetan erreproduzitzeko aukera"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Tokiko terminala"</string>
diff --git a/packages/SettingsLib/res/values-fa/arrays.xml b/packages/SettingsLib/res/values-fa/arrays.xml
index 3599c4c72538..d2297778fb00 100644
--- a/packages/SettingsLib/res/values-fa/arrays.xml
+++ b/packages/SettingsLib/res/values-fa/arrays.xml
@@ -68,10 +68,26 @@
<item msgid="1913619118958233129">"‏avrcp نسخه ۱۵"</item>
<item msgid="7142710449249088270">"‏avrcp نسخه ۱۶"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (5254942598247222737) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:4 (2091430979086738145) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (7848030269621918608) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:4 (298198075927343893) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"استفاده از انتخاب سیستم (پیش‌فرض)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="5254942598247222737">"صوت <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2091430979086738145">"صوت <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ <item msgid="723675059572222462">"فعال کردن کدک‌های اختیاری"</item>
+ <item msgid="3304843301758635896">"غیرفعال کردن کدک‌های اختیاری"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"استفاده از انتخاب سیستم (پیش‌فرض)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="7848030269621918608">"صوت <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="298198075927343893">"صوت <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ <item msgid="2209680154067241740">"فعال کردن کدک‌های اختیاری"</item>
+ <item msgid="741805482892725657">"غیرفعال کردن کدک‌های اختیاری"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="3093023430402746802">"استفاده از انتخاب سیستم (پیش‌فرض)"</item>
<item msgid="8895532488906185219">"۴۴٫۱ کیلوهرتز"</item>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index b825d407c7a4..5d806d0217b5 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"‏اسکن‌های رومینگ Wi‑Fi همیشه مجاز است"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"داده تلفن همراه همیشه فعال باشد"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"شتاب سخت‌افزاری اتصال به اینترنت با تلفن همراه"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"غیرفعال کردن میزان صدای مطلق"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"فعال کردن زنگ زدن درون باندی"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"‏نسخه AVRCP بلوتوث"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"این تنظیمات فقط برای برنامه‌نویسی در نظر گرفته شده است. ممکن است استفاده از این تنظیمات موجب خرابی یا عملکرد نادرست دستگاه یا برنامه‌های شما شود."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"‏تأیید برنامه‌های نصب شده از طریق USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"‏برنامه‌های نصب شده از طریق ADB/ADT را ازنظر رفتار مخاطره‌آمیز بررسی کنید."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"در صورت وجود مشکل میزان صدا با دستگاه‌های راه دور مثل میزان صدای بلند ناخوشایند یا عدم کنترل صدا، قابلیت میزان صدای کامل بلوتوث را غیرفعال کنید."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"اجازه می‌دهد آهنگ‌های زنگ تلفن در هدست‌های بلوتوث پخش شود"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"ترمینال محلی"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 0e4ecad8c090..6b3953effba9 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Salli Wi-Fi-verkkovierailuskannaus aina"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Mobiilidata aina käytössä"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Laitteistokiihdytyksen yhteyden jakaminen"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Poista yleinen äänenvoimakkuuden säätö käytöstä"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Ota käyttöön kaistalla soitto"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetoothin AVRCP-versio"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Nämä asetukset on tarkoitettu vain kehityskäyttöön, ja ne voivat aiheuttaa haittaa laitteellesi tai sen sovelluksille."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Tarkista USB:n kautta asennetut"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Tarkista ADB:n/ADT:n kautta asennetut sovellukset haitallisen toiminnan varalta."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Bluetoothin yleinen äänenvoimakkuuden säätö poistetaan käytöstä ongelmien välttämiseksi esimerkiksi silloin, kun laitteen äänenvoimakkuus on liian kova tai sitä ei voi säätää."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Salli puhelimen soittoäänten toistaminen Bluetooth-kuulokemikrofoneissa"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Paikallinen pääte"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index cd3defe3b36a..28e41fd7ffea 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Toujours autoriser la détection de réseaux Wi-Fi en itinérance"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Données cellulaires toujours actives"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Accélération matérielle pour le partage de connexion"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Désactiver le volume absolu"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Activer la signalisation intra-bande"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Version du profil Bluetooth AVRCP"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ces paramètres sont en cours de développement. Ils peuvent endommager votre appareil et les applications qui s\'y trouvent, ou provoquer leur dysfonctionnement."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Vérifier les applis via USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Vérifiez que les applications installées par ADB/ADT ne présentent pas de comportement dangereux."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Désactive la fonctionnalité de volume absolu par Bluetooth en cas de problème de volume sur les appareils à distance, par exemple si le volume est trop élevé ou s\'il ne peut pas être contrôlé."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Autoriser la lecture des sonneries du téléphone sur les écouteurs Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
diff --git a/packages/SettingsLib/res/values-fr/arrays.xml b/packages/SettingsLib/res/values-fr/arrays.xml
index 7fd8a934cdb5..aaa0381b0e01 100644
--- a/packages/SettingsLib/res/values-fr/arrays.xml
+++ b/packages/SettingsLib/res/values-fr/arrays.xml
@@ -68,10 +68,26 @@
<item msgid="1913619118958233129">"avrcp15"</item>
<item msgid="7142710449249088270">"avrcp16"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (5254942598247222737) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:4 (2091430979086738145) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (7848030269621918608) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:4 (298198075927343893) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Utiliser sélection système (par défaut)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="5254942598247222737">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2091430979086738145">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ <item msgid="723675059572222462">"Activer les codecs facultatifs"</item>
+ <item msgid="3304843301758635896">"Désactiver les codecs facultatifs"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Utiliser sélection système (par défaut)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="7848030269621918608">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="298198075927343893">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ <item msgid="2209680154067241740">"Activer les codecs facultatifs"</item>
+ <item msgid="741805482892725657">"Désactiver les codecs facultatifs"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="3093023430402746802">"Utiliser sélection système (par défaut)"</item>
<item msgid="8895532488906185219">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 275f6d0b79a4..d7c792028101 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Toujours autoriser la détection de réseaux Wi-Fi en itinérance"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Données mobiles toujours actives"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Accélération matérielle pour le partage de connexion"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Désactiver le volume absolu"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Activer la signalisation intra-bande"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Version Bluetooth AVRCP"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ces paramètres sont en cours de développement. Ils peuvent endommager votre appareil et les applications qui s\'y trouvent, ou provoquer leur dysfonctionnement."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Vérifier les applis via USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Vérifiez que les applications installées par ADB/ADT ne présentent pas de comportement dangereux."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Désactive la fonctionnalité de volume absolu du Bluetooth en cas de problème de volume sur les appareils à distance, par exemple si le volume est trop élevé ou s\'il ne peut pas être contrôlé."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Autoriser la lecture des sonneries du téléphone sur les casques Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 523d5c2e3889..cc6a96cad79d 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permitir sempre buscas de itinerancia da wifi"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Datos móbiles sempre activados"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleración de hardware para conexión compartida"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desactivar volume absoluto"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Activar a función de soar na mesma banda"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versión AVRCP de Bluetooth"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Esta configuración só está destinada á programación. Esta pode provocar que o dispositivo e as aplicacións fallen ou se comporten incorrectamente."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificar aplicacións por USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Comprobar as aplicacións instaladas a través de ADB/ADT para detectar comportamento perigoso."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desactiva a función do volume absoluto do Bluetooth en caso de que se produzan problemas de volume cos dispositivos remotos, como volume demasiado alto ou falta de control."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Permite que os tons de chamada do teléfono se reproduzan nos auriculares Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 8f236d8f9fa9..1de92cd2efa2 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"હંમેશા વાઇ-ફાઇ રોમ સ્કૅન્સને મંજૂરી આપો"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"મોબાઇલ ડેટા હંમેશાં સક્રિય"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"ટિથરિંગ માટે હાર્ડવેર ગતિવૃદ્ધિ"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ચોક્કસ વૉલ્યૂમને અક્ષમ કરો"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"બેંડમાં રિંગ કરવાનું સક્ષમ કરો"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"બ્લૂટૂથ AVRCP સંસ્કરણ"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"આ સેટિંગ્સ ફક્ત વિકાસનાં ઉપયોગ માટે જ હેતુબદ્ધ છે. તે તમારા ઉપકરણ અને તેના પરની એપ્લિકેશન્સનાં ભંગ થવા અથવા ખરાબ વર્તનનું કારણ બની શકે છે."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB પર ઍપ્લિકેશનો ચકાસો"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"હાનિકારક વર્તણૂંક માટે ADB/ADT મારફતે ઇન્સ્ટોલ કરવામાં આવેલી ઍપ્લિકેશનો તપાસો."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"રિમોટ ઉપકરણોમાં વધુ પડતું ઊંચું વૉલ્યૂમ અથવા નિયંત્રણની કમી જેવી વૉલ્યૂમની સમસ્યાઓની સ્થિતિમાં બ્લૂટૂથ ચોક્કસ વૉલ્યૂમ સુવિધાને અક્ષમ કરે છે."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"ફોનની રિંગટોન બ્લૂટૂથ હૅડસેટ પર વાગવાની મંજૂરી આપો"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"સ્થાનિક ટર્મિનલ"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index eddcb564da1b..252be3c13576 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"हमेशा वाई-फ़ाई रोम स्कैन करने दें"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"मोबाइल डेटा हमेशा सक्रिय"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"हार्डवेयर त्‍वरण को टेदर करना"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"पूर्ण वॉल्यूम अक्षम करें"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"इन-बैंड रिंग करना सक्षम करें"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"ब्लूटूथ AVRCP वर्शन"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ये सेटिंग केवल विकास संबंधी उपयोग के प्रयोजन से हैं. वे आपके डिवाइस और उस पर स्‍थित ऐप्स को खराब कर सकती हैं या उनके दुर्व्यवहार का कारण हो सकती हैं."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB पर ऐप की पुष्टि करें"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"नुकसानदेह व्यवहार के लिए ADB/ADT के द्वारा इंस्टॉल किए गए ऐप्स जांचें."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"दूरस्थ डिवाइस के साथ वॉल्यूम की समस्याओं जैसे अस्वीकार्य तेज़ वॉल्यूम या नियंत्रण की कमी की स्थिति में ब्लूटूथ पूर्ण वॉल्यूम सुविधा को अक्षम करता है."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"फ़ोन की रिंगटोन को ब्लूटूथ हेडसेट पर बजने दें"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"स्थानीय टर्मिनल"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 03515b2785cd..3795dde12f15 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Uvijek dopusti slobodno traženje Wi-Fi mreže"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Mobilni podaci uvijek aktivni"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardversko ubrzanje za modemsko povezivanje"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Onemogući apsolutnu glasnoću"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Omogući zvuk zvona unutar pojasne širine"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Verzija AVRCP-a za Bluetooth"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ove su postavke namijenjene samo razvojnim programerima. One mogu uzrokovati kvar ili neželjeno ponašanje vašeg uređaja i aplikacija na njemu."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Potvrdi aplikacije putem USB-a"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Provjerite uzrokuju li aplikacije instalirane putem ADB-a/ADT-a poteškoće."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Onemogućuje Bluetoothovu značajku apsolutne glasnoće ako udaljeni uređaji imaju poteškoća sa zvukom, kao što su, primjerice, neprihvatljiva glasnoća ili nepostojanje kontrole."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Omogući reprodukciju melodija zvona telefona putem Bluetooth slušalica"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokalni terminal"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 1baa5a4f93a4..e22b3ce375fd 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi-roaming ellenőrzésének engedélyezése mindig"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"A mobilhálózati kapcsolat mindig aktív"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Internetmegosztás hardveres gyorsítása"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Abszolút hangerő funkció letiltása"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Sávon belüli csörgetés engedélyezése"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"A Bluetooth AVRCP-verziója"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ezek a beállítások csak fejlesztői használatra szolgálnak. Használatuk esetén eszköze vagy alkalmazásai meghibásodhatnak, illetve nem várt módon viselkedhetnek."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB-n keresztül telepített alkalmazások ellenőrzése"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Az ADB/ADT útján telepített alkalmazások ellenőrzése kártékony viselkedésre."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Letiltja a Bluetooth abszolút hangerő funkcióját a távoli eszközökkel kapcsolatos hangerőproblémák – például elfogadhatatlanul magas vagy nem vezérelhető hangerő – esetén."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"A telefonon lévő csengőhangok Bluetooth-headseteken való lejátszásának engedélyezése"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Helyi végpont"</string>
diff --git a/packages/SettingsLib/res/values-hy/arrays.xml b/packages/SettingsLib/res/values-hy/arrays.xml
index 851227a23c2b..27ea288ea7db 100644
--- a/packages/SettingsLib/res/values-hy/arrays.xml
+++ b/packages/SettingsLib/res/values-hy/arrays.xml
@@ -68,10 +68,26 @@
<item msgid="1913619118958233129">"avrcp15"</item>
<item msgid="7142710449249088270">"avrcp16"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (5254942598247222737) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:4 (2091430979086738145) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (7848030269621918608) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:4 (298198075927343893) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Օգտագործել համակարգի կարգավորումը (կանխադրված)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="5254942598247222737">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> աուդիո"</item>
+ <item msgid="2091430979086738145">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> աուդիո"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ <item msgid="723675059572222462">"Միացնել լրացուցիչ կոդեկները"</item>
+ <item msgid="3304843301758635896">"Անջատել լրացուցիչ կոդեկները"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Օգտագործել համակարգի կարգավորումը (կանխադրված)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="7848030269621918608">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> աուդիո"</item>
+ <item msgid="298198075927343893">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> աուդիո"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ <item msgid="2209680154067241740">"Միացնել լրացուցիչ կոդեկները"</item>
+ <item msgid="741805482892725657">"Անջատել լրացուցիչ կոդեկները"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="3093023430402746802">"Օգտագործել համակարգի կարգավորումը (կանխադրված)"</item>
<item msgid="8895532488906185219">"44,1 կՀց"</item>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 43c292d68a74..6c844b90533c 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Միշտ թույլատրել Wi‑Fi ռոումինգի որոնումը"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Բջջային ինտերնետը միշտ ակտիվ է"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Սարքակազմի արագացման միացում"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Անջատել ձայնի բացարձակ ուժգնությունը"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Միացնել ներխմբային զանգը"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP տարբերակը"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Այս կարգավորումները միայն ծրագրավորման նպատակների համար են նախատեսված: Դրանք կարող են խանգարել ձեր սարքի կամ ծրագրի աշխատանքին:"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Ստուգել հավելվածները USB-ի նկատմամբ"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Ստուգեք տեղադրված հավելվածը ADB/ADT-ի միջոցով կասկածելի աշխատանքի պատճառով:"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Կասեցնում է Bluetooth-ի ձայնի բացարձակ ուժգնության գործառույթը՝ հեռավոր սարքերի հետ ձայնի ուժգնությանը վերաբերող խնդիրներ ունենալու դեպքում (օրինակ՝ երբ ձայնի ուժգնությունն անընդունելի է կամ դրա կառավարումը հնարավոր չէ):"</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Ընձեռել հեռախոսի բոլոր զանգերանգների Bluetooth ականջակալներով նվագարկումը"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Տեղային տերմինալ"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 24a91c27aec7..2838be4ae116 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Selalu izinkan Pemindaian Roaming Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Data seluler selalu aktif"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Akselerasi hardware tethering"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Nonaktifkan volume absolut"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Aktifkan dering in-band"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versi AVRCP Bluetooth"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Setelan ini hanya dimaksudkan untuk penggunaan pengembangan. Setelan dapat menyebabkan perangkat dan aplikasi yang menerapkannya rusak atau tidak berfungsi semestinya."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifikasi aplikasi melalui USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Periksa perilaku membahayakan dalam aplikasi yang terpasang melalui ADB/ADT."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Menonaktifkan fitur volume absolut Bluetooth jika ada masalah volume dengan perangkat jarak jauh, misalnya volume terlalu keras atau kurangnya kontrol."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Izinkan nada dering di ponsel diputar di headset Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal lokal"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 718a862b312c..5db0a3a31791 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Leyfa alltaf reikileit með Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Alltaf kveikt á farsímagögnum"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Vélbúnaðarhröðun fyrir tjóðrun"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Slökkva á samstillingu hljóðstyrks"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Leyfa símtöl á sömu rás"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP-útgáfa"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Þessar stillingar eru einungis ætlaðar í þróunarskyni. Þær geta valdið því að tækið og forrit þess bili eða starfi á rangan hátt."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Staðfesta forrit gegnum USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kanna skaðlega hegðun forrita sem sett eru upp frá ADB/ADT."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Slekkur á samstillingu Bluetooth-hljóðstyrks ef vandamál koma upp með hljóðstyrk hjá fjartengdum tækjum, svo sem of hár hljóðstyrkur eða erfiðleikar við stjórnun."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Leyfa að hringitónar í símanum spilist í Bluetooth-höfuðtólum"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Staðbundin skipanalína"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index f3a7253dbca5..b82dce8252fe 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Consenti sempre scansioni roaming Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Dati mobili sempre attivi"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Tethering accelerazione hardware"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Disattiva volume assoluto"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Attiva suoneria in banda"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versione Bluetooth AVRCP"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Queste impostazioni sono utilizzabili solo a scopo di sviluppo. Possono causare l\'arresto o il comportamento anomalo del dispositivo e delle applicazioni su di esso."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifica app tramite USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Controlla che le app installate tramite ADB/ADT non abbiano un comportamento dannoso."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Consente di disattivare la funzione del volume assoluto Bluetooth in caso di problemi con il volume dei dispositivi remoti, ad esempio un volume troppo alto o la mancanza di controllo."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Consenti la riproduzione delle suonerie del telefono tramite gli auricolari Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminale locale"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index a3f92d016474..d73f4207884a 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"‏התר תמיד סריקות נדידה של Wi‑Fi"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"חבילת הגלישה פעילה תמיד"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"שיפור מהירות באמצעות חומרה לצורך שיתוף אינטרנט בין ניידים"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"השבת עוצמת קול מוחלטת"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"‏הפעל צלצולים בערוץ ה-Bluetooth‏ (in-band ringing)"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"‏Bluetooth גרסה AVRCP"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"הגדרות אלה מיועדות לשימוש בפיתוח בלבד. הן עלולות לגרום למכשיר או לאפליקציות המותקנות בו לקרוס או לפעול באופן לא תקין."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"‏אמת אפליקציות באמצעות USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"‏בדוק אפליקציות שהותקנו באמצעות ADB/ADT לאיתור התנהגות מזיקה."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"‏משבית את תכונת עוצמת הקול המוחלטת ב-Bluetooth במקרה של בעיות בעוצמת הקול במכשירים מרוחקים, כגון עוצמת קול רמה מדי או חוסר שליטה ברמת העוצמה."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"‏הפעלת רינגטונים באוזניות Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"מסוף מקומי"</string>
diff --git a/packages/SettingsLib/res/values-ja/arrays.xml b/packages/SettingsLib/res/values-ja/arrays.xml
index 4f9c2fb3d6dc..1c7d2e96cbb5 100644
--- a/packages/SettingsLib/res/values-ja/arrays.xml
+++ b/packages/SettingsLib/res/values-ja/arrays.xml
@@ -68,10 +68,26 @@
<item msgid="1913619118958233129">"avrcp15"</item>
<item msgid="7142710449249088270">"avrcp16"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (5254942598247222737) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:4 (2091430979086738145) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (7848030269621918608) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:4 (298198075927343893) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"システムの選択(デフォルト)を使用"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="5254942598247222737">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> オーディオ"</item>
+ <item msgid="2091430979086738145">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> オーディオ"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ <item msgid="723675059572222462">"オプションのコーデックの有効化"</item>
+ <item msgid="3304843301758635896">"オプションのコーデックの無効化"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"システムの選択(デフォルト)を使用"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="7848030269621918608">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> オーディオ"</item>
+ <item msgid="298198075927343893">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> オーディオ"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ <item msgid="2209680154067241740">"オプションのコーデックを有効にします"</item>
+ <item msgid="741805482892725657">"オプションのコーデックを無効にします"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="3093023430402746802">"システムの選択(デフォルト)を使用"</item>
<item msgid="8895532488906185219">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 597312471199..4a574952ed9f 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fiローミングスキャンを常に許可する"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"モバイルデータを常に ON にする"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"テザリング時のハードウェア アクセラレーション"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"絶対音量を無効にする"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"インバンド リンギングを有効にする"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP バージョン"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"これらの設定は開発専用に設計されています。そのため端末や端末上のアプリが故障したり正常に動作しなくなったりするおそれがあります。"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB経由のアプリを確認"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT経由でインストールされたアプリに不正な動作がないかを確認する"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"リモート端末で音量に関する問題(音量が大きすぎる、制御できないなど)が発生した場合に、Bluetooth の絶対音量の機能を無効にする。"</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"スマートフォンの着信音が Bluetooth ヘッドセットで再生されることを許可する"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"ローカルターミナル"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index b879e999a35f..cbacb28c58d5 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi Roam სკანირების მუდამ დაშვება"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"მობილური ინტერნეტის ყოველთვის გააქტიურება"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"ტეტერინგის აპარატურული აჩქარება"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ხმის აბსოლუტური სიძლიერის გათიშვა"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"ზოლსშიდა დარეკვის ჩართვა"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth-ის AVRCP-ის ვერსია"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ამ პარამეტრების გამოყენება დასაშვებია მხოლოდ დეველოპერული მიზნებით. მათმა გამოყენებამ შეიძლება გამოიწვიოს თქვენი მოწყობილობის და მისი აპლიკაციების დაზიანება ან გაუმართავი მუშაობა."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"აპლიკაციების USB-ს საშუალებით შემოწმება"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"შეამოწმეთ, რამდენად უსაფრთხოა ADB/ADT-ის საშუალებით ინსტალირებული აპლიკაციები."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"გათიშავს Bluetooth-ის ხმის აბსოლუტური სიძლიერის ფუნქციას დისტანციურ მოწყობილობებზე ხმასთან დაკავშირებული ისეთი პრობლემების არსებობის შემთხვევაში, როგორიცაა ხმის დაუშვებლად მაღალი სიძლიერე ან კონტროლის შეუძლებლობა."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"ტელეფონის ზარების Bluetooth-ყურსაცვამებზე დაკვრის დაშვება"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"ადგილობრივი ტერმინალი"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index c9efc46e4c78..354e0b5ddb9b 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi роумингін іздеулерге әрқашан рұқсат ету"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Мобильдік деректер әрқашан қосулы"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Тетерингтің аппараттық жеделдетуі"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Абсолютті дыбыс деңгейін өшіру"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Ішкі жолақтағы шылдырлауды қосу"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP нұсқасы"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Бұл параметрлер жетілдіру мақсатында ғана қолданылады. Олар құрылғыңыз бен қолданбаларыңыздың бұзылуына немесе әдеттен тыс әрекеттерге себеп болуы мүмкін."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB арқылы орнатылған қолданбаларды растау"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT арқылы орнатылған қолданбалардың залалды болмауын тексеру."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Қолайсыз қатты дыбыс деңгейі немесе басқарудың болмауы сияқты қашықтағы құрылғыларда дыбыс деңгейімен мәселелер жағдайында Bluetooth абсолютті дыбыс деңгейі функциясын өшіреді."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Телефондағы қоңырау әуендерінің Bluetooth құлақаспабында ойнатылуына мүмкіндік беру"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Жергілікті терминал"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 9b868fb3fb95..f9800669cf63 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"តែងតែ​អនុញ្ញាត​​​ការវិភាគ​រ៉ូម​វ៉ាយហ្វាយ"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"ទិន្នន័យទូរសព្ទចល័តដំណើរការជានិច្ច"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"ការ​បង្កើនល្បឿន​ផ្នែករឹងសម្រាប់​ការភ្ជាប់"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"បិទកម្រិតសំឡេងលឺខ្លាំង"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"បើក​ការ​រោទ៍​ក្នុងបណ្តាញ"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"កំណែប្ល៊ូធូស AVRCP"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ការ​កំណត់​ទាំង​នេះ​សម្រាប់​តែ​ការ​ប្រើ​ក្នុង​ការ​អភិវឌ្ឍ​ប៉ុណ្ណោះ។ ពួក​វា​អាច​ធ្វើ​ឲ្យ​ឧបករណ៍ និង​កម្មវិធី​របស់​អ្នក​ខូច ឬ​ដំណើរ​មិន​ត្រឹមត្រូវ។"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"ផ្ទៀងផ្ទាត់​កម្មវិធី​តាម​យូអេសប៊ី"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ពិនិត្យ​កម្មវិធី​បាន​ដំឡើង​តាម​រយៈ ADB/ADT សម្រាប់​ឥរិយាបថ​ដែល​គ្រោះ​ថ្នាក់។"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"បិទលក្ខណៈពិសេសកម្រិតសំឡេងលឺខ្លាំងពេលភ្ជាប់ប៊្លូធូសក្នុងករណីមានបញ្ហាជាមួយឧបករណ៍បញ្ជាពីចម្ងាយ ដូចជាកម្រិតសំឡេងលឺខ្លាំងដែលមិនអាចទទួលយកបាន ឬខ្វះការគ្រប់គ្រង។"</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"អនុញ្ញាត​ឲ្យ​សំឡេង​រោទ៍​នៅ​លើ​ទូរសព្ទ​បញ្ចេញសំឡេង​តាម​រយៈ​កាស​ប្ល៊ូធូស"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"ស្ថានីយ​មូលដ្ឋាន"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index b942e3a81cba..40dea01a0e6f 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"ವೈ-ಫೈ ರೋಮ್ ಸ್ಕ್ಯಾನ್‌ಗಳನ್ನು ಯಾವಾಗಲೂ ಅನುಮತಿಸಿ"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"ಮೊಬೈಲ್ ಡೇಟಾ ಯಾವಾಗಲೂ ಸಕ್ರಿಯ"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"ಹಾರ್ಡ್‌ವೇರ್‌ನ ವೇಗವರ್ಧನೆಯನ್ನು ಟೆಥರಿಂಗ್ ಮಾಡಿ"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ಸಂಪೂರ್ಣ ವಾಲ್ಯೂಮ್‌ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"ಇನ್ ಬ್ಯಾಂಡ್ ರಿಂಗಿಂಗ್ ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"ಬ್ಲೂಟೂತ್ AVRCP ಆವೃತ್ತಿ"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ಈ ಸೆಟ್ಟಿಂಗ್‌ಗಳು ಅಭಿವೃದ್ಧಿಯ ಬಳಕೆಗೆ ಮಾತ್ರ. ಅವುಗಳು ನಿಮ್ಮ ಸಾಧನ ಮತ್ತು ಅಪ್ಲಿಕೇಶನ್‌‌ಗಳಿಗೆ ಧಕ್ಕೆ ಮಾಡಬಹುದು ಅಥವಾ ಅವು ಸರಿಯಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸದಿರುವಂತೆ ಮಾಡಬಹುದು."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB ಮೂಲಕ ಆಪ್‌ ಪರಿಶೀಲಿಸಿ"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ಹಾನಿಮಾಡುವಂತಹ ವರ್ತನೆಗಾಗಿ ADB/ADT ಮೂಲಕ ಸ್ಥಾಪಿಸಲಾದ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸಿ."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ರಿಮೋಟ್ ಸಾಧನಗಳೊಂದಿಗೆ ಒಪ್ಪಲಾಗದ ಜೋರಾದ ವಾಲ್ಯೂಮ್ ಅಥವಾ ನಿಯಂತ್ರಣದ ಕೊರತೆಯಂತಹ ವಾಲ್ಯೂಮ್ ಸಮಸ್ಯೆಗಳಂತಹ ಸಂದರ್ಭದಲ್ಲಿ ಬ್ಲೂಟೂತ್ ಸಂಪೂರ್ಣ ವಾಲ್ಯೂಮ್ ವೈಶಿಷ್ಟ್ಯವನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಬಹುದು."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"ಫೋನ್‌ನ ರಿಂಗ್‌ಟೋನ್‌ಗಳನ್ನು ಬ್ಲೂಟೂತ್ ಹೆಡ್‌ಸೆಟ್‌ಗಳಲ್ಲಿ ಪ್ಲೇ ಮಾಡಲು ಅನುಮತಿ ನೀಡಿ"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"ಸ್ಥಳೀಯ ಟರ್ಮಿನಲ್"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 6b8b00461d2b..5c89d8b7a5f5 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi 로밍 스캔 항상 허용"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"항상 모바일 데이터 활성화"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"테더링 하드웨어 가속"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"절대 볼륨 사용 안함"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"대역 내 벨소리 사용 설정"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"블루투스 AVRCP 버전"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"이 설정은 개발자용으로만 설계되었습니다. 이 설정을 사용하면 기기 및 애플리케이션에 예기치 않은 중단이나 오류가 발생할 수 있습니다."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB를 통해 설치된 앱 확인"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT을 통해 설치된 앱에 유해한 동작이 있는지 확인"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"참기 어려울 정도로 볼륨이 크거나 제어가 되지 않는 등 원격 기기에서 볼륨 문제가 발생할 경우 블루투스 절대 볼륨 기능을 사용 중지합니다."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"휴대전화의 벨소리가 블루투스 헤드셋에서 재생되도록 허용"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"로컬 터미널"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index ab880b8ff449..6680d07b1db0 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi-Fi Роуминг Скандоо мүмкүнчүлүгүнө ар дайым уруксат берилсин"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Мобилдик Интернет иштей берсин"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Тетерингдин иштешин тездетүү"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Үндүн абсолюттук деңгээли өчүрүлсүн"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Канал аралык чалууну иштетүү"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP версиясы"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Бул орнотуулар өндүрүүчүлөр үчүн гана берилген. Булар түзмөгүңүздүн колдонмолорун бузулушуна же туура эмес иштешине алып келиши мүмкүн."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB аркылуу келген колдонмолорду ырастоо"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT аркылуу орнотулган колдонмолорду зыянкечтикке текшерүү."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Алыскы түзмөктөр өтө катуу добуш чыгарып же көзөмөлдөнбөй жатса Bluetooth \"Үндүн абсолюттук деңгээли\" функциясын өчүрөт."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Телефондогу рингтондор Bluetooth гарнитурасында ойнотулсун"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Жергиликтүү терминал"</string>
diff --git a/packages/SettingsLib/res/values-lo/arrays.xml b/packages/SettingsLib/res/values-lo/arrays.xml
index 72771b7efa1d..5b546ff241c9 100644
--- a/packages/SettingsLib/res/values-lo/arrays.xml
+++ b/packages/SettingsLib/res/values-lo/arrays.xml
@@ -68,10 +68,26 @@
<item msgid="1913619118958233129">"avrcp15"</item>
<item msgid="7142710449249088270">"avrcp16"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (5254942598247222737) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:4 (2091430979086738145) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (7848030269621918608) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:4 (298198075927343893) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Use System Selection (Default)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="5254942598247222737">"ສຽງ <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2091430979086738145">"ສຽງ <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ <item msgid="723675059572222462">"ເປີດໃຊ້ Codecs ແບບເສີມ"</item>
+ <item msgid="3304843301758635896">"ປິດການໃຊ້ Codecs ແບບເສີມ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Use System Selection (Default)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="7848030269621918608">"ສຽງ <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="298198075927343893">"ສຽງ <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ <item msgid="2209680154067241740">"ເປີດໃຊ້ Codecs ແບບເສີມ"</item>
+ <item msgid="741805482892725657">"ປິດການໃຊ້ Codecs ແບບເສີມ"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="3093023430402746802">"Use System Selection (Default)"</item>
<item msgid="8895532488906185219">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 83bb4b74ac64..25809e14bbd1 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"ອະ​ນຸ​ຍາດ​ການ​ສະ​ແກນ​ການ​ໂຣມ Wi‑Fi ​ສະ​ເໝີ"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"ເປີດໃຊ້ອິນເຕີເນັດມືຖືຕະຫຼອດເວລາ"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"ເປີດໃຊ້ການເລັ່ງຄວາມໄວດ້ວຍຮາດແວ"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ປິດໃຊ້ລະດັບສຽງສົມບູນ"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"ເປີດສຽງເຕືອນແບບອິນແບນ"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"ເວີຊັນ Bluetooth AVRCP"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ການ​ຕັ້ງຄ່າ​ເຫຼົ່ານີ້​ແມ່ນ​ມີ​ຈຸດປະສົງ​ເພື່ອ​ການ​ພັດທະນາ​ເທົ່ານັ້ນ. ພວກ​ມັນ​ສາມາດ​ເຮັດ​ໃຫ້​ອຸປະກອນ ແລະ​ແອັບພລິເຄຊັນ​ຂອງ​ທ່ານ​ຢຸດ​ເຮັດ​ວຽກ ຫຼື​ເຮັດ​ວຽກ​ຜິດປົກກະຕິ​ໄດ້."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"ຢືນຢັນແອັບຯຜ່ານທາງ USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ກວດສອບແອັບຯທີ່ຕິດຕັ້ງແລ້ວຜ່ານທາງ ADB/ADT ເພື່ອກວດຫາພຶດຕິກຳທີ່ເປັນອັນຕະລາຍ."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ປິດໃຊ້ຄຸນສົມບັດລະດັບສຽງສົມບູນຂອງ Bluetooth ໃນກໍລະນີເກີດບັນຫາລະດັບສຽງສົມບູນກັບອຸປະກອນທາງໄກ ເຊັ່ນວ່າ ລະດັບສຽງດັງເກີນຍອມຮັບໄດ້ ຫຼື ຄວບຄຸມບໍ່ໄດ້."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"ເປີດໃຫ້ສຽງຣິງໂທນຢູ່ໂທລະສັບດັງໃນຫູຟັງ Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal ໃນໂຕເຄື່ອງ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 4b60d5a40636..5c8c5db5f26e 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Visada leisti „Wi-Fi“ tarptiklinio ryšio nuskaitymą"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Mobiliojo ryšio duomenys visada suaktyvinti"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Įrenginio kaip modemo naudojimo aparatinės įrangos spartinimas"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Išjungti didžiausią garsą"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Įgalinti diapazono skambėjimą"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"„Bluetooth“ AVRCP versija"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Šie nustatymai skirti tik kūrėjams. Nustačius juos įrenginys ir jame naudojamos programos gali nustoti veikti arba veikti netinkamai."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Patvirtinti progr. naudojant USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Patikrinkite, ar programų, įdiegtų naudojant ADB / ADT, veikimas nėra žalingas."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Išjungiama „Bluetooth“ didžiausio garso funkcija, jei naudojant nuotolinio valdymo įrenginius kyla problemų dėl garso, pvz., garsas yra per didelis arba jo negalima tinkamai valdyti."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Leisti telefono skambėjimo tonus per „Bluetooth“ ausines"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Vietinis terminalas"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 69be078865bd..089862479d4e 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Vienmēr atļaut Wi‑Fi meklēšanu"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Vienmēr aktīvs mobilo datu savienojums"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Paātrināta aparatūras darbība piesaistei"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Atspējot absolūto skaļumu"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Iespējot iekšjoslas zvanīšanu"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP versija"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Šie iestatījumi ir paredzēti tikai izstrādei. To dēļ var tikt pārtraukta vai traucēta ierīces un lietojumprogrammu darbība."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificēt, ja instalētas no USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Pārbaudīt, vai lietotņu, kuru instalēšanai izmantots ADB/ADT, darbība nav kaitīga."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Atspējo Bluetooth absolūtā skaļuma funkciju skaļuma problēmu gadījumiem attālajās ierīcēs, piemēram, ja ir nepieņemami liels skaļums vai nav iespējas kontrolēt skaļumu."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Atļaut tālrunī esošo zvana signālu atskaņošanu Bluetooth austiņās"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Vietējā beigu lietotne"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index f4c4754c2f61..8377fd57e700 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -144,7 +144,7 @@
<string name="tts_status_not_supported" msgid="4491154212762472495">"<xliff:g id="LOCALE">%1$s</xliff:g> не е поддржано"</string>
<string name="tts_status_checking" msgid="5339150797940483592">"Се проверува..."</string>
<string name="tts_engine_settings_title" msgid="3499112142425680334">"Поставки на <xliff:g id="TTS_ENGINE_NAME">%s</xliff:g>"</string>
- <string name="tts_engine_settings_button" msgid="1030512042040722285">"Стартувај подесувања на софтвер"</string>
+ <string name="tts_engine_settings_button" msgid="1030512042040722285">"Стартувај поставки на софтвер"</string>
<string name="tts_engine_preference_section_title" msgid="448294500990971413">"Претпочитан софтвер"</string>
<string name="tts_general_section_title" msgid="4402572014604490502">"Општо"</string>
<string name="tts_reset_speech_pitch_title" msgid="5789394019544785915">"Ресетирајте ја висината на изговорот"</string>
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Секогаш дозволувај Wi‑Fi скенирање во роаминг"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Мобилниот интернет е секогаш активен"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Хардверско забрзување за врзување"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Оневозможете апсолутна јачина на звук"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Овозможете ѕвонење во појас"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Верзија Bluetooth AVRCP"</string>
@@ -228,10 +230,12 @@
<string name="adb_warning_title" msgid="6234463310896563253">"Овозможи отстранување грешки на USB?"</string>
<string name="adb_warning_message" msgid="7316799925425402244">"Отстранувањето грешки на USB е наменето само за целите на развој. Користете го за копирање податоци меѓу вашиот компјутер и вашиот уред, за инсталирање апликации на вашиот уред без известување и за читање евиденција на податоци."</string>
<string name="adb_keys_warning_message" msgid="5659849457135841625">"Отповикај пристап кон отстранување грешка од USB од сите претходно овластени компјутери?"</string>
- <string name="dev_settings_warning_title" msgid="7244607768088540165">"Дозволи подесувања за развој?"</string>
- <string name="dev_settings_warning_message" msgid="2298337781139097964">"Овие подесувања се наменети само за употреба за развој. Тие може да предизвикаат уредот и апликациите во него да се расипат или да се однесуваат необично."</string>
+ <string name="dev_settings_warning_title" msgid="7244607768088540165">"Дозволи поставки за развој?"</string>
+ <string name="dev_settings_warning_message" msgid="2298337781139097964">"Овие поставки се наменети само за употреба за развој. Тие може да предизвикаат уредот и апликациите во него да се расипат или да се однесуваат необично."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Потврди апликации преку USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Провери апликации инсталирани преку ADB/ADT за штетно однесување."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Ја оневозможува карактеристиката за апсолутна јачина на звук преку Bluetooth во случај кога ќе настанат проблеми со далечинските уреди, како на пр., неприфатливо силен звук или недоволна контрола."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Дозволи мелодиите на телефонот да се пуштаат на Bluetooth слушалките"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Локален терминал"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index d93916f705ab..63704f47bfa0 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"എപ്പോഴും വൈഫൈ റോം സ്‌‌കാൻ അനുവദിക്കൂ"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"മൊബൈൽ ഡാറ്റ എല്ലായ്‌പ്പോഴും സജീവം"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"ടെതറിംഗ് ഹാർഡ്‌വെയർ ത്വരിതപ്പെടുത്തൽ"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"അബ്‌സൊല്യൂട്ട് വോളിയം പ്രവർത്തനരഹിതമാക്കുക"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"ഇൻ-ബാൻഡ് റിംഗുചെയ്യൽ പ്രവർത്തനക്ഷമമാക്കുക"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP പതിപ്പ്"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ഈ ക്രമീകരണങ്ങൾ വികസന ഉപയോഗത്തിന് മാത്രമായുള്ളതാണ്. അവ നിങ്ങളുടെ ഉപകരണവും അതിലെ അപ്ലിക്കേഷനുകളും തകരാറിലാക്കുന്നതിനോ തെറ്റായി പ്രവർത്തിക്കുന്നതിനോ ഇടയാക്കാം."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB വഴി ആപ്സ് പരിശോധിച്ചുറപ്പിക്കൂ"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"കേടാക്കുന്ന പ്രവർത്തനരീതിയുള്ള ADB/ADT വഴി ഇൻസ്റ്റാളുചെയ്‌ത അപ്ലിക്കേഷനുകൾ പരിശോധിക്കുക."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"അസ്വീകാര്യമായ തരത്തിൽ ഉയർന്ന വോളിയമോ ശബ്ദ നിയന്ത്രണത്തിന്റെ അഭാവമോ പോലെ, വിദൂര ഉപകരണങ്ങളുമായി ബന്ധപ്പെട്ട വോളിയം പ്രശ്നങ്ങൾ ഉണ്ടാകുന്ന സാഹചര്യത്തിൽ, Bluetooth അബ്‌സൊല്യൂട്ട് വോളിയം ഫീച്ചർ പ്രവർത്തനരഹിതമാക്കുന്നു."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"ഫോണിലെ റിംഗ്‌ടോണുകൾ Bluetooth ഹെഡ്‌സെറ്റുകളിൽ പ്ലേ ചെയ്യാനായി അനുവദിക്കുക"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"പ്രാദേശിക ടെർമിനൽ"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index fd79b4131acb..4da11e564f3b 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi Роум сканыг байнга зөвшөөрөх"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Мобайл дата байнга идэвхтэй"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Модем болгох хардвер хурдасгуур"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Үнэмлэхүй дууны түвшинг идэвхгүй болгох"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Сүлжээний хонхны аяыг идэвхжүүлэх"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP хувилбар"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Эдгээр тохиргоо нь зөвхөн хөгжүүлэлтэд ашиглах зорилготой. Эдгээр нь таны төхөөрөмж буюу түүн дээрх аппликейшнүүдийг эвдрэх, буруу ажиллах шалтгаан нь болж болно."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Апп-г USB-р тулгах"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT-р суулгасан апп-уудыг хорлонтой авиртай эсэхийг шалгах."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Хэт чанга дуугаралт эсвэл муу тохиргоо зэрэг алсын зайн төхөөрөмжийн дуугаралттай холбоотой асуудлын үед Bluetooth-ийн үнэмлэхүй дууны түвшинг идэвхгүй болго."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Утасны хонхны аяыг Bluetooth чихэвчээр тоглуулахыг зөвшөөрөх"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Локал терминал"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 0b2ad7452eb6..7cb750983612 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"वाय-फाय रोम स्‍कॅनला नेहमी अनुमती द्या"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"मोबाइल डेटा नेहमी सक्रिय"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"टेदरिंग हार्डवेअर प्रवेग"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"संपूर्ण आवाज अक्षम करा"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"इन-बँड रिंगिंग सक्षम करा"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"ब्लूटूथ AVRCP आवृत्ती"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"या सेटिंग्जचा हेतू फक्त विकास वापरासाठी आहे. त्यामुळे तुमचे डीव्हाइस आणि त्यावरील अॅप्लिकेशन ब्रेक होऊ शकतात किंवा नेहमीपेक्षा वेगळे वर्तन करू शकतात."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB वर अॅप्स पडताळून पाहा"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"हानिकारक वर्तनासाठी ADB/ADT द्वारे इंस्टॉल अॅप्स तपासा."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"दूरस्थ डीव्हाइसमध्ये सहन न होणारा मोठा आवाज किंवा नियंत्रणचा अभाव यासारखी आवाजाची समस्या असल्यास ब्लूटूथ संपूर्ण आवाज वैशिष्ट्य अक्षम करते."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"फोनवरील रिंगटोन ब्लूटूथ हेडसेटवर वाजू द्या"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"स्थानिक टर्मिनल"</string>
@@ -380,7 +384,7 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"सानुकूल करा (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"मदत आणि अभिप्राय"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"मेनू"</string>
- <string name="retail_demo_reset_message" msgid="118771671364131297">"डेमो मोडमध्ये फॅक्टरी रीसेट करण्यासाठी पासवर्ड एंटर करा"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"डेमो मोडमध्ये फॅक्टरी रीसेट करण्यासाठी पासवर्ड प्रविष्ट करा"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"पुढील"</string>
<string name="retail_demo_reset_title" msgid="696589204029930100">"संकेतशब्द आवश्यक"</string>
<string name="active_input_method_subtypes" msgid="3596398805424733238">"सक्रिय इनपुट पद्धती"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 0310185a7f39..e3a86f7bbb66 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Sentiasa benarkan Imbasan Perayauan Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Data mudah alih sentiasa aktif"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Pecutan perkakasan penambatan"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Lumpuhkan kelantangan mutlak"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Dayakan dering dalam jalur"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versi AVRCP Bluetooth"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Tetapan ini adalah untuk penggunaan pembangunan sahaja. Peranti dan aplikasi yang terdapat padanya boleh rosak atau tidak berfungsi dengan betul."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Sahkan apl melalui USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Semak apl yang dipasang melalui ADB/ADT untuk tingkah laku yang berbahaya."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Lumpuhkan ciri kelantangan mutlak Bluetooth dalam kes isu kelantangan menggunakan peranti kawalan jauh seperti kelantangan yang sangat kuat atau tidak dapat mengawal."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Benarkan nada dering pada telefon dimainkan pada set kepala Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal setempat"</string>
diff --git a/packages/SettingsLib/res/values-my/arrays.xml b/packages/SettingsLib/res/values-my/arrays.xml
index 1f2fec46c76a..750c0420db6f 100644
--- a/packages/SettingsLib/res/values-my/arrays.xml
+++ b/packages/SettingsLib/res/values-my/arrays.xml
@@ -68,10 +68,26 @@
<item msgid="1913619118958233129">"avrcp15"</item>
<item msgid="7142710449249088270">"avrcp16"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (5254942598247222737) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:4 (2091430979086738145) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (7848030269621918608) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:4 (298198075927343893) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"စနစ်ရွေးချယ်မှုကို အသုံးပြုပါ (မူရင်း)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="5254942598247222737">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> အသံ"</item>
+ <item msgid="2091430979086738145">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> အသံ"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ <item msgid="723675059572222462">"စိတ်ကြိုက်ထည့်သွင်းနိုင်သော ကိုးဒက်ခ်များကို ဖွင့်ပါ"</item>
+ <item msgid="3304843301758635896">"စိတ်ကြိုက်ထည့်သွင်းနိုင်သော ကိုးဒက်ခ်များကို ပိတ်ပါ"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"စနစ်ရွေးချယ်မှုကို အသုံးပြုပါ (မူရင်း)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="7848030269621918608">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> အသံ"</item>
+ <item msgid="298198075927343893">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> အသံ"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ <item msgid="2209680154067241740">"စိတ်ကြိုက်ထည့်သွင်းနိုင်သော ကိုးဒက်ခ်များကို ဖွင့်ပါ"</item>
+ <item msgid="741805482892725657">"စိတ်ကြိုက်ထည့်သွင်းနိုင်သော ကိုးဒက်ခ်များကို ပိတ်ပါ"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="3093023430402746802">"စနစ်ရွေးချယ်မှုကို အသုံးပြုပါ (မူရင်း)"</item>
<item msgid="8895532488906185219">"၄၄.၁ kHz"</item>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 8610140d5687..ebbb7df70803 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi ရွမ်းရှာဖွေမှုကို အမြဲတမ်း ခွင့်ပြုမည်"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"မိုဘိုင်းဒေတာကို အမြဲဖွင့်ထားရန်"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"ဖုန်းကို မိုဒမ်အဖြစ်အသုံးပြုမှု စက်ပစ္စည်းဖြင့် အရှိန်မြှင့်တင်ခြင်း"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ပကတိ အသံနှုန်း သတ်မှတ်ချက် ပိတ်ရန်"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"သတ်မှတ်ထားသည့်ဖုန်းမြည်သံကို အသုံးပြုခြင်းအား ဖွင့်ရန်"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"ဘလူးတုသ် AVRCP ဗားရှင်း"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ဤဆက်တင်းများကို တည်ဆောက်ပြုပြင်ရာတွင် သုံးရန်အတွက်သာ ရည်ရွယ်သည်။ ၎င်းတို့သည် သင်၏စက်နှင့် အပလီကေးရှင်းများကို ရပ်စေခြင်း သို့ လုပ်ဆောင်ချက်မမှန်ကန်ခြင်းများ ဖြစ်ပေါ်စေနိုင်သည်။"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USBပေါ်မှ အပလီကေးရှင်းများကို အတည်ပြုစိစစ်ရန်"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT မှတဆင့် ထည့်သွင်းသော အပလီကေးရှင်းများကို အန္တရာယ်ဖြစ်နိုင်ခြင်း ရှိမရှိ စစ်ဆေးရန်။"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ချိတ်ဆက်ထားသည့် ကိရိယာတွင် လက်မခံနိုင်လောက်အောင် ဆူညံ သို့မဟုတ် ထိန်းညှိမရနိုင်သော အသံပိုင်းပြဿနာ ရှိခဲ့လျှင် ဘလူးတုသ် ပကတိ အသံနှုန်းကို ပိတ်ပါ။"</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"ဖုန်းတွင်းရှိ ဖုန်းမြည်သံများကို ဘလူးတုသ် မိုက်ခွက်ပါနားကြပ်တွင် ဖွင့်ခွင့်ပြုရန်"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"လိုကယ်တာမီနယ်"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index de6284da2502..3f82a0536b75 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Tillat alltid skanning for Wi-Fi-roaming"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Mobildata er alltid aktiv"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Maskinvareakselerasjon for internettdeling"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Slå av funksjonen for absolutt volum"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Slå på innenbåndsringing"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP-versjon"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Disse innstillingene er bare beregnet for bruk under programutvikling. De kan forårsake problemer med enheten din og tilhørende apper."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Bekreft apper via USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Sjekk apper som er installert via ADB/ADT for skadelig adferd."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Slår av funksjonen for absolutt volum via Bluetooth i tilfelle det oppstår volumrelaterte problemer med eksterne enheter, for eksempel uakseptabelt høyt volum eller mangel på kontroll."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Tillater at ringelyder på telefonen spilles av på Bluetooth-hodetelefoner"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokal terminal"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 6d161bc150c8..1b8f47086b33 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi-Fi घुम्ने स्क्यान गर्न सधैँ अनुमति दिनुहोस्"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"मोबाइल डेटा सधैँ सक्रिय राख्नुहोस्"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"टेदरिङको लागि हार्डवेयरको प्रवेग"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"निरपेक्ष आवाज असक्षम गर्नुहोस्"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"इन-ब्यान्ड घन्टी बज्ने सुविधालाई सक्षम पार्नुहोस्"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"ब्लुटुथको AVRCP संस्करण"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"यी सेटिङहरू केवल विकास प्रयोगको लागि विचार गरिएको हो। तिनीहरूले तपाईंको उपकरण र अनुप्रयोगहरूलाई विच्छेदन गर्न वा दुर्व्यवहार गर्न सक्दछ।"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB मा अनुप्रयोगहरू रुजु गर्नुहोस्"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"हानिकारक व्यवहारको लागि ADB/ADT को माध्यमबाट स्थापित अनुप्रयोगहरूको जाँच गर्नुहोस्।"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"रिमोट यन्त्रहरूमा अस्वीकार्य चर्को आवाज वा नियन्त्रणमा कमी जस्ता आवाज सम्बन्धी समस्याहरूको अवस्थामा ब्लुटुथ निरपेक्ष आवाज सुविधालाई असक्षम गराउँछ।"</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"उक्त फोनमा भएका रिङटोनहरूलाई ब्लुटुथका हेडसेटहरूमा प्ले गर्न दिनुहोस्"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"स्थानीय टर्मिनल"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index c4f18705ee69..93291a04572a 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Altijd roamingscans voor wifi toestaan"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Mobiele data altijd actief"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardwareversnelling voor tethering"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Absoluut volume uitschakelen"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"In-band bellen inschakelen"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth-AVRCP-versie"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Deze instellingen zijn uitsluitend bedoeld voor ontwikkelingsgebruik. Je apparaat en apps kunnen hierdoor vastlopen of anders reageren."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Apps verifiëren via USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Apps die zijn geïnstalleerd via ADB/ADT, controleren op schadelijk gedrag"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Hiermee wordt de functie voor absoluut volume van Bluetooth uitgeschakeld in geval van volumeproblemen met externe apparaten, zoals een onacceptabel hoog volume of geen volumeregeling."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Toestaan dat beltonen worden afgespeeld op Bluetooth-headsets"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokale terminal"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index a6f168f2c8fe..95a9cce6999f 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"ਹਮੇਸ਼ਾਂ ਵਾਈ‑ਫਾਈ ਰੋਮ ਸਕੈਨਾਂ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"ਮੋਬਾਈਲ ਡਾਟਾ ਹਮੇਸ਼ਾਂ ਕਿਰਿਆਸ਼ੀਲ"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"ਟੈਦਰਿੰਗ ਹਾਰਡਵੇਅਰ ਐਕਸੇਲਰੇਸ਼ਨ"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ਪੂਰਨ ਵੌਲਿਊਮ ਨੂੰ ਅਯੋਗ ਬਣਾਓ"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"ਇਨ-ਬੈਂਡ ਘੰਟੀ ਵੱਜਣ ਨੂੰ ਯੋਗ ਬਣਾਓ"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"ਬਲੂਟੁੱਥ AVRCP ਰੂਪ"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ਇਹ ਸੈਟਿੰਗਾਂ ਕੇਵਲ ਵਿਕਾਸਕਾਰ ਦੀ ਵਰਤੋਂ ਲਈ ਹਨ। ਇਹ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਅਤੇ ਇਸਤੇ ਮੌਜੂਦ ਐਪਲੀਕੇਸ਼ਨ ਨੂੰ ਬ੍ਰੇਕ ਕਰਨ ਜਾਂ ਦੁਰਵਿਵਹਾਰ ਕਰਨ ਦਾ ਕਾਰਨ ਬਣ ਸਕਦੇ ਹਨ।"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB ਤੇ ਐਪਸ ਨੂੰ ਪ੍ਰਮਾਣਿਤ ਕਰੋ"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ਹਾਨੀਕਾਰਕ ਵਿਵਹਾਰ ਲਈ ADB/ADT ਰਾਹੀਂ ਇੰਸਟੌਲ ਕੀਤੇ ਐਪਸ ਦੀ ਜਾਂਚ ਕਰੋ।"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ਰਿਮੋਟ ਡੀਵਾਈਸਾਂ ਨਾਲ ਵੌਲਿਊਮ ਸਮੱਸਿਆਵਾਂ ਜਿਵੇਂ ਕਿ ਨਾ ਪਸੰਦ ਕੀਤੀ ਜਾਣ ਵਾਲੀ ਉੱਚੀ ਵੌਲਿਊਮ ਜਾਂ ਕੰਟਰੋਲ ਦੀ ਕਮੀ ਵਰਗੀ ਹਾਲਤ ਵਿੱਚ ਬਲੂਟੁੱਥ ਪੂਰਨ ਵੌਲਿਊਮ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਅਯੋਗ ਬਣਾਉਂਦਾ ਹੈ।"</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"ਤੁਹਾਡੇ ਫ਼ੋਨ ਦੀਆਂ ਰਿੰਗਟੋਨਾਂ ਨੂੰ ਬਲੂਟੁੱਥ ਹੈੱਡਸੈੱਟਾਂ \'ਤੇ ਚਲਾਉਣ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"ਸਥਾਨਕ ਟਰਮੀਨਲ"</string>
@@ -292,7 +296,7 @@
<string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"ਹਰੇਕ ਗਤੀਵਿਧੀ ਨੂੰ ਨਸ਼ਟ ਕਰੋ ਜਿਵੇਂ ਹੀ ਉਪਭੋਗਤਾ ਇਸਨੂੰ ਛੱਡ ਦੇਵੇ"</string>
<string name="app_process_limit_title" msgid="4280600650253107163">"ਪਿਛੋਕੜ ਪ੍ਰਕਿਰਿਆ ਸੀਮਾ"</string>
<string name="show_all_anrs" msgid="28462979638729082">"ਸਾਰੇ ANR ਦਿਖਾਓ"</string>
- <string name="show_all_anrs_summary" msgid="641908614413544127">"ਪਿਛੋਕੜ ਐਪਸ ਲਈ ਐਪਸ ਜਵਾਬ ਨਹੀਂ ਦੇ ਰਹੇ ਡਾਇਲੌਗ ਦਿਖਾਓ"</string>
+ <string name="show_all_anrs_summary" msgid="641908614413544127">"ਬੈਕਗਰਾਊਂਡ ਐਪਾਂ ਲਈ ਐਪ ਜਵਾਬ ਨਹੀਂ ਦੇ ਰਹੇ ਡਾਇਲੌਗ ਦਿਖਾਓ"</string>
<string name="show_notification_channel_warnings" msgid="1399948193466922683">"ਸੂਚਨਾ ਚੈਨਲ ਚੇਤਾਵਨੀਆਂ ਦਿਖਾਓ"</string>
<string name="show_notification_channel_warnings_summary" msgid="5536803251863694895">"ਐਪ ਵੱਲੋਂ ਵੈਧ ਚੈਨਲ ਤੋਂ ਬਿਨਾਂ ਸੂਚਨਾ ਪੋਸਟ ਕਰਨ \'ਤੇ ਸਕ੍ਰੀਨ \'ਤੇ ਚੇਤਾਵਨੀ ਦਿਖਾਉਂਦੀ ਹੈ"</string>
<string name="force_allow_on_external" msgid="3215759785081916381">"ਐਪਸ ਨੂੰ ਬਾਹਰਲੇ ਤੇ ਜ਼ਬਰਦਸਤੀ ਆਗਿਆ ਦਿਓ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index a3a717ad02ba..43cec530e828 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Zawsze szukaj Wi-Fi w roamingu"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Mobilna transmisja danych zawsze aktywna"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Akceleracja sprzętowa tetheringu"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Wyłącz głośność bezwzględną"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Włącz dzwonek w kanale dźwiękowym"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Wersja AVRCP Bluetooth"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Te ustawienia są przeznaczone wyłącznie dla programistów. Ich użycie może spowodować uszkodzenie lub nieprawidłowe działanie urządzenia i zainstalowanych na nim aplikacji."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Zweryfikuj aplikacje przez USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Sprawdź, czy aplikacje zainstalowane przez ADB/ADT nie zachowują się w szkodliwy sposób"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Wyłącza funkcję Głośność bezwzględna Bluetooth, jeśli występują problemy z urządzeniami zdalnymi, np. zbyt duża głośność lub brak kontroli."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Zezwala na odtwarzanie dzwonków telefonu w zestawach słuchawkowych Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal lokalny"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index f9f68a77b4ea..526299388406 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Sempre permitir verif. de roaming de Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Dados móveis sempre ativos"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleração de hardware de tethering"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desativar volume absoluto"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Ativar o toque em banda"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versão do Bluetooth AVRCP"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Essas configurações são destinadas apenas para o uso de desenvolvedores. Elas podem causar a desativação ou mau funcionamento do dispositivo e dos apps contidos nele."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificar apps por USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Verificar comportamento nocivo em apps instalados via ADB/ADT."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desativa o recurso Bluetooth de volume absoluto em caso de problemas com o volume em dispositivos remotos, como volume excessivamente alto ou falta de controle."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Permitir que os toques no smartphone sejam reproduzidos em fones de ouvido Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index c2c8758df5bd..9ad38e1e2cf0 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Permitir sempre a deteção de Wi-Fi em roaming"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Dados móveis sempre ativos"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleração de hardware para ligação (à Internet) via telemóvel"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desativar volume absoluto"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Ativar toque dentro da banda"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versão de Bluetooth AVRCP"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Estas definições destinam-se apenas a programação. Podem fazer com que o seu aparelho e as aplicações nele existentes falhem ou funcionem mal."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificar aplicações de USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Verificar as aplicações instaladas via ADB/ADT para detetar comportamento perigoso."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desativa a funcionalidade de volume absoluto do Bluetooth caso existam problemas de volume com dispositivos remotos, como um volume insuportavelmente alto ou a ausência de controlo."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Permitir que os toques no telemóvel sejam reproduzidos em auscultadores com microfone integrado Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index f9f68a77b4ea..526299388406 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Sempre permitir verif. de roaming de Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Dados móveis sempre ativos"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Aceleração de hardware de tethering"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desativar volume absoluto"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Ativar o toque em banda"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versão do Bluetooth AVRCP"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Essas configurações são destinadas apenas para o uso de desenvolvedores. Elas podem causar a desativação ou mau funcionamento do dispositivo e dos apps contidos nele."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificar apps por USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Verificar comportamento nocivo em apps instalados via ADB/ADT."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Desativa o recurso Bluetooth de volume absoluto em caso de problemas com o volume em dispositivos remotos, como volume excessivamente alto ou falta de controle."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Permitir que os toques no smartphone sejam reproduzidos em fones de ouvido Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminal local"</string>
diff --git a/packages/SettingsLib/res/values-ro/arrays.xml b/packages/SettingsLib/res/values-ro/arrays.xml
index 62a198298143..3877bc952dea 100644
--- a/packages/SettingsLib/res/values-ro/arrays.xml
+++ b/packages/SettingsLib/res/values-ro/arrays.xml
@@ -68,10 +68,26 @@
<item msgid="1913619118958233129">"avrcp15"</item>
<item msgid="7142710449249088270">"avrcp16"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (5254942598247222737) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:4 (2091430979086738145) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (7848030269621918608) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:4 (298198075927343893) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Folosiți selectarea sist. (prestabilit)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="5254942598247222737">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2091430979086738145">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ <item msgid="723675059572222462">"Activați codecurile opționale"</item>
+ <item msgid="3304843301758635896">"Dezactivați codecurile opționale"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Folosiți selectarea sist. (prestabilit)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="7848030269621918608">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="298198075927343893">"Audio <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ <item msgid="2209680154067241740">"Activați codecurile opționale"</item>
+ <item msgid="741805482892725657">"Dezactivați codecurile opționale"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="3093023430402746802">"Folosiți selectarea sist. (prestabilit)"</item>
<item msgid="8895532488906185219">"44,1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 9f63e043954b..717d69028eff 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Se permite întotdeauna scanarea traficului Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Date mobile permanent active"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Accelerare hardware pentru tethering"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Dezactivați volumul absolut"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Activați soneria în căști"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versiunea AVRCP pentru Bluetooth"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Aceste setări sunt destinate exclusiv utilizării pentru dezvoltare. Din cauza lor, este posibil ca dispozitivul dvs. și aplicațiile de pe acesta să nu mai funcționeze sau să funcționeze necorespunzător."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verificați aplicațiile prin USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Verificați aplicațiile instalate utilizând ADB/ADT, pentru a detecta un comportament dăunător."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Dezactivează funcția Bluetooth de volum absolut în cazul problemelor de volum apărute la dispozitivele la distanță, cum ar fi volumul mult prea ridicat sau lipsa de control asupra acestuia."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Permiteți ca tonurile de sonerie de pe telefon să fie redate prin căștile Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Aplicație terminal locală"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index e9327b2754c2..c51295df38ae 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Всегда включать поиск сетей Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Не отключать мобильный Интернет"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Аппаратное ускорение в режиме модема"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Отключить абсолютный уровень громкости"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Включить внутриполосное воспроизведение"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Версия Bluetooth AVRCP"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Только для разработчиков. Изменение этих настроек может привести к сбоям или неправильной работе устройства и приложений."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Проверять приложения при установке"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Выполнять проверку безопасности приложений при установке через ADB/ADT"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Отключить абсолютный уровень громкости Bluetooth при возникновении проблем на удаленных устройствах, например при слишком громком звучании или невозможности контролировать настройку."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Разрешить воспроизведение рингтонов на телефоне через Bluetooth-гарнитуру"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Локальный терминальный доступ"</string>
diff --git a/packages/SettingsLib/res/values-si/arrays.xml b/packages/SettingsLib/res/values-si/arrays.xml
index 3fd6b7e3100d..60f951e2f683 100644
--- a/packages/SettingsLib/res/values-si/arrays.xml
+++ b/packages/SettingsLib/res/values-si/arrays.xml
@@ -68,10 +68,26 @@
<item msgid="1913619118958233129">"avrcp15"</item>
<item msgid="7142710449249088270">"avrcp16"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (5254942598247222737) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:4 (2091430979086738145) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (7848030269621918608) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:4 (298198075927343893) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"පද්ධති තේරීම භාවිත කරන්න (පෙරනිමි)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="5254942598247222737">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ශ්‍රව්‍යය"</item>
+ <item msgid="2091430979086738145">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ශ්‍රව්‍යය"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ <item msgid="723675059572222462">"විකල්පමය කොඩෙක් සබල කරන්න"</item>
+ <item msgid="3304843301758635896">"විකල්පමය කොඩෙක් අබල කරන්න"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"පද්ධති තේරීම භාවිත කරන්න (පෙරනිමි)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="7848030269621918608">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g> ශ්‍රව්‍යය"</item>
+ <item msgid="298198075927343893">"<xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g> ශ්‍රව්‍යය"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ <item msgid="2209680154067241740">"විකල්පමය කොඩෙක් සබල කරන්න"</item>
+ <item msgid="741805482892725657">"විකල්පමය කොඩෙක් අබල කරන්න"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="3093023430402746802">"පද්ධති තේරීම භාවිත කරන්න (පෙරනිමි)"</item>
<item msgid="8895532488906185219">"44.1 kHz"</item>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index d008fef93af6..794272ba8394 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi රෝම් පරිලෝකන වෙතට සැමවිට අවසර දෙන්න"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"ජංගම දත්ත සැමවිට ක්‍රියාකාරීය"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"ටෙදරින් දෘඪාංග ත්වරණය"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"නිරපේක්ෂ හඩ පරිමාව අබල කරන්න"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"කලාපය තුළ නාද වීම සබල කරන්න"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"බ්ලූටූත් AVRCP අනුවාදය"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"මෙම සැකසීම් වර්ධක භාවිතය සඳහා පමණි. ඔබගේ උපාංගයේ සහ යෙදුම්වල අක්‍රිය වීමට හෝ වැරදි ක්‍රියා කෙරුමකට ඒවා බලපෑ හැක."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB ඔස්සේ යෙදුම් සත්‍යාපනය කරගන්න"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT හරහා ස්ථාපනය වූ යෙදුම්, විනාශකාරී ක්‍රියාවන් ඇත්දැයි පරික්ෂාකර බලන්න."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"පිළිගත නොහැකි ලෙස වැඩි හඩ පරිමාව හෝ පාලනය නොමැති වීම යනාදී දුරස්ථ උපාංග සමගින් වන හඬ පරිමා ගැටලුවලදී බ්ලූටූත් නිරපේක්ෂ හඬ පරිමා විශේෂාංගය අබල කරයි."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"දුරකථනයේ නාද රටාවලට බ්ලූටූත් මත වාදනය වීමට ඉඩ දෙන්න"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"අභ්‍යන්තර අන්තය"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index ebef1ada3ad4..fd9b44985735 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Vždy povoliť funkciu Wi-Fi Roam Scans"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Mobilné dáta ponechať vždy aktívne"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardvérovú akcelerácia pre tethering"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Zakázať absolútnu hlasitosť"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Povoliť zvonenie v hovorovom pásme"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Verzia rozhrania Bluetooth AVRCP"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Tieto nastavenia sú určené len pre vývojárov. Môžu spôsobiť poruchu alebo nesprávne fungovanie zariadenia a nainštalovaných aplikácií."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Overovať aplikácie z USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrolovať škodlivosť aplikácií nainštalovaných pomocou nástroja ADB alebo ADT"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Umožňuje zakázať funkciu absolútnej hlasitosti rozhrania Bluetooth v prípade problémov s hlasitosťou na vzdialených zariadeniach, ako je napríklad neprijateľne vysoká hlasitosť alebo absencia ovládacích prvkov."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Umožňuje prehrávať tóny zvonenia na telefóne v náhlavných súpravách Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Miestny terminál"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index dc27278441ea..0fbbfacd8f3f 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Vedno omogoči iskanje omrežij Wi-Fi za gostovanje"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Prenos podatkov v mobilnem omrežju je vedno aktiven"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Strojno pospeševanje za internetno povezavo prek mobilnega telefona"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Onemogočanje absolutnega praga glasnosti"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Omogoči zvonjenje iz telefona"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Različica profila AVRCP za Bluetooth"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Te nastavitve so namenjene samo za razvijanje in lahko povzročijo prekinitev ali napačno delovanje naprave in aplikacij v njej."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Preveri aplikacije prek USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Preveri, ali so aplikacije, nameščene prek ADB/ADT, škodljive."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Onemogoči funkcijo absolutnega praga glasnosti za Bluetooth, če pride do težav z glasnostjo z oddaljenimi napravami, kot je nesprejemljivo visoka glasnost ali pomanjkanje nadzora."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Omogoči, da se toni zvonjenja v telefonu predvajajo v slušalkah z mikrofonom Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokalni terminal"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index 97c506fd9a26..48e050641689 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Lejo gjithmonë skanimet për Wi-Fi edhe kur je në lëvizje"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Të dhënat celulare gjithmonë aktive"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Përshpejtimi i harduerit për ndarjen"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Çaktivizo volumin absolut"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Aktivizo zilen brenda të njëjtit brez"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Versioni AVRCP i Bluetooth-it"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Këto cilësime janë të projektuara vetëm për përdorim në programim. Ato mund të shkaktojnë që pajisja dhe aplikacionet në të, të mos punojnë ose të veprojnë në mënyrë të gabuar."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifiko apl. përmes USB-së"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrollo aplikacionet e instaluara nëpërmjet ADB/ADT për sjellje të dëmshme."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Çaktivizon funksionin e volumit absolut të Bluetooth në rast të problemeve të volumit me pajisjet në largësi, si p.sh. një volum i lartë i papranueshëm ose mungesa e kontrollit."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Lejo që zilet në telefon të luhen në kufjet me \"Bluetooth\""</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Terminali lokal"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 7d07e4f08cf5..cb105f423cb3 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Увек дозволи скенирање Wi‑Fi-ја у ромингу"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Мобилни подаци су увек активни"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Хардверско убрзање привезивања"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Онемогући главно подешавање јачине звука"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Омогућавање звоњаве на истом каналу"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Верзија Bluetooth AVRCP-а"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ова подешавања су намењена само за програмирање. Могу да изазову престанак функционисања или неочекивано понашање уређаја и апликација на њему."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Верификуј апликације преко USB-а"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Проверава да ли су апликације инсталиране преко ADB-а/ADT-а штетне."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Онемогућава главно подешавање јачине звука на Bluetooth уређају у случају проблема са јачином звука на даљинским уређајима, као што су изузетно велика јачина звука или недостатак контроле."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Омогућите да се мелодија звона на телефону пушта преко Bluetooth слушалица"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Локални терминал"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 617eac38bec4..defbee940a78 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Tillåt alltid sökning efter Wi-Fi-roaming"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Mobildata alltid aktiverad"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Maskinvaruacceleration för internetdelning"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Inaktivera Absolute volume"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Aktivera samtal inom nätverket"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"AVRCP-version för Bluetooth"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Inställningarna är endast avsedda att användas för utvecklingsändamål. De kan orsaka problem med enheten eller apparna som finns installerade på den."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Verifiera appar via USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kontrollera om appar som installeras via ADB/ADT kan vara skadliga."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Inaktivera Bluetooth-funktionen Absolute volume om det skulle uppstå problem med volymen på fjärrenheter, t.ex. alldeles för hög volym eller brist på kontroll."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Tillåt att ringsignaler på mobilen kan spelas upp i Bluetooth-headset"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokal terminal"</string>
diff --git a/packages/SettingsLib/res/values-sw/arrays.xml b/packages/SettingsLib/res/values-sw/arrays.xml
index 556199e3ef61..97b560a4f6cf 100644
--- a/packages/SettingsLib/res/values-sw/arrays.xml
+++ b/packages/SettingsLib/res/values-sw/arrays.xml
@@ -68,10 +68,26 @@
<item msgid="1913619118958233129">"avrcp15"</item>
<item msgid="7142710449249088270">"avrcp16"</item>
</string-array>
- <!-- no translation found for bluetooth_a2dp_codec_titles:3 (5254942598247222737) -->
- <!-- no translation found for bluetooth_a2dp_codec_titles:4 (2091430979086738145) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:3 (7848030269621918608) -->
- <!-- no translation found for bluetooth_a2dp_codec_summaries:4 (298198075927343893) -->
+ <string-array name="bluetooth_a2dp_codec_titles">
+ <item msgid="7065842274271279580">"Tumia Uteuzi wa Mfumo (Chaguo-msingi)"</item>
+ <item msgid="7539690996561263909">"SBC"</item>
+ <item msgid="686685526567131661">"AAC"</item>
+ <item msgid="5254942598247222737">"Sauti ya <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="2091430979086738145">"Sauti ya <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="6751080638867012696">"LDAC"</item>
+ <item msgid="723675059572222462">"Washa Kodeki Zisizo za Lazima"</item>
+ <item msgid="3304843301758635896">"Zima Kodeki Zisizo za Lazima"</item>
+ </string-array>
+ <string-array name="bluetooth_a2dp_codec_summaries">
+ <item msgid="5062108632402595000">"Tumia Uteuzi wa Mfumo (Chaguo-msingi)"</item>
+ <item msgid="6898329690939802290">"SBC"</item>
+ <item msgid="6839647709301342559">"AAC"</item>
+ <item msgid="7848030269621918608">"Sauti ya <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX">aptX™</xliff:g>"</item>
+ <item msgid="298198075927343893">"Sauti ya <xliff:g id="QUALCOMM">Qualcomm®</xliff:g> <xliff:g id="APTX_HD">aptX™ HD</xliff:g>"</item>
+ <item msgid="7950781694447359344">"LDAC"</item>
+ <item msgid="2209680154067241740">"Washa Kodeki Zisizo za Lazima"</item>
+ <item msgid="741805482892725657">"Zima Kodeki Zisizo za Lazima"</item>
+ </string-array>
<string-array name="bluetooth_a2dp_codec_sample_rate_titles">
<item msgid="3093023430402746802">"Tumia Uteuzi wa Mfumo (Chaguo-msingi)"</item>
<item msgid="8895532488906185219">"kHz 44.1"</item>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index ebc722c4e56d..a7fba53fc058 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Ruhusu Uchanganuzi wa Matumizi ya Mitandao mingine"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Iendelee kutumia data ya simu"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Kuongeza kasi kwa kutumia maunzi ili kusambaza mtandao"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Zima sauti kamili"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Washa kipengele cha mlio wa simu katika kituo hicho hicho"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Toleo la Bluetooth AVRCP"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Mipangilio hii imekusudiwa kwa matumizi ya usanidi tu. Inaweza kusababisha kifaa chako na programu zilizoko kuvunjika au kutofanya kazi vizuri."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Thibitisha programu kupitia USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kagua programu zilizosakinishwa kupitia ADB/ADT kwa tabia ya kudhuru."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Huzima kipengele cha Bluetooth cha sauti kamili kunapotokea matatizo ya sauti katika vifaa vya mbali kama vile sauti ya juu mno au inaposhindikana kuidhibiti."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Ruhusu milio ya simu kwenye simu ichezwe kwenye Vifaa vya sauti vya Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Kituo cha karibu"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index f2d0b11b33db..c2fc83e1dd1c 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"எப்போதும் வைஃபை ரோமிங் ஸ்கேன்களை அனுமதி"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"மொபைல் தரவை எப்போதும் இயக்கத்திலேயே வை"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"வன்பொருள் விரைவுப்படுத்துதல் இணைப்பு முறை"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"அப்சல்யூட் ஒலியளவு அம்சத்தை முடக்கு"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"இன்-பேண்ட் ரிங் செய்வதை இயக்கு"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"புளூடூத் AVRCP பதிப்பு"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"இந்த அமைப்பு மேம்பட்டப் பயன்பாட்டிற்காக மட்டுமே. உங்கள் சாதனம் மற்றும் அதில் உள்ள பயன்பாடுகளைச் சிதைக்கும் அல்லது தவறாகச் செயல்படும் வகையில் பாதிப்பை ஏற்படுத்தும்."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB பயன்பாடுகளை சரிபார்"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"தீங்கு விளைவிக்கும் செயல்பாட்டை அறிய ADB/ADT மூலம் நிறுவப்பட்டப் பயன்பாடுகளைச் சரிபார்."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"மிகவும் அதிகமான ஒலியளவு அல்லது கட்டுப்பாடு இழப்பு போன்ற தொலைநிலைச் சாதனங்களில் ஏற்படும் ஒலி தொடர்பான சிக்கல்கள் இருக்கும் சமயங்களில், புளூடூத் அப்சல்யூட் ஒலியளவு அம்சத்தை முடக்கும்."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"ஃபோனில் இருக்கும் ரிங்டோன்களை, புளூடூத் ஹெட்செட்களில் இயக்க அனுமதி"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"அக முனையம்"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 6b43c6cc9d61..2b8795ae1f3b 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi సంచార స్కాన్‌లను ఎల్లప్పుడూ అనుమతించు"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"మొబైల్ డేటాని ఎల్లప్పుడూ సక్రియంగా ఉంచు"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"టీథెరింగ్ హార్డ్‌వేర్ వేగవృద్ధి"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"సంపూర్ణ వాల్యూమ్‌‍ను నిలిపివేయి"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"ఇన్-బ్యాండ్ రింగింగ్‌ని ప్రారంభించండి"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"బ్లూటూత్ AVRCP సంస్కరణ"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"ఈ సెట్టింగ్‌లు అభివృద్ధి వినియోగం కోసం మాత్రమే ఉద్దేశించబడినవి. వీటి వలన మీ పరికరం మరియు దీనిలోని యాప్‌లు విచ్ఛిన్నం కావచ్చు లేదా తప్పుగా ప్రవర్తించవచ్చు."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB ద్వారా అనువర్తనాలను ధృవీకరించు"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"హానికరమైన ప్రవర్తన కోసం ADB/ADT ద్వారా ఇన్‌స్టాల్ చేయబడిన అనువర్తనాలను తనిఖీ చేయి."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"రిమోట్ పరికరాల్లో ఆమోదించలేని స్థాయిలో అధిక వాల్యూమ్ ఉండటం లేదా వాల్యూమ్ నియంత్రణ లేకపోవడం వంటి సమస్యలు ఉంటే బ్లూటూత్ సంపూర్ణ వాల్యూమ్ లక్షణాన్ని నిలిపివేస్తుంది."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"బ్లూటూత్ హెడ్‌సెట్‌లలో ప్లే చేయడానికి ఫోన్‌లో రింగ్‌టోన్‌లను అనుమతించండి"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"స్థానిక టెర్మినల్"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 007d3a5abf7b..8b49036f2114 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"ใช้การสแกน Wi-Fi ข้ามเครือข่ายเสมอ"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"เปิดใช้อินเทอร์เน็ตมือถือเสมอ"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"การเร่งฮาร์ดแวร์การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ปิดใช้การควบคุมระดับเสียงของอุปกรณ์อื่น"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"เปิดใช้การส่งเสียงในช่องสัญญาณเดียวกัน"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"เวอร์ชันของบลูทูธ AVRCP"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"การตั้งค่านี้มีไว้เพื่อการพัฒนาเท่านั้น จึงอาจทำให้อุปกรณ์และแอปพลิเคชันที่มีอยู่เสียหายหรือทำงานผิดพลาดได้"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"ยืนยันแอปพลิเคชันผ่าน USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ตรวจสอบแอปพลิเคชันที่ติดตั้งผ่าน ADB/ADT เพื่อตรวจดูพฤติกรรมที่เป็นอันตราย"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ปิดใช้ฟีเจอร์การควบคุมระดับเสียงของอุปกรณ์อื่นผ่านบลูทูธในกรณีที่มีปัญหาเกี่ยวกับระดับเสียงของอุปกรณ์ระยะไกล เช่น ระดับเสียงที่ดังเกินไปหรือระดับเสียงที่ไม่มีการควบคุม"</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"ให้เสียงเรียกเข้าในโทรศัพท์เล่นในชุดหูฟังบลูทูธ"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"เทอร์มินัลในตัวเครื่อง"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index c1f0a23b7a4a..c054248a6fe5 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Palaging payagan ang Mga Pag-scan sa Roaming ng Wi‑Fi"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Palaging aktibo ang mobile data"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Hardware acceleration para sa pag-tether"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"I-disable ang absolute volume"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"I-enable ang pag-ring na nasa band"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bersyon ng AVRCP ng Bluetooth"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Nilalayon ang mga setting na ito para sa paggamit sa pag-develop lamang. Maaaring magsanhi ang mga ito ng pagkasira o hindi paggana nang maayos ng iyong device at mga application na nandito."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"I-verify ang mga app sa USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Tingnan kung may nakakahamak na pagkilos sa apps na na-install sa pamamagitan ng ADB/ADT."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Dini-disable ang absolute volume feature ng Bluetooth kung may mga isyu sa volume ang mga malayong device gaya ng hindi katanggap-tanggap na malakas na volume o kawalan ng kontrol."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Payagan ang pag-play ng mga ringtone sa telepono sa mga headset na gumagamit ng Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Lokal na terminal"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index a3f3ad1cb804..69dd6be97523 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Kablosuz Dolaşım Taramalarına daima izin ver"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Mobil veri her zaman etkin"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Tethering donanım hızlandırıcısı"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Mutlak sesi iptal et"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Bant içi zil çaldırmayı etkinleştir"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP Sürümü"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Bu ayarlar yalnızca geliştirme amaçlıdır. Cihazınızın veya cihazdaki uygulamaların bozulmasına veya hatalı çalışmasına neden olabilir."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB\'den yüklenen uygulamaları doğrula"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT üzerinden yüklenen uygulamaları zararlı davranışlara karşı denetle."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Uzak cihazda sesin aşırı yüksek olması veya kontrol edilememesi gibi ses sorunları olması ihtimaline karşı Bluetooh mutlak ses özelliğini iptal eder."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Telefondaki zil seslerinin Bluetooth kulaklıklarda çalınmasına olanak tanır"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Yerel terminal"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index 7bf924360690..6b6e245366b4 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Завжди шукати мережі Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Не вимикати мобільне передавання даних"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Апаратне прискорення під час використання телефона в режимі модема"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Вимкнути абсолютну гучність"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Увімкнути внутрішньосмугові сигнали"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Версія Bluetooth AVRCP"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Ці налаштування застосовуються лише з метою розробки. Вони можуть спричиняти вихід з ладу або неправильне функціонування вашого пристрою чи програм у ньому."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Встановлення через USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Перевіряти безпеку додатків, установлених через ADB/ADT."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Функція абсолютної гучності Bluetooth вимикається, якщо на віддалених пристроях виникають проблеми, як-от надто висока гучність або втрата контролю."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Дозволити відтворювати сигнали дзвінка на телефоні через гарнітуру Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Локальний термінал"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index c2819ae7942e..09e83188ec99 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"‏ہمیشہ Wi‑Fi روم اسکینز کی اجازت دیں"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"موبائل ڈیٹا ہمیشہ فعال رکھیں"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"ہارڈویئر کی سرعت کاری میں ربط بنایا جا رہا ہے"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"مطلق والیوم کو غیر فعال کریں"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"ان بینڈ رنگنگ فعال کریں"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"‏بلوٹوتھ AVRCP ورژن"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"یہ ترتیبات صرف ڈویلپمنٹ استعمال کے ارادے سے ہیں۔ ان سے آپ کا آلہ اور اس پر موجود ایپلیکیشنز بریک ہو سکتی یا غلط برتاؤ کر سکتی ہیں۔"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"‏USB پر ایپس کی توثیق کریں"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"‏نقصان دہ رویے کے مدنظر ADB/ADT کی معرفت انسٹال شدہ ایپس کی جانچ کریں۔"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"ریموٹ آلات کے ساتھ والیوم کے مسائل مثلاً نا قابل قبول حد تک بلند والیوم یا کنٹرول نہ ہونے کی صورت میں بلو ٹوتھ مطلق والیوم والی خصوصیت کو غیر فعال کریں۔"</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"فون پر موجود رنگ ٹونز کو بلوٹوتھ ہیڈ سیٹز پر چلنے دیں"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"مقامی ٹرمینل"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index f7bb82506e20..981b67e4cfb3 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi-Fi tarmoqlarini qidirishga doim ruxsat"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Mobil internet doim yoniq tursin"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Modem rejimida apparatli tezlashtirish"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Ovoz balangligining mutlaq darajasini o‘chirib qo‘yish"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Bitta liniyada jiringlashni yoqish"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth AVRCP versiyasi"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Bu sozlamalar faqat dasturlash maqsadlariga mo‘ljallangan. Shuning uchun, ular qurilmangizga va undagi ilovalariga shikast yetkazib, noto‘g‘ri ishlashiga sabab bo‘lishi mumkin."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"USB orqali o‘rnatish"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT orqali o‘rnatilgan ilovalar xavfsizligini tekshiring"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Masofadan ulanadigan qurilmalar bilan muammolar yuz berganda, jumladan, juda baland ovoz yoki sozlamalarni boshqarib bo‘lmaydigan holatlarda Bluetooth ovozi balandligining mutlaq darajasini o‘chirib qo‘yadi."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Bluetooth quloqliklarda ijro etish uchun telefonda ringtonlarga ruxsat bering"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Mahalliy terminal"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 4a32d272b3dd..d5ee2161c215 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Luôn cho phép quét chuyển vùng Wi‑Fi"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Dữ liệu di động luôn hiện hoạt"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"Tăng tốc phần cứng cho chia sẻ kết nối"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Vô hiệu hóa âm lượng tuyệt đối"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Bật đổ chuông trong dải"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Bluetooth phiên bản AVRCP"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Những cài đặt này chỉ dành cho mục đích phát triển. Chúng có thể làm cho thiết bị và ứng dụng trên thiết bị của bạn bị lỗi và hoạt động sai."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Xác minh ứng dụng qua USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Kiểm tra các ứng dụng được cài đặt qua ADB/ADT để xem có hoạt động gây hại hay không."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Vô hiệu hóa tính năng âm lượng tuyệt đối qua Bluetooth trong trường hợp xảy ra sự cố về âm lượng với các thiết bị từ xa, chẳng hạn như âm lượng lớn không thể chấp nhận được hoặc thiếu kiểm soát."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Cho phép nhạc chuông trên điện thoại được phát trên tai nghe Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Dòng lệnh cục bộ"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 40a0d7efe3e2..c6f9061dce43 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"一律允许WLAN漫游扫描"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"始终开启移动数据网络"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"网络共享硬件加速"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"停用绝对音量功能"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"启用手机默认铃声"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"蓝牙 AVRCP 版本"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"这些设置仅适用于开发工作。一旦启用,会导致您的设备以及设备上的应用崩溃或出现异常。"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"通过USB验证应用"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"通过 ADB/ADT 检查安装的应用是否存在有害行为。"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"停用蓝牙绝对音量功能,即可避免在连接到远程设备时出现音量问题(例如音量高得让人无法接受或无法控制音量等)。"</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"允许手机铃声通过蓝牙耳机播放"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"本地终端"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 56336ecfc7e4..af9ba2405125 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"永遠允許 Wi-Fi 漫遊掃瞄"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"一律保持啟用流動數據"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"網絡共享硬件加速"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"停用絕對音量功能"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"啟用頻內鈴聲"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"藍牙 AVRCP 版本"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"這些設定僅供開發用途,可能會導致您的裝置及應用程式損毀或運作不正常。"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"透過 USB 驗證應用程式"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"透過 ADB/ADT 檢查安裝的應用程式有否有害的行為。"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"連線至遠端裝置時,如發生音量過大或無法控制音量等問題,請停用藍牙絕對音量功能。"</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"允許藍牙耳機播放手機鈴聲"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"本機終端機"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 3ff0f194ff7a..9e8d1ca76a54 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"一律允許 Wi-Fi 漫遊掃描"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"行動數據連線一律保持啟用狀態"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"數據連線硬體加速"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"停用絕對音量功能"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"啟用藍牙同步鈴聲功能"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"藍牙 AVRCP 版本"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"這些設定僅供開發之用,可能導致你的裝置及裝置中的應用程式毀損或運作異常。"</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"透過 USB 驗證應用程式"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"檢查透過 ADB/ADT 安裝的應用程式是否具有有害行為。"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"只要停用藍牙絕對音量功能,即可避免在連線到遠端裝置時,發生音量過大或無法控制音量等問題。"</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"允許手機鈴聲透過藍牙耳機播放"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"本機終端機"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 19b98c2ab746..5be0b8ecec61 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -193,6 +193,8 @@
<string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Vumela njalo ukuskena kokuzula kwe-Wi-Fi"</string>
<string name="mobile_data_always_on" msgid="8774857027458200434">"Idatha yeselula ihlala isebenza"</string>
<string name="tethering_hardware_offload" msgid="7470077827090325814">"I-Tethering hardware acceleration"</string>
+ <!-- no translation found for bluetooth_show_devices_without_names (4708446092962060176) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Khubaza ivolumu ngokuphelele"</string>
<string name="bluetooth_enable_inband_ringing" msgid="3291686366721786740">"Nika amandla ukukhala okuphakathi nomkhiqizo"</string>
<string name="bluetooth_select_avrcp_version_string" msgid="3750059931120293633">"Inguqulo ye-Bluetooth ye-AVRCP"</string>
@@ -232,6 +234,8 @@
<string name="dev_settings_warning_message" msgid="2298337781139097964">"Lezi zilungiselelo zenzelwe ukusetshenziswa ukuthuthukisa kuphela. Zingadala ukuthi idivayisi yakho kanye nensiza ekuyona ukuthi iphuke noma iziphathe kabi."</string>
<string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Qiniseka izinhlelo zokusebenza nge-USB"</string>
<string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"Hlola izinhlelo zokusebenza ezifakiwe nge-ADB/ADT ngokuziphatha okuyingozi."</string>
+ <!-- no translation found for bluetooth_show_devices_without_names_summary (2351196058115755520) -->
+ <skip />
<string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Ikhubaza isici esiphelele sevolumu ye-Bluetooth uma kuba nezinkinga zevolumu ngamadivayisi esilawuli kude ezifana nevolumu ephezulu noma eshoda ngokulawuleka."</string>
<string name="bluetooth_enable_inband_ringing_summary" msgid="2787866074741784975">"Vumela amathoni okukhala efonini ukuthi adlalwe kuma-earphone e-Bluetooth"</string>
<string name="enable_terminal_title" msgid="95572094356054120">"Itheminali yasendaweni"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 2627380e91fb..8def03648558 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -96,7 +96,9 @@ public class Utils {
public static Drawable getUserIcon(Context context, UserManager um, UserInfo user) {
final int iconSize = UserIconDrawable.getSizeForList(context);
if (user.isManagedProfile()) {
- return context.getDrawable(com.android.internal.R.drawable.ic_corp_icon);
+ Drawable drawable = context.getDrawable(com.android.internal.R.drawable.ic_corp_icon);
+ drawable.setBounds(0, 0, iconSize, iconSize);
+ return drawable;
}
if (user.iconPath != null) {
Bitmap icon = um.getUserIcon(user.id);
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 443f1ee1d827..87bf0de2b2c8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -1638,6 +1638,21 @@ public class ApplicationsState {
}
};
+ public static final AppFilter FILTER_PHOTOS =
+ new AppFilter() {
+ @Override
+ public void init() {}
+
+ @Override
+ public boolean filterApp(AppEntry entry) {
+ boolean isPhotosApp;
+ synchronized (entry) {
+ isPhotosApp = entry.info.category == ApplicationInfo.CATEGORY_IMAGE;
+ }
+ return isPhotosApp;
+ }
+ };
+
public static final AppFilter FILTER_OTHER_APPS =
new AppFilter() {
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 7268d00bade1..0946181ab710 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -233,8 +233,8 @@ public class A2dpProfile implements LocalBluetoothProfile {
public String getHighQualityAudioOptionLabel(BluetoothDevice device) {
int unknownCodecId = R.string.bluetooth_profile_a2dp_high_quality_unknown_codec;
- if (!supportsHighQualityAudio(device) ||
- getConnectionStatus(device) != BluetoothProfile.STATE_CONNECTED) {
+ if (!supportsHighQualityAudio(device)
+ || getConnectionStatus(device) != BluetoothProfile.STATE_CONNECTED) {
return mContext.getString(unknownCodecId);
}
// We want to get the highest priority codec, since that's the one that will be used with
@@ -248,11 +248,36 @@ public class A2dpProfile implements LocalBluetoothProfile {
return b.getCodecPriority() - a.getCodecPriority();
});
}
- if (selectable == null || selectable.length < 1 || selectable[0].isMandatoryCodec()) {
+
+ final BluetoothCodecConfig codecConfig = (selectable == null || selectable.length < 1)
+ ? null : selectable[0];
+ final int codecType = (codecConfig == null || codecConfig.isMandatoryCodec())
+ ? BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID : codecConfig.getCodecType();
+
+ int index = -1;
+ switch (codecType) {
+ case BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC:
+ index = 1;
+ break;
+ case BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC:
+ index = 2;
+ break;
+ case BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX:
+ index = 3;
+ break;
+ case BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD:
+ index = 4;
+ break;
+ case BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC:
+ index = 5;
+ break;
+ }
+
+ if (index < 0) {
return mContext.getString(unknownCodecId);
}
return mContext.getString(R.string.bluetooth_profile_a2dp_high_quality,
- selectable[0].getCodecName());
+ mContext.getResources().getStringArray(R.array.bluetooth_a2dp_codec_titles)[index]);
}
public String toString() {
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java
index fed18fa1bcb0..751b4ba316d7 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/applications/ApplicationsStateTest.java
@@ -110,6 +110,27 @@ public class ApplicationsStateTest {
}
@Test
+ public void testPhotosFilterAcceptsFilter() {
+ mEntry.info.category = ApplicationInfo.CATEGORY_IMAGE;
+
+ assertThat(ApplicationsState.FILTER_PHOTOS.filterApp(mEntry)).isTrue();
+ }
+
+ @Test
+ public void testPhotosFilterRejectsNotPhotos() {
+ mEntry.info.category = ApplicationInfo.CATEGORY_VIDEO;
+
+ assertThat(ApplicationsState.FILTER_PHOTOS.filterApp(mEntry)).isFalse();
+ }
+
+ @Test
+ public void testPhotosFilterRejectsDefaultCategory() {
+ mEntry.info.category = ApplicationInfo.CATEGORY_UNDEFINED;
+
+ assertThat(ApplicationsState.FILTER_PHOTOS.filterApp(mEntry)).isFalse();
+ }
+
+ @Test
public void testDownloadAndLauncherAndInstantAcceptsCorrectApps() {
// should include instant apps
mEntry.isHomeApp = false;
diff --git a/packages/Shell/res/values-hi/strings.xml b/packages/Shell/res/values-hi/strings.xml
index 6992240e33f9..c82284c68c6f 100644
--- a/packages/Shell/res/values-hi/strings.xml
+++ b/packages/Shell/res/values-hi/strings.xml
@@ -17,31 +17,31 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_label" msgid="3701846017049540910">"शेल"</string>
- <string name="bugreport_notification_channel" msgid="2574150205913861141">"बग रिपोर्ट"</string>
- <string name="bugreport_in_progress_title" msgid="4311705936714972757">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g> जेनरेट की जा रही है"</string>
- <string name="bugreport_finished_title" msgid="4429132808670114081">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g> कैप्चर की गई"</string>
- <string name="bugreport_updating_title" msgid="4423539949559634214">"बग रिपोर्ट में विवरण जोड़े जा रहे हैं"</string>
+ <string name="bugreport_notification_channel" msgid="2574150205913861141">"गड़बड़ी की रिपोर्ट"</string>
+ <string name="bugreport_in_progress_title" msgid="4311705936714972757">"गड़बड़ी की रिपोर्ट <xliff:g id="ID">#%d</xliff:g> तैयार की जा रही है"</string>
+ <string name="bugreport_finished_title" msgid="4429132808670114081">"गड़बड़ी की रिपोर्ट <xliff:g id="ID">#%d</xliff:g> कैप्चर की गई"</string>
+ <string name="bugreport_updating_title" msgid="4423539949559634214">"गड़बड़ी की रिपोर्ट में पूरी जानकारी जोड़ी जा रही है"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"कृपया प्रतीक्षा करें…"</string>
- <string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"बग रिपोर्ट थोड़ी ही देर में फ़ोन पर दिखाई देगी"</string>
- <string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"अपनी बग रिपोर्ट साझा करना चुनें"</string>
- <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"अपनी बग रिपोर्ट शेयर करने के लिए टैप करें"</string>
- <string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"किसी स्क्रीनशॉट के बिना अपनी बग रिपोर्ट साझा करना चुनें या स्क्रीनशॉट पूरा होने तक इंतज़ार करें"</string>
- <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"अपनी बग रिपोर्ट को बिना स्क्रीनशॉट साझा करने हेतु टैप करें या स्क्रीनशॉट पूरा होने की प्रतीक्षा करें"</string>
- <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"अपनी बग रिपोर्ट को बिना स्क्रीनशॉट साझा करने हेतु टैप करें या स्क्रीनशॉट पूरा होने की प्रतीक्षा करें"</string>
- <string name="bugreport_confirm" msgid="5917407234515812495">"बग रिपोर्ट में सिस्टम की विभिन्न लॉग फ़ाइलों का डेटा शामिल होता है, जिसमें ऐसा डेटा शामिल हो सकता है जिसे आप संवेदनशील मानते हैं (जैसे कि ऐप्लिकेशन का उपयोग और स्थान डेटा). बग रिपोर्ट केवल अपने विश्वसनीय लोगों और ऐप्लिकेशन से साझा करें."</string>
+ <string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"गड़बड़ी की रिपोर्ट थोड़ी ही देर में फ़ोन पर दिखाई देगी"</string>
+ <string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"अपनी गड़बड़ी की रिपोर्ट शेयर करने के लिए टैप करें"</string>
+ <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"अपनी गड़बड़ी की रिपोर्ट शेयर करने के लिए टैप करें"</string>
+ <string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"स्क्रीनशॉट के बिना अपनी गड़बड़ी की रिपोर्ट शेयर करना चुनें या स्क्रीनशॉट पूरा होने तक इंतज़ार करें"</string>
+ <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"अपनी गड़बड़ी की रिपोर्ट को बिना स्क्रीनशॉट के शेयर करने के लिए टैप करें या स्क्रीनशॉट पूरा होने की इंतज़ार करें"</string>
+ <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"अपनी गड़बड़ी की रिपोर्ट को बिना स्क्रीनशॉट के शेयर करने के लिए टैप करें या स्क्रीनशॉट पूरा होने की इंतज़ार करें"</string>
+ <string name="bugreport_confirm" msgid="5917407234515812495">"गड़बड़ी की रिपोर्ट में सिस्टम की अलग-अलग लॉग फ़ाइलों का डेटा शामिल होता है, जिसमें ऐसा डेटा शामिल हो सकता है जिसे आप संवेदनशील मानते हैं (जैसे कि ऐप्लिकेशन का उपयोग और स्थान डेटा). गड़बड़ी की रिपोर्ट केवल अपने भरोसेमंद लोगों और ऐप्लिकेशन से साझा करें."</string>
<string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"फिर से ना दिखाएं"</string>
- <string name="bugreport_storage_title" msgid="5332488144740527109">"बग रिपोर्ट"</string>
- <string name="bugreport_unreadable_text" msgid="586517851044535486">"बग रिपोर्ट फ़ाइल नहीं पढ़ी जा सकी"</string>
- <string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"बग रिपोर्ट को ज़िप फ़ाइल में नहीं जोड़ा जा सका"</string>
+ <string name="bugreport_storage_title" msgid="5332488144740527109">"गड़बड़ी की रिपोर्ट"</string>
+ <string name="bugreport_unreadable_text" msgid="586517851044535486">"गड़बड़ी की रिपोर्ट फ़ाइल नहीं पढ़ी जा सकी"</string>
+ <string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"गड़बड़ी की रिपोर्ट को ज़िप फ़ाइल में नहीं जोड़ा जा सका"</string>
<string name="bugreport_unnamed" msgid="2800582406842092709">"अनामांकित"</string>
<string name="bugreport_info_action" msgid="2158204228510576227">"विवरण"</string>
<string name="bugreport_screenshot_action" msgid="8677781721940614995">"स्क्रीनशॉट"</string>
<string name="bugreport_screenshot_taken" msgid="5684211273096253120">"स्क्रीनशॉट सफलतापूर्वक लिया गया."</string>
<string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रीनशॉट नहीं लिया जा सका."</string>
- <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g> के विवरण"</string>
+ <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"गड़बड़ी की रिपोर्ट <xliff:g id="ID">#%d</xliff:g> की पूरी जानकारी"</string>
<string name="bugreport_info_name" msgid="4414036021935139527">"फ़ाइल नाम"</string>
- <string name="bugreport_info_title" msgid="2306030793918239804">"बग शीर्षक"</string>
- <string name="bugreport_info_description" msgid="5072835127481627722">"बग सारांश"</string>
+ <string name="bugreport_info_title" msgid="2306030793918239804">"गड़बड़ी का शीर्षक"</string>
+ <string name="bugreport_info_description" msgid="5072835127481627722">"गड़बड़ी का सारांश"</string>
<string name="save" msgid="4781509040564835759">"सहेजें"</string>
- <string name="bugreport_intent_chooser_title" msgid="7605709494790894076">"बग रिपोर्ट साझा करें"</string>
+ <string name="bugreport_intent_chooser_title" msgid="7605709494790894076">"गड़बड़ी की रिपोर्ट शेयर करें"</string>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml
index ef6a22d03b01..5e9bf3c9e1ae 100644
--- a/packages/SystemUI/res-keyguard/values-hi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml
@@ -34,7 +34,7 @@
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"तेज़ी से चार्ज हो रही है"</string>
<string name="keyguard_plugged_in_charging_slowly" msgid="6637043106038550407">"धीरे चार्ज हो रही है"</string>
<string name="keyguard_low_battery" msgid="9218432555787624490">"अपना चार्जर कनेक्‍ट करें."</string>
- <string name="keyguard_instructions_when_pattern_disabled" msgid="8566679946700751371">"अनलॉक करने के लिए मेनू दबाएं."</string>
+ <string name="keyguard_instructions_when_pattern_disabled" msgid="8566679946700751371">"लॉक खोलने के लिए मेन्यू दबाएं."</string>
<string name="keyguard_network_locked_message" msgid="6743537524631420759">"नेटवर्क लॉक किया हुआ है"</string>
<string name="keyguard_missing_sim_message_short" msgid="6327533369959764518">"कोई SIM कार्ड नहीं है"</string>
<string name="keyguard_missing_sim_message" product="tablet" msgid="4550152848200783542">"टैबलेट में कोई SIM कार्ड नहीं है."</string>
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 589f1c16935b..b0f7d2810a3d 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -133,7 +133,10 @@
<!-- Message shown when user enters wrong PIN -->
<string name="kg_wrong_pin">Wrong PIN</string>
<!-- Countdown message shown after too many failed unlock attempts -->
- <string name="kg_too_many_failed_attempts_countdown">Try again in <xliff:g id="number">%d</xliff:g> seconds.</string>
+ <plurals name="kg_too_many_failed_attempts_countdown">
+ <item quantity="one">Try again in 1 second.</item>
+ <item quantity="other">Try again in <xliff:g id="number">%d</xliff:g> seconds.</item>
+ </plurals>
<!-- Instructions for using the pattern unlock screen -->
<string name="kg_pattern_instructions">Draw your pattern</string>
<!-- Instructions for using the SIM PIN unlock screen -->
diff --git a/packages/SystemUI/res/drawable/car_qs_background_primary.xml b/packages/SystemUI/res/drawable/car_qs_background_primary.xml
deleted file mode 100644
index 0f77987bb7ce..000000000000
--- a/packages/SystemUI/res/drawable/car_qs_background_primary.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<inset xmlns:android="http://schemas.android.com/apk/res/android">
- <shape>
- <solid android:color="?android:attr/colorPrimaryDark"/>
- </shape>
-</inset>
diff --git a/packages/SystemUI/res/layout/battery_percentage_view.xml b/packages/SystemUI/res/layout/battery_percentage_view.xml
index deb494fdefbc..59c0957d98cb 100644
--- a/packages/SystemUI/res/layout/battery_percentage_view.xml
+++ b/packages/SystemUI/res/layout/battery_percentage_view.xml
@@ -26,4 +26,5 @@
android:textColor="?android:attr/textColorPrimary"
android:gravity="center_vertical|start"
android:paddingEnd="@dimen/battery_level_padding_start"
+ android:importantForAccessibility="no"
/>
diff --git a/packages/SystemUI/res/layout/car_qs_panel.xml b/packages/SystemUI/res/layout/car_qs_panel.xml
index 0b46b0bdaa1c..4cb0fd5fecfb 100644
--- a/packages/SystemUI/res/layout/car_qs_panel.xml
+++ b/packages/SystemUI/res/layout/car_qs_panel.xml
@@ -18,12 +18,13 @@
android:id="@+id/quick_settings_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@drawable/car_qs_background_primary"
+ android:background="@color/car_qs_background_primary"
android:orientation="vertical"
- android:elevation="4dp">
+ android:elevation="4dp"
+ android:theme="@android:style/Theme">
- <include layout="@layout/car_status_bar_header" />
- <include layout="@layout/car_qs_footer" />
+ <include layout="@layout/car_status_bar_header"/>
+ <include layout="@layout/car_qs_footer"/>
<com.android.systemui.statusbar.car.UserGridView
android:id="@+id/user_grid"
diff --git a/packages/SystemUI/res/layout/navigation_layout.xml b/packages/SystemUI/res/layout/navigation_layout.xml
index 53f5dfe1acbe..3e6079451c74 100644
--- a/packages/SystemUI/res/layout/navigation_layout.xml
+++ b/packages/SystemUI/res/layout/navigation_layout.xml
@@ -21,8 +21,8 @@
android:layout_height="match_parent"
android:layout_marginStart="@dimen/rounded_corner_content_padding"
android:layout_marginEnd="@dimen/rounded_corner_content_padding"
- android:paddingStart="8dp"
- android:paddingEnd="8dp">
+ android:paddingStart="@dimen/nav_content_padding"
+ android:paddingEnd="@dimen/nav_content_padding">
<com.android.systemui.statusbar.phone.NearestTouchFrame
android:id="@+id/nav_buttons"
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 849bea49a62c..2cf3e4ac3f19 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
@@ -37,6 +37,7 @@
android:ellipsize="marquee"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"
+ android:textDirection="locale"
android:singleLine="true" />
<com.android.systemui.BatteryMeterView android:id="@+id/battery"
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 1b1d53cb8fd3..8adf1542558e 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -775,5 +775,5 @@
<string name="running_foreground_services_title" msgid="381024150898615683">"កម្មវិធីដែលកំពុងដំណើរការនៅផ្ទៃខាងក្រោយ"</string>
<string name="running_foreground_services_msg" msgid="6326247670075574355">"ចុចដើម្បីមើលព័ត៌មានលម្អិតអំពីការប្រើប្រាស់ទិន្នន័យ និងថ្ម"</string>
<string name="data_usage_disable_mobile" msgid="5116269981510015864">"បិទទិន្នន័យ​ចល័ត?"</string>
- <string name="touch_filtered_warning" msgid="8671693809204767551">"ការកំណត់​មិនអាច​ផ្ទៀងផ្ទាត់​ការឆ្លើយតប​របស់អ្នក​បាន​ទេ ដោយសារ​កម្មវិធី​កំពុង​លាក់​សំណើ​សុំការ​អនុញ្ញាត។"</string>
+ <string name="touch_filtered_warning" msgid="8671693809204767551">"ការកំណត់​មិនអាច​ផ្ទៀងផ្ទាត់​ការឆ្លើយតប​របស់អ្នក​បាន​ទេ ដោយសារ​កម្មវិធី​កំពុង​បាំងសំណើ​សុំការ​អនុញ្ញាត។"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 9e915d540915..89749af39acc 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -81,7 +81,7 @@
<string name="use_ptp_button_title" msgid="7517127540301625751">"कॅमेरा म्हणून माउंट करा (PTP)"</string>
<string name="installer_cd_button_title" msgid="2312667578562201583">"Mac साठी Android फाईल स्थानांतर अॅप इंस्टॉल करा"</string>
<string name="accessibility_back" msgid="567011538994429120">"मागे"</string>
- <string name="accessibility_home" msgid="8217216074895377641">"होम स्क्रीन"</string>
+ <string name="accessibility_home" msgid="8217216074895377641">"होम"</string>
<string name="accessibility_menu" msgid="316839303324695949">"मेनू"</string>
<string name="accessibility_accessibility_button" msgid="7601252764577607915">"प्रवेशयोग्यता"</string>
<string name="accessibility_recent" msgid="5208608566793607626">"अवलोकन"</string>
@@ -511,7 +511,7 @@
<string name="status_bar" msgid="4877645476959324760">"स्टेटस बार"</string>
<string name="overview" msgid="4018602013895926956">"अवलोकन"</string>
<string name="demo_mode" msgid="2532177350215638026">"सिस्टीम UI डेमो मोड"</string>
- <string name="enable_demo_mode" msgid="4844205668718636518">"डेमो मोड सक्षम करा"</string>
+ <string name="enable_demo_mode" msgid="4844205668718636518">"डेमो मोड सुरू करा"</string>
<string name="show_demo_mode" msgid="2018336697782464029">"डेमो मोड दर्शवा"</string>
<string name="status_bar_ethernet" msgid="5044290963549500128">"इथरनेट"</string>
<string name="status_bar_alarm" msgid="8536256753575881818">"अलार्म"</string>
@@ -615,7 +615,7 @@
<string name="keyboard_key_num_lock" msgid="5052537581246772117">"Num Lock"</string>
<string name="keyboard_key_numpad_template" msgid="8729216555174634026">"Numpad <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"सिस्टीम"</string>
- <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"होम स्क्रीन"</string>
+ <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"होम"</string>
<string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"अलीकडील"</string>
<string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"परत"</string>
<string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"सूचना"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 691cfdddc176..12101eb6fec2 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -527,12 +527,12 @@
<string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"ਹੌਟਸਪੌਟ"</string>
<string name="accessibility_managed_profile" msgid="6613641363112584120">"ਕੰਮ ਪ੍ਰੋਫਾਈਲ"</string>
<string name="tuner_warning_title" msgid="7094689930793031682">"ਕੁਝ ਵਾਸਤੇ ਤਾਂ ਮਜ਼ੇਦਾਰ ਹੈ ਲੇਕਿਨ ਸਾਰਿਆਂ ਵਾਸਤੇ ਨਹੀਂ"</string>
- <string name="tuner_warning" msgid="8730648121973575701">"ਸਿਸਟਮ UI ਟਿਊਨਰ ਤੁਹਾਨੂੰ Android ਉਪਭੋਗਤਾ ਇੰਟਰਫੇਸ ਤਬਦੀਲ ਕਰਨ ਅਤੇ ਅਨੁਕੂਲਿਤ ਕਰਨ ਲਈ ਵਾਧੂ ਤਰੀਕੇ ਦਿੰਦਾ ਹੈ। ਇਹ ਪ੍ਰਯੋਗਾਤਮਿਕ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਭਵਿੱਖ ਦੀ ਰੀਲੀਜ਼ ਵਿੱਚ ਬਦਲ ਸਕਦੀਆਂ ਹਨ, ਟੁੱਟ ਸਕਦੀਆਂ ਹਨ, ਜਾਂ ਅਲੋਪ ਹੋ ਸਕਦੀਆਂ ਹਨ। ਸਾਵਧਾਨੀ ਨਾਲ ਅੱਗੇ ਵੱਧੋ।"</string>
+ <string name="tuner_warning" msgid="8730648121973575701">"ਸਿਸਟਮ UI ਟਿਊਨਰ ਤੁਹਾਨੂੰ Android ਵਰਤੋਂਕਾਰ ਇੰਟਰਫੇਸ ਤਬਦੀਲ ਕਰਨ ਅਤੇ ਵਿਉਂਤਬੱਧ ਕਰਨ ਲਈ ਵਾਧੂ ਤਰੀਕੇ ਦਿੰਦਾ ਹੈ। ਇਹ ਪ੍ਰਯੋਗਾਤਮਿਕ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਭਵਿੱਖ ਦੀ ਰੀਲੀਜ਼ ਵਿੱਚ ਬਦਲ ਸਕਦੀਆਂ ਹਨ, ਟੁੱਟ ਸਕਦੀਆਂ ਹਨ, ਜਾਂ ਅਲੋਪ ਹੋ ਸਕਦੀਆਂ ਹਨ। ਸਾਵਧਾਨੀ ਨਾਲ ਅੱਗੇ ਵੱਧੋ।"</string>
<string name="tuner_persistent_warning" msgid="8597333795565621795">"ਇਹ ਪ੍ਰਯੋਗਾਤਮਿਕ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਭਵਿੱਖ ਦੀ ਰੀਲੀਜ਼ ਵਿੱਚ ਬਦਲ ਸਕਦੀਆਂ ਹਨ, ਟੁੱਟ ਸਕਦੀਆਂ ਹਨ, ਜਾਂ ਅਲੋਪ ਹੋ ਸਕਦੀਆਂ ਹਨ। ਸਾਵਧਾਨੀ ਨਾਲ ਅੱਗੇ ਵੱਧੋ।"</string>
<string name="got_it" msgid="2239653834387972602">"ਸਮਝ ਲਿਆ"</string>
- <string name="tuner_toast" msgid="603429811084428439">"ਵਧਾਈਆਂ! ਸਿਸਟਮ UI ਟਿਊਨਰ ਨੂੰ ਸੈਟਿੰਗਜ਼ ਵਿੱਚ ਜੋੜਿਆ ਗਿਆ ਹੈ"</string>
+ <string name="tuner_toast" msgid="603429811084428439">"ਵਧਾਈਆਂ! ਸਿਸਟਮ UI ਟਿਊਨਰ ਨੂੰ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜੋੜਿਆ ਗਿਆ ਹੈ"</string>
<string name="remove_from_settings" msgid="8389591916603406378">"ਸੈਟਿੰਗਜ਼ ਤੋਂ ਹਟਾਓ"</string>
- <string name="remove_from_settings_prompt" msgid="6069085993355887748">"ਕੀ ਸੈਟਿੰਗਜ਼ ਤੋਂ ਸਿਸਟਮ UI ਟਿਊਨਰ ਨੂੰ ਹਟਾਉਣਾ ਹੈ ਅਤੇ ਇਸਦੀਆਂ ਸਾਰੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਉਪਯੋਗ ਕਰਨ ਤੋਂ ਰੋਕਣਾ ਹੈ?"</string>
+ <string name="remove_from_settings_prompt" msgid="6069085993355887748">"ਕੀ ਸੈਟਿੰਗਾਂ ਤੋਂ ਸਿਸਟਮ UI ਟਿਊਨਰ ਨੂੰ ਹਟਾਉਣਾ ਹੈ ਅਤੇ ਇਸਦੀਆਂ ਸਾਰੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਉਪਯੋਗ ਕਰਨ ਤੋਂ ਰੋਕਣਾ ਹੈ?"</string>
<string name="activity_not_found" msgid="348423244327799974">"ਐਪਲੀਕੇਸ਼ਨ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਤੇ ਸਥਾਪਤ ਨਹੀਂ ਕੀਤੀ ਗਈ ਹੈ"</string>
<string name="clock_seconds" msgid="7689554147579179507">"ਘੜੀ ਸਕਿੰਟ ਦਿਖਾਓ"</string>
<string name="clock_seconds_desc" msgid="6282693067130470675">"ਸਥਿਤੀ ਬਾਰ ਵਿੱਚ ਘੜੀ ਸਕਿੰਟ ਦਿਖਾਓ। ਬੈਟਰੀ ਸਮਰੱਥਾ ਤੇ ਅਸਰ ਪੈ ਸਕਦਾ ਹੈ।"</string>
diff --git a/packages/SystemUI/res/values-sw372dp/dimens.xml b/packages/SystemUI/res/values-sw372dp/dimens.xml
new file mode 100644
index 000000000000..635185d7f2ad
--- /dev/null
+++ b/packages/SystemUI/res/values-sw372dp/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2006, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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="nav_content_padding">8dp</dimen>
+ <dimen name="rounded_corner_content_padding">8dp</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values/colors_car.xml b/packages/SystemUI/res/values/colors_car.xml
index 9593fe51917c..1b8c2fa68244 100644
--- a/packages/SystemUI/res/values/colors_car.xml
+++ b/packages/SystemUI/res/values/colors_car.xml
@@ -17,6 +17,7 @@
*/
-->
<resources>
+ <color name="car_qs_background_primary">#263238</color> <!-- Blue Gray 900 -->
<color name="car_user_switcher_progress_bgcolor">#00000000</color> <!-- Transparent -->
<color name="car_user_switcher_progress_fgcolor">#80CBC4</color> <!-- Teal 200 -->
<color name="car_user_switcher_no_user_image_bgcolor">#FAFAFA</color> <!-- Grey 50 -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index c8e6021d6f89..54421f74419e 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -846,7 +846,8 @@
<dimen name="edge_margin">16dp</dimen>
<dimen name="rounded_corner_radius">0dp</dimen>
- <dimen name="rounded_corner_content_padding">8dp</dimen>
+ <dimen name="rounded_corner_content_padding">0dp</dimen>
+ <dimen name="nav_content_padding">0dp</dimen>
<!-- Intended corner radius when drawing the mobile signal -->
<dimen name="stat_sys_mobile_signal_corner_radius">0.75dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index abc3b94777b0..775b9e8a4d3b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -223,8 +223,9 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
@Override
public void onTick(long millisUntilFinished) {
int secondsRemaining = (int) Math.round(millisUntilFinished / 1000.0);
- mSecurityMessageDisplay.formatMessage(
- R.string.kg_too_many_failed_attempts_countdown, secondsRemaining);
+ mSecurityMessageDisplay.setMessage(mContext.getResources().getQuantityString(
+ R.plurals.kg_too_many_failed_attempts_countdown,
+ secondsRemaining, secondsRemaining));
}
@Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 3c9a6b9dcdec..ec5f356a1a55 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -332,8 +332,9 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
@Override
public void onTick(long millisUntilFinished) {
final int secondsRemaining = (int) Math.round(millisUntilFinished / 1000.0);
- mSecurityMessageDisplay.formatMessage(
- R.string.kg_too_many_failed_attempts_countdown, secondsRemaining);
+ mSecurityMessageDisplay.setMessage(mContext.getResources().getQuantityString(
+ R.plurals.kg_too_many_failed_attempts_countdown,
+ secondsRemaining, secondsRemaining));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index c4de63bdd303..fd2447bd47b4 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -18,6 +18,7 @@ package com.android.systemui;
import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
import android.animation.ArgbEvaluator;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -40,6 +41,7 @@ import android.widget.TextView;
import com.android.settingslib.Utils;
import com.android.settingslib.graph.BatteryMeterDrawableBase;
+import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
@@ -58,6 +60,7 @@ public class BatteryMeterView extends LinearLayout implements
private final BatteryMeterDrawableBase mDrawable;
private final String mSlotBattery;
private final ImageView mBatteryIconView;
+ private final CurrentUserTracker mUserTracker;
private TextView mBatteryPercentView;
private BatteryController mBatteryController;
@@ -72,6 +75,7 @@ public class BatteryMeterView extends LinearLayout implements
private int mLightModeBackgroundColor;
private int mLightModeFillColor;
private float mDarkIntensity;
+ private int mUser;
public BatteryMeterView(Context context) {
this(context, null, 0);
@@ -120,6 +124,16 @@ public class BatteryMeterView extends LinearLayout implements
// Init to not dark at all.
onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
+ mUserTracker = new CurrentUserTracker(mContext) {
+ @Override
+ public void onUserSwitched(int newUserId) {
+ mUser = newUserId;
+ getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
+ getContext().getContentResolver().registerContentObserver(
+ Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver,
+ newUserId);
+ }
+ };
}
public void setForceShowPercent(boolean show) {
@@ -145,16 +159,19 @@ public class BatteryMeterView extends LinearLayout implements
super.onAttachedToWindow();
mBatteryController = Dependency.get(BatteryController.class);
mBatteryController.addCallback(this);
+ mUser = ActivityManager.getCurrentUser();
getContext().getContentResolver().registerContentObserver(
- Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver);
+ Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver, mUser);
updateShowPercent();
Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
Dependency.get(ConfigurationController.class).addCallback(this);
+ mUserTracker.startTracking();
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
+ mUserTracker.stopTracking();
mBatteryController.removeCallback(this);
getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
Dependency.get(TunerService.class).removeTunable(this);
@@ -191,8 +208,8 @@ public class BatteryMeterView extends LinearLayout implements
private void updateShowPercent() {
final boolean showing = mBatteryPercentView != null;
- if (0 != Settings.System.getInt(getContext().getContentResolver(),
- SHOW_BATTERY_PERCENT, 0) || mForceShowPercent) {
+ if (0 != Settings.System.getIntForUser(getContext().getContentResolver(),
+ SHOW_BATTERY_PERCENT, 0, mUser) || mForceShowPercent) {
if (!showing) {
mBatteryPercentView = loadPercentView();
if (mTextColor != 0) mBatteryPercentView.setTextColor(mTextColor);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java b/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java
new file mode 100644
index 000000000000..d1d180819eef
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/AlwaysOnDisplayPolicy.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.doze;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.provider.Settings;
+import android.text.format.DateUtils;
+import android.util.KeyValueListParser;
+import android.util.Log;
+
+import com.android.systemui.R;
+
+import java.util.Arrays;
+
+/**
+ * Class to store the policy for AOD, which comes from
+ * {@link android.provider.Settings.Global}
+ */
+public class AlwaysOnDisplayPolicy {
+ public static final String TAG = "AlwaysOnDisplayPolicy";
+
+ static final String KEY_SCREEN_BRIGHTNESS_ARRAY = "screen_brightness_array";
+ static final String KEY_DIMMING_SCRIM_ARRAY = "dimming_scrim_array";
+ static final String KEY_PROX_SCREEN_OFF_DELAY_MS = "prox_screen_off_delay";
+ static final String KEY_PROX_COOLDOWN_TRIGGER_MS = "prox_cooldown_trigger";
+ static final String KEY_PROX_COOLDOWN_PERIOD_MS = "prox_cooldown_period";
+
+ /**
+ * Integer array to map ambient brightness type to real screen brightness.
+ *
+ * @see Settings.Global#ALWAYS_ON_DISPLAY_CONSTANTS
+ * @see #KEY_SCREEN_BRIGHTNESS_ARRAY
+ */
+ public final int[] screenBrightnessArray;
+
+ /**
+ * Integer array to map ambient brightness type to dimming scrim.
+ *
+ * @see Settings.Global#ALWAYS_ON_DISPLAY_CONSTANTS
+ * @see #KEY_DIMMING_SCRIM_ARRAY
+ */
+ public final int[] dimmingScrimArray;
+
+ /**
+ * Delay time(ms) from covering the prox to turning off the screen.
+ *
+ * @see Settings.Global#ALWAYS_ON_DISPLAY_CONSTANTS
+ * @see #KEY_PROX_SCREEN_OFF_DELAY_MS
+ */
+ public final long proxScreenOffDelayMs;
+
+ /**
+ * The threshold time(ms) to trigger the cooldown timer, which will
+ * turn off prox sensor for a period.
+ *
+ * @see Settings.Global#ALWAYS_ON_DISPLAY_CONSTANTS
+ * @see #KEY_PROX_COOLDOWN_TRIGGER_MS
+ */
+ public final long proxCooldownTriggerMs;
+
+ /**
+ * The period(ms) to turning off the prox sensor if
+ * {@link #KEY_PROX_COOLDOWN_TRIGGER_MS} is triggered.
+ *
+ * @see Settings.Global#ALWAYS_ON_DISPLAY_CONSTANTS
+ * @see #KEY_PROX_COOLDOWN_PERIOD_MS
+ */
+ public final long proxCooldownPeriodMs;
+
+ private final KeyValueListParser mParser;
+
+ public AlwaysOnDisplayPolicy(Context context) {
+ final Resources resources = context.getResources();
+ mParser = new KeyValueListParser(',');
+
+ final String value = Settings.Global.getString(context.getContentResolver(),
+ Settings.Global.ALWAYS_ON_DISPLAY_CONSTANTS);
+
+ try {
+ mParser.setString(value);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Bad AOD constants");
+ }
+
+ proxScreenOffDelayMs = mParser.getLong(KEY_PROX_SCREEN_OFF_DELAY_MS,
+ 10 * DateUtils.MINUTE_IN_MILLIS);
+ proxCooldownTriggerMs = mParser.getLong(KEY_PROX_COOLDOWN_TRIGGER_MS,
+ 2 * DateUtils.MINUTE_IN_MILLIS);
+ proxCooldownPeriodMs = mParser.getLong(KEY_PROX_COOLDOWN_PERIOD_MS,
+ 5 * DateUtils.MINUTE_IN_MILLIS);
+ screenBrightnessArray = parseIntArray(KEY_SCREEN_BRIGHTNESS_ARRAY,
+ resources.getIntArray(R.array.config_doze_brightness_sensor_to_brightness));
+ dimmingScrimArray = parseIntArray(KEY_DIMMING_SCRIM_ARRAY,
+ resources.getIntArray(R.array.config_doze_brightness_sensor_to_scrim_opacity));
+ }
+
+ private int[] parseIntArray(final String key, final int[] defaultArray) {
+ final String value = mParser.getString(key, null);
+ if (value != null) {
+ return Arrays.stream(value.split(":")).map(String::trim).mapToInt(
+ Integer::parseInt).toArray();
+ } else {
+ return defaultArray;
+ }
+ }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index d374d68a456b..6f8bcff16a83 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -59,7 +59,7 @@ public class DozeFactory {
DozeMachine machine = new DozeMachine(wrappedService, config, wakeLock);
machine.setParts(new DozeMachine.Part[]{
- new DozePauser(handler, machine, alarmManager),
+ new DozePauser(handler, machine, alarmManager, new AlwaysOnDisplayPolicy(context)),
new DozeFalsingManagerAdapter(FalsingManager.getInstance(context)),
createDozeTriggers(context, sensorManager, host, alarmManager, config, params,
handler, wakeLock, machine),
@@ -76,7 +76,8 @@ public class DozeFactory {
Handler handler) {
Sensor sensor = DozeSensors.findSensorWithType(sensorManager,
context.getString(R.string.doze_brightness_sensor_type));
- return new DozeScreenBrightness(context, service, sensorManager, sensor, host, handler);
+ return new DozeScreenBrightness(context, service, sensorManager, sensor, host, handler,
+ new AlwaysOnDisplayPolicy(context));
}
private DozeTriggers createDozeTriggers(Context context, SensorManager sensorManager,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java b/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java
index a33b454c6430..76a190213ba3 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozePauser.java
@@ -26,20 +26,22 @@ import com.android.systemui.util.AlarmTimeout;
*/
public class DozePauser implements DozeMachine.Part {
public static final String TAG = DozePauser.class.getSimpleName();
- private static final long TIMEOUT = 10 * 1000;
private final AlarmTimeout mPauseTimeout;
private final DozeMachine mMachine;
+ private final long mTimeoutMs;
- public DozePauser(Handler handler, DozeMachine machine, AlarmManager alarmManager) {
+ public DozePauser(Handler handler, DozeMachine machine, AlarmManager alarmManager,
+ AlwaysOnDisplayPolicy policy) {
mMachine = machine;
mPauseTimeout = new AlarmTimeout(alarmManager, this::onTimeout, TAG, handler);
+ mTimeoutMs = policy.proxScreenOffDelayMs;
}
@Override
public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
switch (newState) {
case DOZE_AOD_PAUSING:
- mPauseTimeout.schedule(TIMEOUT, AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
+ mPauseTimeout.schedule(mTimeoutMs, AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
break;
default:
mPauseTimeout.cancel();
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index 30420529df56..11b4b0ef8294 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -42,7 +42,7 @@ public class DozeScreenBrightness implements DozeMachine.Part, SensorEventListen
public DozeScreenBrightness(Context context, DozeMachine.Service service,
SensorManager sensorManager, Sensor lightSensor, DozeHost host,
- Handler handler) {
+ Handler handler, AlwaysOnDisplayPolicy policy) {
mContext = context;
mDozeService = service;
mSensorManager = sensorManager;
@@ -50,10 +50,8 @@ public class DozeScreenBrightness implements DozeMachine.Part, SensorEventListen
mDozeHost = host;
mHandler = handler;
- mSensorToBrightness = context.getResources().getIntArray(
- R.array.config_doze_brightness_sensor_to_brightness);
- mSensorToScrimOpacity = context.getResources().getIntArray(
- R.array.config_doze_brightness_sensor_to_scrim_opacity);
+ mSensorToBrightness = policy.screenBrightnessArray;
+ mSensorToScrimOpacity = policy.dimmingScrimArray;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 566353c74b57..91cde378c41b 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -72,7 +72,7 @@ public class DozeSensors {
public DozeSensors(Context context, AlarmManager alarmManager, SensorManager sensorManager,
DozeParameters dozeParameters,
AmbientDisplayConfiguration config, WakeLock wakeLock, Callback callback,
- Consumer<Boolean> proxCallback) {
+ Consumer<Boolean> proxCallback, AlwaysOnDisplayPolicy policy) {
mContext = context;
mAlarmManager = alarmManager;
mSensorManager = sensorManager;
@@ -112,7 +112,7 @@ public class DozeSensors {
true /* touchscreen */),
};
- mProxSensor = new ProxSensor();
+ mProxSensor = new ProxSensor(policy);
mCallback = callback;
}
@@ -206,17 +206,16 @@ public class DozeSensors {
private class ProxSensor implements SensorEventListener {
- static final long COOLDOWN_TRIGGER = 2 * 1000;
- static final long COOLDOWN_PERIOD = 5 * 1000;
-
boolean mRequested;
boolean mRegistered;
Boolean mCurrentlyFar;
long mLastNear;
final AlarmTimeout mCooldownTimer;
+ final AlwaysOnDisplayPolicy mPolicy;
- public ProxSensor() {
+ public ProxSensor(AlwaysOnDisplayPolicy policy) {
+ mPolicy = policy;
mCooldownTimer = new AlarmTimeout(mAlarmManager, this::updateRegistered,
"prox_cooldown", mHandler);
}
@@ -264,11 +263,12 @@ public class DozeSensors {
// Sensor has been unregistered by the proxCallback. Do nothing.
} else if (!mCurrentlyFar) {
mLastNear = now;
- } else if (mCurrentlyFar && now - mLastNear < COOLDOWN_TRIGGER) {
+ } else if (mCurrentlyFar && now - mLastNear < mPolicy.proxCooldownTriggerMs) {
// If the last near was very recent, we might be using more power for prox
// wakeups than we're saving from turning of the screen. Instead, turn it off
// for a while.
- mCooldownTimer.schedule(COOLDOWN_PERIOD, AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
+ mCooldownTimer.schedule(mPolicy.proxCooldownPeriodMs,
+ AlarmTimeout.MODE_IGNORE_IF_SCHEDULED);
updateRegistered();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 45831601a0f2..f7a258a2c959 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -84,7 +84,8 @@ public class DozeTriggers implements DozeMachine.Part {
mWakeLock = wakeLock;
mAllowPulseTriggers = allowPulseTriggers;
mDozeSensors = new DozeSensors(context, alarmManager, mSensorManager, dozeParameters,
- config, wakeLock, this::onSensor, this::onProximityFar);
+ config, wakeLock, this::onSensor, this::onProximityFar,
+ new AlwaysOnDisplayPolicy(context));
mUiModeManager = mContext.getSystemService(UiModeManager.class);
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index ca58080c0260..e8c129521010 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -127,6 +127,10 @@ public class PipManager implements BasePipManager {
private PipNotification mPipNotification;
private ParceledListSlice mCustomActions;
+ // Keeps track of the IME visibility to adjust the PiP when the IME is visible
+ private boolean mImeVisible;
+ private int mImeHeightAdjustment;
+
private final PinnedStackListener mPinnedStackListener = new PinnedStackListener();
private final Runnable mResizePinnedStackRunnable = new Runnable() {
@@ -175,7 +179,22 @@ public class PipManager implements BasePipManager {
public void onListenerRegistered(IPinnedStackController controller) {}
@Override
- public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {}
+ public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
+ if (mState == STATE_PIP) {
+ if (mImeVisible != imeVisible) {
+ if (imeVisible) {
+ // Save the IME height adjustment, and offset to not occlude the IME
+ mPipBounds.offset(0, -imeHeight);
+ mImeHeightAdjustment = imeHeight;
+ } else {
+ // Apply the inverse adjustment when the IME is hidden
+ mPipBounds.offset(0, mImeHeightAdjustment);
+ }
+ mImeVisible = imeVisible;
+ resizePinnedStack(STATE_PIP);
+ }
+ }
+ }
@Override
public void onMinimizedStateChanged(boolean isMinimized) {}
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
index f66331525ab7..82c0128c10c0 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -136,11 +136,12 @@ public class PluginInstanceManager<T extends Plugin> {
return disableAny;
}
- public void disableAll() {
+ public boolean disableAll() {
ArrayList<PluginInfo> plugins = new ArrayList<>(mPluginHandler.mPlugins);
for (int i = 0; i < plugins.size(); i++) {
disable(plugins.get(i));
}
+ return plugins.size() != 0;
}
private void disable(PluginInfo info) {
@@ -182,6 +183,7 @@ public class PluginInstanceManager<T extends Plugin> {
if (DEBUG) Log.d(TAG, "onPluginConnected");
PluginPrefs.setHasPlugins(mContext);
PluginInfo<T> info = (PluginInfo<T>) msg.obj;
+ mManager.handleWtfs();
if (!(msg.obj instanceof PluginFragment)) {
// Only call onDestroy for plugins that aren't fragments, as fragments
// will get the onCreate as part of the fragment lifecycle.
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
index 493d244f5e99..03747d50a6fa 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
@@ -36,6 +36,9 @@ import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
+import android.util.Log;
+import android.util.Log.TerribleFailure;
+import android.util.Log.TerribleFailureHandler;
import android.widget.Toast;
import com.android.internal.annotations.VisibleForTesting;
@@ -71,10 +74,11 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
private boolean mListening;
private boolean mHasOneShot;
private Looper mLooper;
+ private boolean mWtfsSet;
public PluginManagerImpl(Context context) {
this(context, new PluginInstanceManagerFactory(),
- Build.IS_DEBUGGABLE, Thread.getDefaultUncaughtExceptionHandler());
+ Build.IS_DEBUGGABLE, Thread.getUncaughtExceptionPreHandler());
}
@VisibleForTesting
@@ -88,7 +92,7 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
PluginExceptionHandler uncaughtExceptionHandler = new PluginExceptionHandler(
defaultHandler);
- Thread.setDefaultUncaughtExceptionHandler(uncaughtExceptionHandler);
+ Thread.setUncaughtExceptionPreHandler(uncaughtExceptionHandler);
if (isDebuggable) {
new Handler(mLooper).post(() -> {
// Plugin dependencies that don't have another good home can go here, but
@@ -290,6 +294,15 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
return false;
}
+ public void handleWtfs() {
+ if (!mWtfsSet) {
+ mWtfsSet = true;
+ Log.setWtfHandler((tag, what, system) -> {
+ throw new CrashWhilePluginActiveException(what);
+ });
+ }
+ }
+
@VisibleForTesting
public static class PluginInstanceManagerFactory {
public <T extends Plugin> PluginInstanceManager createPluginInstanceManager(Context context,
@@ -339,9 +352,12 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
// disable all the plugins, so we can be sure that SysUI is running as
// best as possible.
for (PluginInstanceManager manager : mPluginMap.values()) {
- manager.disableAll();
+ disabledAny |= manager.disableAll();
}
}
+ if (disabledAny) {
+ throwable = new CrashWhilePluginActiveException(throwable);
+ }
// Run the normal exception handler so we can crash and cleanup our state.
mHandler.uncaughtException(thread, throwable);
@@ -358,4 +374,10 @@ public class PluginManagerImpl extends BroadcastReceiver implements PluginManage
return disabledAny | checkStack(throwable.getCause());
}
}
+
+ private class CrashWhilePluginActiveException extends RuntimeException {
+ public CrashWhilePluginActiveException(Throwable throwable) {
+ super(throwable);
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index 10514a7f0c7f..8b434a546504 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -323,7 +323,7 @@ public class QSDetail extends LinearLayout {
post(new Runnable() {
@Override
public void run() {
- handleShowingDetail(detail, x, y, true /* toggleQs */);
+ handleShowingDetail(detail, x, y, false /* toggleQs */);
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
index f91aa9a6d0b0..b4cc4b1586a2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailItems.java
@@ -184,7 +184,11 @@ public class QSDetailItems extends FrameLayout {
}
view.setVisibility(mItemsVisible ? VISIBLE : INVISIBLE);
final ImageView iv = (ImageView) view.findViewById(android.R.id.icon);
- iv.setImageResource(item.icon);
+ if (item.iconDrawable != null) {
+ iv.setImageDrawable(item.iconDrawable);
+ } else {
+ iv.setImageResource(item.icon);
+ }
iv.getOverlay().clear();
if (item.overlay != null) {
item.overlay.setBounds(0, 0, mQsDetailIconOverlaySize, mQsDetailIconOverlaySize);
@@ -254,6 +258,7 @@ public class QSDetailItems extends FrameLayout {
public static class Item {
public int icon;
+ public Drawable iconDrawable;
public Drawable overlay;
public CharSequence line1;
public CharSequence line2;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index 9eb29f8bfae8..3aa78676d755 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -45,6 +45,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.keyguard.KeyguardStatusView;
import com.android.settingslib.Utils;
+import com.android.settingslib.drawable.UserIconDrawable;
import com.android.systemui.Dependency;
import com.android.systemui.FontSizeUtils;
import com.android.systemui.R;
@@ -404,8 +405,9 @@ public class QSFooterImpl extends FrameLayout implements QSFooter,
@Override
public void onUserInfoChanged(String name, Drawable picture, String userAccount) {
if (picture != null &&
- UserManager.get(mContext).isGuestUser(ActivityManager.getCurrentUser())) {
- picture = picture.getConstantState().newDrawable().mutate();
+ UserManager.get(mContext).isGuestUser(ActivityManager.getCurrentUser()) &&
+ !(picture instanceof UserIconDrawable)) {
+ picture = picture.getConstantState().newDrawable(mContext.getResources()).mutate();
picture.setColorFilter(
Utils.getColorAttr(mContext, android.R.attr.colorForeground),
Mode.SRC_IN);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 0a0d2ce00a1b..bdc5e7d75b48 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -556,7 +556,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
@Override
public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) {
- if (viewHolder.getItemViewType() == TYPE_EDIT) {
+ if (viewHolder.getItemViewType() == TYPE_EDIT || viewHolder.getItemViewType() == TYPE_DIVIDER) {
return makeMovementFlags(0, 0);
}
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.RIGHT
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 12fccda907ff..bc6233d45a67 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -16,6 +16,8 @@
package com.android.systemui.qs.tiles;
+import static com.android.settingslib.graph.BluetoothDeviceLayerDrawable.createLayerDrawable;
+
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
@@ -32,8 +34,10 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settingslib.Utils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.graph.BluetoothDeviceLayerDrawable;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.R.drawable;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.DetailAdapter;
import com.android.systemui.plugins.qs.QSTile.BooleanState;
@@ -127,6 +131,15 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
if (connected) {
state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_connected);
state.label = mController.getLastDeviceName();
+ CachedBluetoothDevice lastDevice = mController.getLastDevice();
+ if (lastDevice != null) {
+ int batteryLevel = lastDevice.getBatteryLevel();
+ if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
+ BluetoothDeviceLayerDrawable drawable = createLayerDrawable(mContext,
+ R.drawable.ic_qs_bluetooth_connected, batteryLevel);
+ state.icon = new DrawableIcon(drawable);
+ }
+ }
state.contentDescription = mContext.getString(
R.string.accessibility_bluetooth_name, state.label);
} else if (state.isTransient) {
@@ -278,6 +291,8 @@ public class BluetoothTile extends QSTileImpl<BooleanState> {
item.icon = R.drawable.ic_qs_bluetooth_connected;
int batteryLevel = device.getBatteryLevel();
if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
+ item.iconDrawable = createLayerDrawable(mContext, item.icon,
+ batteryLevel);
item.line2 = mContext.getString(
R.string.quick_settings_connected_battery_level,
Utils.formatPercentage(batteryLevel));
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 4a8b43ec62db..3e1522d2b53c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -565,6 +565,13 @@ public class Recents extends SystemUI
mImpl.showPrevAffiliatedTask();
}
+ @Override
+ public void appTransitionFinished() {
+ // Fallback, reset the flag once an app transition ends
+ EventBus.getDefault().send(new SetWaitingForTransitionStartEvent(
+ false /* waitingForTransitionStart */));
+ }
+
/**
* Updates on configuration change.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 79558a33fc4e..aecf95fc677f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -132,6 +132,11 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
// Preloads the next task
RecentsConfiguration config = Recents.getConfiguration();
if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
+ Rect windowRect = getWindowRect(null /* windowRectOverride */);
+ if (windowRect.isEmpty()) {
+ return;
+ }
+
// Load the next task only if we aren't svelte
SystemServicesProxy ssp = Recents.getSystemServices();
ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getRunningTask();
@@ -146,8 +151,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
// This callback is made when a new activity is launched and the old one is
// paused so ignore the current activity and try and preload the thumbnail for
// the previous one.
- updateDummyStackViewLayout(mBackgroundLayoutAlgorithm, stack,
- getWindowRect(null /* windowRectOverride */));
+ updateDummyStackViewLayout(mBackgroundLayoutAlgorithm, stack, windowRect);
// Launched from app is always the worst case (in terms of how many
// thumbnails/tasks visible)
@@ -376,6 +380,12 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
}
public void toggleRecents(int growTarget) {
+ // Skip preloading if the task is locked
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (ssp.isScreenPinningActive()) {
+ return;
+ }
+
// Skip this toggle if we are already waiting to trigger recents via alt-tab
if (mFastAltTabTrigger.isDozing()) {
return;
@@ -391,7 +401,6 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
mTriggeredFromAltTab = false;
try {
- SystemServicesProxy ssp = Recents.getSystemServices();
MutableBoolean isHomeStackVisible = new MutableBoolean(true);
long elapsedTime = SystemClock.elapsedRealtime() - mLastToggleTime;
@@ -454,11 +463,16 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
}
public void preloadRecents() {
+ // Skip preloading if the task is locked
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ if (ssp.isScreenPinningActive()) {
+ return;
+ }
+
// Preload only the raw task list into a new load plan (which will be consumed by the
// RecentsActivity) only if there is a task to animate to. Post this to ensure that we
// don't block the touch feedback on the nav bar button which triggers this.
mHandler.post(() -> {
- SystemServicesProxy ssp = Recents.getSystemServices();
MutableBoolean isHomeStackVisible = new MutableBoolean(true);
if (!ssp.isRecentsActivityVisible(isHomeStackVisible)) {
ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index c66b2dd8eec5..717778228989 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -47,7 +47,6 @@ import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PorterDuff;
@@ -59,7 +58,6 @@ import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.Message;
-import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
@@ -95,9 +93,7 @@ import com.android.systemui.recents.RecentsImpl;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.ThumbnailData;
import com.android.systemui.statusbar.policy.UserInfoController;
-import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
@@ -717,21 +713,7 @@ public class SystemServicesProxy {
return thumbnailData;
}
- ThumbnailData thumbnailData = getThumbnail(taskId, reduced);
- if (thumbnailData.thumbnail != null && !ActivityManager.ENABLE_TASK_SNAPSHOTS) {
- thumbnailData.thumbnail.setHasAlpha(false);
- // We use a dumb heuristic for now, if the thumbnail is purely transparent in the top
- // left pixel, then assume the whole thumbnail is transparent. Generally, proper
- // screenshots are always composed onto a bitmap that has no alpha.
- if (Color.alpha(thumbnailData.thumbnail.getPixel(0, 0)) == 0) {
- mBgProtectionCanvas.setBitmap(thumbnailData.thumbnail);
- mBgProtectionCanvas.drawRect(0, 0, thumbnailData.thumbnail.getWidth(),
- thumbnailData.thumbnail.getHeight(), mBgProtectionPaint);
- mBgProtectionCanvas.setBitmap(null);
- Log.e(TAG, "Invalid screenshot detected from getTaskThumbnail()");
- }
- }
- return thumbnailData;
+ return getThumbnail(taskId, reduced);
}
/**
@@ -742,43 +724,17 @@ public class SystemServicesProxy {
return new ThumbnailData();
}
- final ThumbnailData thumbnailData;
- if (ActivityManager.ENABLE_TASK_SNAPSHOTS) {
- ActivityManager.TaskSnapshot snapshot = null;
- try {
- snapshot = ActivityManager.getService().getTaskSnapshot(taskId, reducedResolution);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to retrieve snapshot", e);
- }
- if (snapshot != null) {
- thumbnailData = ThumbnailData.createFromTaskSnapshot(snapshot);
- } else {
- return new ThumbnailData();
- }
+ ActivityManager.TaskSnapshot snapshot = null;
+ try {
+ snapshot = ActivityManager.getService().getTaskSnapshot(taskId, reducedResolution);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to retrieve snapshot", e);
+ }
+ if (snapshot != null) {
+ return ThumbnailData.createFromTaskSnapshot(snapshot);
} else {
- ActivityManager.TaskThumbnail taskThumbnail = mAm.getTaskThumbnail(taskId);
- if (taskThumbnail == null) {
- return new ThumbnailData();
- }
-
- Bitmap thumbnail = taskThumbnail.mainThumbnail;
- ParcelFileDescriptor descriptor = taskThumbnail.thumbnailFileDescriptor;
- if (thumbnail == null && descriptor != null) {
- thumbnail = BitmapFactory.decodeFileDescriptor(descriptor.getFileDescriptor(),
- null, sBitmapOptions);
- }
- if (descriptor != null) {
- try {
- descriptor.close();
- } catch (IOException e) {
- }
- }
- thumbnailData = new ThumbnailData();
- thumbnailData.thumbnail = thumbnail;
- thumbnailData.orientation = taskThumbnail.thumbnailInfo.screenOrientation;
- thumbnailData.insets.setEmpty();
+ return new ThumbnailData();
}
- return thumbnailData;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 29d0a2372769..9e6bf85445a0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -17,11 +17,9 @@
package com.android.systemui.recents.model;
import android.app.ActivityManager;
-import android.app.ActivityManager.TaskThumbnail;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
-import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -35,7 +33,6 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Objects;
-
/**
* A task represents the top most task in the system's task stack.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
index dba085e37427..7998ecb4290a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
@@ -51,7 +51,7 @@ public class AnimateableViewBounds extends ViewOutlineProvider {
* Resets the right and bottom clip for this view.
*/
public void reset() {
- mClipRect.set(-1, -1, -1, -1);
+ mClipRect.set(0, 0, 0, 0);
updateClipBounds();
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 45835d51ff90..bf98a835f104 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -596,7 +596,7 @@ public class DividerView extends FrameLayout implements OnTouchListener,
Runnable endAction = () -> {
commitSnapFlags(snapTarget);
mWindowManagerProxy.setResizing(false);
- mDockSide = WindowManager.DOCKED_INVALID;
+ updateDockSide();
mCurrentAnimator = null;
mEntranceAnimationRunning = false;
mExitAnimationRunning = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 74737c4c2948..569e58d78fae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -184,8 +184,15 @@ public class KeyguardIndicationController {
mVisible = visible;
mIndicationArea.setVisibility(visible ? View.VISIBLE : View.GONE);
if (visible) {
- hideTransientIndication();
+ // If this is called after an error message was already shown, we should not clear it.
+ // Otherwise the error message won't be shown
+ if (!mHandler.hasMessages(MSG_HIDE_TRANSIENT)) {
+ hideTransientIndication();
+ }
updateIndication();
+ } else if (!visible) {
+ // If we unlock and return to keyguard quickly, previous error should not be shown
+ hideTransientIndication();
}
}
@@ -389,7 +396,6 @@ public class KeyguardIndicationController {
hideTransientIndication();
} else if (msg.what == MSG_CLEAR_FP_MSG) {
mLockIcon.setTransientFpError(false);
- hideTransientIndication();
}
}
};
@@ -443,10 +449,10 @@ public class KeyguardIndicationController {
int errorColor = Utils.getColorError(mContext);
if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
mStatusBarKeyguardViewManager.showBouncerMessage(helpString, errorColor);
- } else if (updateMonitor.isDeviceInteractive()
- || mDozing && updateMonitor.isScreenOn()) {
+ } else if (updateMonitor.isScreenOn()) {
mLockIcon.setTransientFpError(true);
showTransientIndication(helpString, errorColor);
+ hideTransientIndicationDelayed(TRANSIENT_FP_ERROR_TIMEOUT);
mHandler.removeMessages(MSG_CLEAR_FP_MSG);
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_FP_MSG),
TRANSIENT_FP_ERROR_TIMEOUT);
@@ -459,7 +465,8 @@ public class KeyguardIndicationController {
@Override
public void onFingerprintError(int msgId, String errString) {
KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
- if (!updateMonitor.isUnlockingWithFingerprintAllowed()
+ if ((!updateMonitor.isUnlockingWithFingerprintAllowed()
+ && msgId != FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT)
|| msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
return;
}
@@ -472,7 +479,7 @@ public class KeyguardIndicationController {
if (mLastSuccessiveErrorMessage != msgId) {
mStatusBarKeyguardViewManager.showBouncerMessage(errString, errorColor);
}
- } else if (updateMonitor.isDeviceInteractive()) {
+ } else if (updateMonitor.isScreenOn()) {
showTransientIndication(errString, errorColor);
// We want to keep this message around in case the screen was off
hideTransientIndicationDelayed(HIDE_DELAY_MS);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
index f3c2bc56b409..f379a4636623 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
@@ -75,6 +75,10 @@ public class BarTransitions {
return mMode;
}
+ public void setAutoDim(boolean autoDim) {
+ // Default is don't care.
+ }
+
/**
* @param alwaysOpaque if {@code true}, the bar's background will always be opaque, regardless
* of what mode it is currently set to.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index 5c040588b266..8c923cbcde0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -14,6 +14,9 @@
package com.android.systemui.statusbar.phone;
+import static android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS;
+import static android.app.StatusBarManager.DISABLE_SYSTEM_INFO;
+
import static com.android.systemui.statusbar.phone.StatusBar.reinflateSignalCluster;
import android.annotation.Nullable;
@@ -144,35 +147,39 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
final int old1 = mDisabled1;
final int diff1 = state1 ^ old1;
mDisabled1 = state1;
- if ((diff1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
- if ((state1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
+ if ((diff1 & DISABLE_SYSTEM_INFO) != 0) {
+ if ((state1 & DISABLE_SYSTEM_INFO) != 0) {
hideSystemIconArea(animate);
} else {
showSystemIconArea(animate);
}
}
- if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
- if ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+ if ((diff1 & DISABLE_NOTIFICATION_ICONS) != 0) {
+ if ((state1 & DISABLE_NOTIFICATION_ICONS) != 0) {
hideNotificationIconArea(animate);
} else {
showNotificationIconArea(animate);
}
}
+ if (!BarTransitions.HIGH_END) {
+ int mask = DISABLE_NOTIFICATION_ICONS | DISABLE_SYSTEM_INFO;
+ getView().setVisibility((mDisabled1 & mask) == mask ? View.GONE : View.VISIBLE);
+ }
}
protected int adjustDisableFlags(int state) {
if (!mStatusBarComponent.isLaunchTransitionFadingAway()
&& !mKeyguardMonitor.isKeyguardFadingAway()
&& shouldHideNotificationIcons()) {
- state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
- state |= StatusBarManager.DISABLE_SYSTEM_INFO;
+ state |= DISABLE_NOTIFICATION_ICONS;
+ state |= DISABLE_SYSTEM_INFO;
}
if (mNetworkController != null && EncryptionHelper.IS_DATA_ENCRYPTED) {
if (mNetworkController.hasEmergencyCryptKeeperText()) {
- state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
+ state |= DISABLE_NOTIFICATION_ICONS;
}
if (!mNetworkController.isRadioOn()) {
- state |= StatusBarManager.DISABLE_SYSTEM_INFO;
+ state |= DISABLE_SYSTEM_INFO;
}
}
return state;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
index b0ac6ecae5bb..d3a6280212cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
@@ -127,6 +127,11 @@ public class LightBarTransitionsController implements Dumpable, Callbacks {
}
public void setIconsDark(boolean dark, boolean animate) {
+ if (!BarTransitions.HIGH_END) {
+ setIconTintInternal(0.0f);
+ mNextDarkIntensity = 0.0f;
+ return;
+ }
if (!animate) {
setIconTintInternal(dark ? 1.0f : 0.0f);
mNextDarkIntensity = dark ? 1.0f : 0.0f;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index cb925d5f7e16..f3ca66ffa9b3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -32,6 +32,7 @@ public final class NavigationBarTransitions extends BarTransitions {
private final LightBarTransitionsController mLightTransitionsController;
private boolean mLightsOut;
+ private boolean mAutoDim;
public NavigationBarTransitions(NavigationBarView view) {
super(view, R.drawable.nav_background);
@@ -44,7 +45,19 @@ public final class NavigationBarTransitions extends BarTransitions {
public void init() {
applyModeBackground(-1, getMode(), false /*animate*/);
- applyMode(getMode(), false /*animate*/, true /*force*/);
+ applyLightsOut(false /*animate*/, true /*force*/);
+ }
+
+ @Override
+ public void setAutoDim(boolean autoDim) {
+ if (mAutoDim == autoDim) return;
+ mAutoDim = autoDim;
+ applyLightsOut(true, false);
+ }
+
+ @Override
+ protected boolean isLightsOut(int mode) {
+ return super.isLightsOut(mode) || mAutoDim;
}
public LightBarTransitionsController getLightTransitionsController() {
@@ -54,13 +67,12 @@ public final class NavigationBarTransitions extends BarTransitions {
@Override
protected void onTransition(int oldMode, int newMode, boolean animate) {
super.onTransition(oldMode, newMode, animate);
- applyMode(newMode, animate, false /*force*/);
+ applyLightsOut(animate, false /*force*/);
}
- private void applyMode(int mode, boolean animate, boolean force) {
-
+ private void applyLightsOut(boolean animate, boolean force) {
// apply to lights out
- applyLightsOut(isLightsOut(mode), animate, force);
+ applyLightsOut(isLightsOut(getMode()), animate, force);
}
private void applyLightsOut(boolean lightsOut, boolean animate, boolean force) {
@@ -86,7 +98,6 @@ public final class NavigationBarTransitions extends BarTransitions {
}
}
-
public void reapplyDarkIntensity() {
applyDarkIntensity(mLightTransitionsController.getCurrentDarkIntensity());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 46f9c04aa42e..afe5c917a856 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -404,8 +404,8 @@ public abstract class PanelView extends FrameLayout {
false /* collapseWhenFinished */);
notifyBarPanelExpansionChanged();
if (mVibrateOnOpening && !isHapticFeedbackDisabled(mContext)) {
- AsyncTask.execute(
- () -> mVibrator.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_TICK)));
+ AsyncTask.execute(() ->
+ mVibrator.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_TICK, false)));
}
}
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 75db6e92a0f5..7aebfdc5c3bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -558,14 +558,12 @@ public class StatusBar extends SystemUI implements DemoMode,
protected DozeScrimController mDozeScrimController;
private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
- private final Runnable mAutohide = new Runnable() {
- @Override
- public void run() {
- int requested = mSystemUiVisibility & ~STATUS_OR_NAV_TRANSIENT;
- if (mSystemUiVisibility != requested) {
- notifyUiVisibilityChanged(requested);
- }
- }};
+ private final Runnable mAutohide = () -> {
+ int requested = mSystemUiVisibility & ~STATUS_OR_NAV_TRANSIENT;
+ if (mSystemUiVisibility != requested) {
+ notifyUiVisibilityChanged(requested);
+ }
+ };
private boolean mWaitingForKeyguardExit;
protected boolean mDozing;
@@ -3322,6 +3320,7 @@ public class StatusBar extends SystemUI implements DemoMode,
} else {
cancelAutohide();
}
+ touchAutoDim();
}
protected int computeStatusBarMode(int oldVal, int newVal) {
@@ -3407,6 +3406,7 @@ public class StatusBar extends SystemUI implements DemoMode,
dismissVolumeDialog();
}
checkBarModes();
+ touchAutoDim();
}
private void dismissVolumeDialog() {
@@ -3438,6 +3438,16 @@ public class StatusBar extends SystemUI implements DemoMode,
mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS);
}
+ public void touchAutoDim() {
+ if (mNavigationBar != null) {
+ mNavigationBar.getBarTransitions().setAutoDim(false);
+ }
+ mHandler.removeCallbacks(mAutoDim);
+ if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED) {
+ mHandler.postDelayed(mAutoDim, AUTOHIDE_TIMEOUT_MS);
+ }
+ }
+
void checkUserAutohide(View v, MotionEvent event) {
if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0 // a transient bar is revealed
&& event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
@@ -4856,6 +4866,7 @@ public class StatusBar extends SystemUI implements DemoMode,
updateReportRejectedTouchVisibility();
updateDozing();
updateTheme();
+ touchAutoDim();
mNotificationShelf.setStatusBarState(state);
}
@@ -7560,4 +7571,10 @@ public class StatusBar extends SystemUI implements DemoMode,
}
}
// End Extra BaseStatusBarMethods.
+
+ private final Runnable mAutoDim = () -> {
+ if (mNavigationBar != null) {
+ mNavigationBar.getBarTransitions().setAutoDim(true);
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 03f42a6f760d..d7f11f710501 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -422,7 +422,7 @@ public class StatusBarWindowView extends FrameLayout {
mFloatingActionMode.finish();
}
cleanupFloatingActionModeViews();
- mFloatingToolbar = new FloatingToolbar(mContext, mFakeWindow);
+ mFloatingToolbar = new FloatingToolbar(mFakeWindow);
final FloatingActionMode mode =
new FloatingActionMode(mContext, callback, originatingView, mFloatingToolbar);
mFloatingActionModeOriginatingView = originatingView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
index 7e92edf76b74..1411a544c346 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
@@ -154,6 +154,11 @@ public class UnlockMethodCache {
public void onStrongAuthStateChanged(int userId) {
update(false /* updateAlways */);
}
+
+ @Override
+ public void onScreenTurnedOff() {
+ update(false /* updateAlways */);
+ }
};
public boolean isTrustManaged() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
index 9daa199ee92a..b693ebbf09a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothController.java
@@ -39,6 +39,7 @@ public interface BluetoothController extends CallbackController<Callback>, Dumpa
int getMaxConnectionState(CachedBluetoothDevice device);
int getBondState(CachedBluetoothDevice device);
+ CachedBluetoothDevice getLastDevice();
public interface Callback {
void onBluetoothStateChange(boolean enabled);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 5b24f9cd97bf..3b15c2b8253f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -121,6 +121,11 @@ public class BluetoothControllerImpl implements BluetoothController, BluetoothCa
}
@Override
+ public CachedBluetoothDevice getLastDevice() {
+ return mLastDevice;
+ }
+
+ @Override
public int getMaxConnectionState(CachedBluetoothDevice device) {
return getCachedState(device).mMaxConnectionState;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
index 13ee23fb7af9..06040e2b0bcc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeadZone.java
@@ -28,6 +28,8 @@ import android.view.Surface;
import android.view.View;
import com.android.systemui.R;
+import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.statusbar.phone.StatusBar;
/**
* The "dead zone" consumes unintentional taps along the top edge of the navigation bar.
@@ -44,6 +46,7 @@ public class DeadZone extends View {
public static final int VERTICAL = 1; // Consume taps along the left edge.
private static final boolean CHATTY = true; // print to logcat when we eat a click
+ private final StatusBar mStatusBar;
private boolean mShouldFlash;
private float mFlashFrac = 0f;
@@ -88,6 +91,7 @@ public class DeadZone extends View {
+ (mVertical ? " vertical" : " horizontal"));
setFlashOnTouchCapture(context.getResources().getBoolean(R.bool.config_dead_zone_flash));
+ mStatusBar = SysUiServiceProvider.getComponent(context, StatusBar.class);
}
static float lerp(float a, float b, float f) {
@@ -132,6 +136,7 @@ public class DeadZone extends View {
if (DEBUG) {
Slog.v(TAG, this + " ACTION_DOWN: " + event.getX() + "," + event.getY());
}
+ if (mStatusBar != null) mStatusBar.touchAutoDim();
int size = (int) getSize(event.getEventTime());
// In the vertical orientation consume taps along the left edge.
// In horizontal orientation consume taps along the top edge.
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java
index 1ea23bb65107..4d95969a63b5 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java
@@ -22,9 +22,11 @@ import android.provider.Settings.Global;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
+import android.view.ViewGroup;
import android.widget.Checkable;
import android.widget.LinearLayout;
import android.widget.TextView;
+
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.ZenModeController;
@@ -65,6 +67,11 @@ public class TunerZenModePanel extends LinearLayout implements OnClickListener {
mDone = mButtons.findViewById(android.R.id.button1);
mDone.setOnClickListener(this);
((TextView) mDone).setText(R.string.quick_settings_done);
+ // Hide the resizing space because it causes issues in the volume panel.
+ ViewGroup detail_header = findViewById(R.id.tuner_zen_switch);
+ detail_header.getChildAt(0).setVisibility(View.GONE);
+ // No background so it can blend with volume panel.
+ findViewById(R.id.edit_container).setBackground(null);
}
@Override
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 5e71dd4684c5..27c16d53ce78 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -54,7 +54,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
SystemUI-proto \
SystemUI-tags \
legacy-android-test \
- testables
+ testables \
+ truth-prebuilt \
LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common android.car
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/AlwaysOnDisplayPolicyTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/AlwaysOnDisplayPolicyTest.java
new file mode 100644
index 000000000000..abc2d0e5c845
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/AlwaysOnDisplayPolicyTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.doze;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.provider.Settings;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.format.DateUtils;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class AlwaysOnDisplayPolicyTest extends SysuiTestCase {
+ private static final String ALWAYS_ON_DISPLAY_CONSTANTS_VALUE = "prox_screen_off_delay=1000"
+ + ",prox_cooldown_trigger=2000"
+ + ",prox_cooldown_period=3000"
+ + ",screen_brightness_array=1:2:3:4:5"
+ + ",dimming_scrim_array=5:4:3:2:1";
+
+ private String mPreviousConfig;
+
+ @Before
+ public void setUp() {
+ mPreviousConfig = Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.ALWAYS_ON_DISPLAY_CONSTANTS);
+ }
+
+ @After
+ public void tearDown() {
+ Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.ALWAYS_ON_DISPLAY_CONSTANTS, mPreviousConfig);
+ }
+
+ @Test
+ public void testPolicy_valueNull_containsDefaultValue() throws Exception {
+ Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.ALWAYS_ON_DISPLAY_CONSTANTS, null);
+
+ AlwaysOnDisplayPolicy policy = new AlwaysOnDisplayPolicy(mContext);
+
+ assertThat(policy.proxScreenOffDelayMs).isEqualTo(10 * DateUtils.MINUTE_IN_MILLIS);
+ assertThat(policy.proxCooldownTriggerMs).isEqualTo(2 * DateUtils.MINUTE_IN_MILLIS);
+ assertThat(policy.proxCooldownPeriodMs).isEqualTo(5 * DateUtils.MINUTE_IN_MILLIS);
+ assertThat(policy.screenBrightnessArray).isEqualTo(mContext.getResources().getIntArray(
+ R.array.config_doze_brightness_sensor_to_brightness));
+ assertThat(policy.dimmingScrimArray).isEqualTo(mContext.getResources().getIntArray(
+ R.array.config_doze_brightness_sensor_to_scrim_opacity));
+ }
+
+ @Test
+ public void testPolicy_valueNotNull_containsValue() throws Exception {
+ Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.ALWAYS_ON_DISPLAY_CONSTANTS, ALWAYS_ON_DISPLAY_CONSTANTS_VALUE);
+
+ AlwaysOnDisplayPolicy policy = new AlwaysOnDisplayPolicy(mContext);
+
+ assertThat(policy.proxScreenOffDelayMs).isEqualTo(1000);
+ assertThat(policy.proxCooldownTriggerMs).isEqualTo(2000);
+ assertThat(policy.proxCooldownPeriodMs).isEqualTo(3000);
+ assertThat(policy.screenBrightnessArray).isEqualTo(new int[]{1, 2, 3, 4, 5});
+ assertThat(policy.dimmingScrimArray).isEqualTo(new int[]{5, 4, 3, 2, 1});
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
index c2758068a4ed..46e1d5562714 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -60,7 +60,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
mSensorManager = new FakeSensorManager(mContext);
mSensor = mSensorManager.getFakeLightSensor();
mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
- mSensor.getSensor(), mHostFake, null /* handler */);
+ mSensor.getSensor(), mHostFake, null /* handler */,
+ new AlwaysOnDisplayPolicy(mContext));
}
@Test
@@ -135,7 +136,8 @@ public class DozeScreenBrightnessTest extends SysuiTestCase {
@Test
public void testNullSensor() throws Exception {
mScreen = new DozeScreenBrightness(mContext, mServiceFake, mSensorManager,
- null /* sensor */, mHostFake, null /* handler */);
+ null /* sensor */, mHostFake, null /* handler */,
+ new AlwaysOnDisplayPolicy(mContext));
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
index b8e9fcd29096..94dbc2ad7147 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginManagerTest.java
@@ -67,7 +67,7 @@ public class PluginManagerTest extends SysuiTestCase {
public void setup() throws Exception {
mDependency.injectTestDependency(Dependency.BG_LOOPER,
TestableLooper.get(this).getLooper());
- mRealExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
+ mRealExceptionHandler = Thread.getUncaughtExceptionPreHandler();
mMockExceptionHandler = mock(UncaughtExceptionHandler.class);
mMockFactory = mock(PluginInstanceManagerFactory.class);
mMockPluginInstance = mock(PluginInstanceManager.class);
@@ -167,9 +167,9 @@ public class PluginManagerTest extends SysuiTestCase {
}
private void resetExceptionHandler() {
- mPluginExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
+ mPluginExceptionHandler = Thread.getUncaughtExceptionPreHandler();
// Set back the real exception handler so the test can crash if it wants to.
- Thread.setDefaultUncaughtExceptionHandler(mRealExceptionHandler);
+ Thread.setUncaughtExceptionPreHandler(mRealExceptionHandler);
}
@ProvidesInterface(action = TestPlugin.ACTION, version = TestPlugin.VERSION)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java
new file mode 100644
index 000000000000..0c1baaa1b476
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarTransitionsTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+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.spy;
+import static org.mockito.Mockito.when;
+
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.CommandQueue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class NavigationBarTransitionsTest extends SysuiTestCase {
+
+ private NavigationBarTransitions mTransitions;
+
+ @Before
+ public void setup() {
+ mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
+ NavigationBarView navBar = spy(new NavigationBarView(mContext, null));
+ when(navBar.getCurrentView()).thenReturn(navBar);
+ when(navBar.findViewById(anyInt())).thenReturn(navBar);
+ mTransitions = new NavigationBarTransitions(navBar);
+ }
+
+ @Test
+ public void setIsLightsOut_NoAutoDim() {
+ mTransitions.setAutoDim(false);
+
+ assertFalse(mTransitions.isLightsOut(BarTransitions.MODE_OPAQUE));
+
+ assertTrue(mTransitions.isLightsOut(BarTransitions.MODE_LIGHTS_OUT));
+ }
+
+ @Test
+ public void setIsLightsOut_AutoDim() {
+ mTransitions.setAutoDim(true);
+
+ assertTrue(mTransitions.isLightsOut(BarTransitions.MODE_OPAQUE));
+
+ assertTrue(mTransitions.isLightsOut(BarTransitions.MODE_LIGHTS_OUT));
+ }
+
+} \ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java
index 9ec096ad49e0..44c49835def4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeBluetoothController.java
@@ -93,4 +93,9 @@ public class FakeBluetoothController extends BaseLeakChecker<Callback> implement
public int getBondState(CachedBluetoothDevice device) {
return 0;
}
+
+ @Override
+ public CachedBluetoothDevice getLastDevice() {
+ return null;
+ }
}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 3bc592371a85..8e782c0dd32b 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -1516,7 +1516,7 @@ message MetricsEvent {
// OS: N
ACTION_ZEN_ALLOW_LIGHTS = 264;
- // OPEN: Settings > Notifications > [App] > Topic Notifications
+ // OPEN: Settings > Notifications > [App] > Channel Notifications
// CATEGORY: SETTINGS
// OS: N
NOTIFICATION_TOPIC_NOTIFICATION = 265;
@@ -4051,6 +4051,7 @@ message MetricsEvent {
ASSIST_GESTURE_PRIMED = 998;
// ACTION: Assist gesture triggered
+ // SUBTYPE: 1 is for SCREEN_ON, 2 is for SCREEN_OFF
// CATEGORY: GLOBAL_SYSTEM_UI
// OS: O DR
ASSIST_GESTURE_TRIGGERED = 999;
@@ -4281,6 +4282,11 @@ message MetricsEvent {
// the app transition.
APP_TRANSITION_REPORTED_DRAWN_MS = 1091;
+ // OPEN: Settings > Storage > Photos & Videos
+ // CATEGORY: SETTINGS
+ // OS: O MR
+ APPLICATIONS_STORAGE_PHOTOS = 1092;
+
// ---- End O-MR1 Constants, all O-MR1 constants go above this line ----
// OPEN: Settings > Network & Internet > Mobile network
@@ -4354,6 +4360,11 @@ message MetricsEvent {
// CATEGORY: SETTINGS
SETTINGS_FEATURE_FLAGS_DASHBOARD = 1156;
+ // OPEN: Settings > Notifications > [App] > Topic Notifications
+ // CATEGORY: SETTINGS
+ // OS: P
+ NOTIFICATION_CHANNEL_GROUP = 1157;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 7324b82351f6..c60647fada09 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -417,7 +417,8 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
final boolean triggerable = (mEnabledFeatures
& FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0;
mMagnificationGestureHandler = new MagnificationGestureHandler(
- mContext, mAms, detectControlGestures, triggerable);
+ mContext, mAms.getMagnificationController(),
+ detectControlGestures, triggerable);
addFirstEventHandler(mMagnificationGestureHandler);
}
diff --git a/services/accessibility/java/com/android/server/accessibility/GestureUtils.java b/services/accessibility/java/com/android/server/accessibility/GestureUtils.java
index bc761914caf2..abfdb683c04c 100644
--- a/services/accessibility/java/com/android/server/accessibility/GestureUtils.java
+++ b/services/accessibility/java/com/android/server/accessibility/GestureUtils.java
@@ -12,32 +12,27 @@ final class GestureUtils {
/* cannot be instantiated */
}
- public static boolean isTap(MotionEvent down, MotionEvent up, int tapTimeSlop,
- int tapDistanceSlop, int actionIndex) {
- return eventsWithinTimeAndDistanceSlop(down, up, tapTimeSlop, tapDistanceSlop, actionIndex);
- }
-
public static boolean isMultiTap(MotionEvent firstUp, MotionEvent secondUp,
- int multiTapTimeSlop, int multiTapDistanceSlop, int actionIndex) {
+ int multiTapTimeSlop, int multiTapDistanceSlop) {
+ if (firstUp == null || secondUp == null) return false;
return eventsWithinTimeAndDistanceSlop(firstUp, secondUp, multiTapTimeSlop,
- multiTapDistanceSlop, actionIndex);
+ multiTapDistanceSlop);
}
private static boolean eventsWithinTimeAndDistanceSlop(MotionEvent first, MotionEvent second,
- int timeout, int distance, int actionIndex) {
+ int timeout, int distance) {
if (isTimedOut(first, second, timeout)) {
return false;
}
- final double deltaMove = computeDistance(first, second, actionIndex);
+ final double deltaMove = distance(first, second);
if (deltaMove >= distance) {
return false;
}
return true;
}
- public static double computeDistance(MotionEvent first, MotionEvent second, int pointerIndex) {
- return MathUtils.dist(first.getX(pointerIndex), first.getY(pointerIndex),
- second.getX(pointerIndex), second.getY(pointerIndex));
+ public static double distance(MotionEvent first, MotionEvent second) {
+ return MathUtils.dist(first.getX(), first.getY(), second.getX(), second.getY());
}
public static boolean isTimedOut(MotionEvent firstUp, MotionEvent secondUp, int timeout) {
@@ -54,7 +49,6 @@ final class GestureUtils {
/**
* Determines whether a two pointer gesture is a dragging one.
*
- * @param event The event with the pointer data.
* @return True if the gesture is a dragging one.
*/
public static boolean isDraggingGesture(float firstPtrDownX, float firstPtrDownY,
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
index caa74b9512d1..98b8e6b723ac 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
@@ -16,11 +16,6 @@
package com.android.server.accessibility;
-import com.android.internal.R;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.os.SomeArgs;
-import com.android.server.LocalServices;
-
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.content.BroadcastReceiver;
@@ -42,6 +37,12 @@ import android.view.View;
import android.view.WindowManagerInternal;
import android.view.animation.DecelerateInterpolator;
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.SomeArgs;
+import com.android.server.LocalServices;
+
import java.util.Locale;
/**
@@ -138,7 +139,7 @@ class MagnificationController implements Handler.Callback {
private final WindowManagerInternal mWindowManager;
// Flag indicating that we are registered with window manager.
- private boolean mRegistered;
+ @VisibleForTesting boolean mRegistered;
private boolean mUnregisterPending;
@@ -148,9 +149,14 @@ class MagnificationController implements Handler.Callback {
mHandler = new Handler(context.getMainLooper(), this);
}
- public MagnificationController(Context context, AccessibilityManagerService ams, Object lock,
- Handler handler, WindowManagerInternal windowManagerInternal,
- ValueAnimator valueAnimator, SettingsBridge settingsBridge) {
+ public MagnificationController(
+ Context context,
+ AccessibilityManagerService ams,
+ Object lock,
+ Handler handler,
+ WindowManagerInternal windowManagerInternal,
+ ValueAnimator valueAnimator,
+ SettingsBridge settingsBridge) {
mHandler = handler;
mWindowManager = windowManagerInternal;
mMainThreadId = context.getMainLooper().getThread().getId();
@@ -672,8 +678,7 @@ class MagnificationController implements Handler.Callback {
* Resets magnification if magnification and auto-update are both enabled.
*
* @param animate whether the animate the transition
- * @return {@code true} if magnification was reset to the disabled state,
- * {@code false} if magnification is still active
+ * @return whether was {@link #isMagnifying magnifying}
*/
boolean resetIfNeeded(boolean animate) {
synchronized (mLock) {
@@ -790,6 +795,19 @@ class MagnificationController implements Handler.Callback {
return true;
}
+ @Override
+ public String toString() {
+ return "MagnificationController{" +
+ "mCurrentMagnificationSpec=" + mCurrentMagnificationSpec +
+ ", mMagnificationRegion=" + mMagnificationRegion +
+ ", mMagnificationBounds=" + mMagnificationBounds +
+ ", mUserId=" + mUserId +
+ ", mIdOfLastServiceToMagnify=" + mIdOfLastServiceToMagnify +
+ ", mRegistered=" + mRegistered +
+ ", mUnregisterPending=" + mUnregisterPending +
+ '}';
+ }
+
/**
* Class responsible for animating spec on the main thread and sending spec
* updates to the window manager.
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index 7e82edaae3e5..d6452f87d155 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -16,6 +16,21 @@
package com.android.server.accessibility;
+import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_POINTER_DOWN;
+import static android.view.MotionEvent.ACTION_POINTER_UP;
+import static android.view.MotionEvent.ACTION_UP;
+
+import static com.android.server.accessibility.GestureUtils.distance;
+
+import static java.lang.Math.abs;
+import static java.util.Arrays.asList;
+import static java.util.Arrays.copyOfRange;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -27,7 +42,6 @@ import android.util.Slog;
import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
-import android.view.InputDevice;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.MotionEvent.PointerCoords;
@@ -37,6 +51,8 @@ import android.view.ScaleGestureDetector.OnScaleGestureListener;
import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
+import com.android.internal.annotations.VisibleForTesting;
+
/**
* This class handles magnification in response to touch events.
*
@@ -85,91 +101,109 @@ import android.view.accessibility.AccessibilityEvent;
*
* 7. The magnification scale will be persisted in settings and in the cloud.
*/
+@SuppressWarnings("WeakerAccess")
class MagnificationGestureHandler implements EventStreamTransformation {
private static final String LOG_TAG = "MagnificationEventHandler";
- private static final boolean DEBUG_STATE_TRANSITIONS = false;
- private static final boolean DEBUG_DETECTING = false;
- private static final boolean DEBUG_PANNING = false;
+ private static final boolean DEBUG_ALL = false;
+ private static final boolean DEBUG_STATE_TRANSITIONS = false || DEBUG_ALL;
+ private static final boolean DEBUG_DETECTING = false || DEBUG_ALL;
+ private static final boolean DEBUG_PANNING = false || DEBUG_ALL;
- private static final int STATE_DELEGATING = 1;
- private static final int STATE_DETECTING = 2;
- private static final int STATE_VIEWPORT_DRAGGING = 3;
- private static final int STATE_MAGNIFIED_INTERACTION = 4;
+ /** @see #handleMotionEventStateDelegating */
+ @VisibleForTesting static final int STATE_DELEGATING = 1;
+ /** @see DetectingStateHandler */
+ @VisibleForTesting static final int STATE_DETECTING = 2;
+ /** @see ViewportDraggingStateHandler */
+ @VisibleForTesting static final int STATE_VIEWPORT_DRAGGING = 3;
+ /** @see PanningScalingStateHandler */
+ @VisibleForTesting static final int STATE_PANNING_SCALING = 4;
private static final float MIN_SCALE = 2.0f;
private static final float MAX_SCALE = 5.0f;
- private final MagnificationController mMagnificationController;
- private final DetectingStateHandler mDetectingStateHandler;
- private final MagnifiedContentInteractionStateHandler mMagnifiedContentInteractionStateHandler;
- private final StateViewportDraggingHandler mStateViewportDraggingHandler;
+ @VisibleForTesting final MagnificationController mMagnificationController;
+
+ @VisibleForTesting final DetectingStateHandler mDetectingStateHandler;
+ @VisibleForTesting final PanningScalingStateHandler mPanningScalingStateHandler;
+ @VisibleForTesting final ViewportDraggingStateHandler mViewportDraggingStateHandler;
private final ScreenStateReceiver mScreenStateReceiver;
- private final boolean mDetectTripleTap;
- private final boolean mTriggerable;
+ /**
+ * {@code true} if this detector should detect and respond to triple-tap
+ * gestures for engaging and disengaging magnification,
+ * {@code false} if it should ignore such gestures
+ */
+ final boolean mDetectTripleTap;
+
+ /**
+ * Whether {@link #mShortcutTriggered shortcut} is enabled
+ */
+ final boolean mDetectShortcutTrigger;
- private EventStreamTransformation mNext;
+ EventStreamTransformation mNext;
- private int mCurrentState;
- private int mPreviousState;
+ @VisibleForTesting int mCurrentState;
+ @VisibleForTesting int mPreviousState;
- private boolean mTranslationEnabledBeforePan;
+ @VisibleForTesting boolean mShortcutTriggered;
- private boolean mShortcutTriggered;
+ /**
+ * Time of last {@link MotionEvent#ACTION_DOWN} while in {@link #STATE_DELEGATING}
+ */
+ long mDelegatingStateDownTime;
private PointerCoords[] mTempPointerCoords;
private PointerProperties[] mTempPointerProperties;
- private long mDelegatingStateDownTime;
-
/**
* @param context Context for resolving various magnification-related resources
- * @param ams AccessibilityManagerService used to obtain a {@link MagnificationController}
+ * @param magnificationController the {@link MagnificationController}
+ *
* @param detectTripleTap {@code true} if this detector should detect and respond to triple-tap
- * gestures for engaging and disengaging magnification,
- * {@code false} if it should ignore such gestures
- * @param triggerable {@code true} if this detector should be "triggerable" by some external
- * shortcut invoking {@link #notifyShortcutTriggered}, {@code
- * false} if it should ignore such triggers.
+ * gestures for engaging and disengaging magnification,
+ * {@code false} if it should ignore such gestures
+ * @param detectShortcutTrigger {@code true} if this detector should be "triggerable" by some
+ * external shortcut invoking {@link #notifyShortcutTriggered},
+ * {@code false} if it should ignore such triggers.
*/
- public MagnificationGestureHandler(Context context, AccessibilityManagerService ams,
- boolean detectTripleTap, boolean triggerable) {
- mMagnificationController = ams.getMagnificationController();
+ public MagnificationGestureHandler(Context context,
+ MagnificationController magnificationController,
+ boolean detectTripleTap,
+ boolean detectShortcutTrigger) {
+ mMagnificationController = magnificationController;
+
mDetectingStateHandler = new DetectingStateHandler(context);
- mStateViewportDraggingHandler = new StateViewportDraggingHandler();
- mMagnifiedContentInteractionStateHandler =
- new MagnifiedContentInteractionStateHandler(context);
+ mViewportDraggingStateHandler = new ViewportDraggingStateHandler();
+ mPanningScalingStateHandler =
+ new PanningScalingStateHandler(context);
+
mDetectTripleTap = detectTripleTap;
- mTriggerable = triggerable;
+ mDetectShortcutTrigger = detectShortcutTrigger;
- if (triggerable) {
+ if (mDetectShortcutTrigger) {
mScreenStateReceiver = new ScreenStateReceiver(context, this);
mScreenStateReceiver.register();
} else {
mScreenStateReceiver = null;
}
- transitionToState(STATE_DETECTING);
+ transitionTo(STATE_DETECTING);
}
@Override
public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
- if (!event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)) {
- if (mNext != null) {
- mNext.onMotionEvent(event, rawEvent, policyFlags);
- }
- return;
- }
- if (!mDetectTripleTap && !mTriggerable) {
- if (mNext != null) {
- dispatchTransformedEvent(event, rawEvent, policyFlags);
- }
+ if ((!mDetectTripleTap && !mDetectShortcutTrigger)
+ || !event.isFromSource(SOURCE_TOUCHSCREEN)) {
+ dispatchTransformedEvent(event, rawEvent, policyFlags);
return;
}
- mMagnifiedContentInteractionStateHandler.onMotionEvent(event, rawEvent, policyFlags);
- switch (mCurrentState) {
+ // Local copy to avoid dispatching the same event to more than one state handler
+ // in case mPanningScalingStateHandler changes mCurrentState
+ int currentState = mCurrentState;
+ mPanningScalingStateHandler.onMotionEvent(event, rawEvent, policyFlags);
+ switch (currentState) {
case STATE_DELEGATING: {
handleMotionEventStateDelegating(event, rawEvent, policyFlags);
}
@@ -179,17 +213,17 @@ class MagnificationGestureHandler implements EventStreamTransformation {
}
break;
case STATE_VIEWPORT_DRAGGING: {
- mStateViewportDraggingHandler.onMotionEvent(event, rawEvent, policyFlags);
+ mViewportDraggingStateHandler.onMotionEvent(event, rawEvent, policyFlags);
}
break;
- case STATE_MAGNIFIED_INTERACTION: {
- // mMagnifiedContentInteractionStateHandler handles events only
+ case STATE_PANNING_SCALING: {
+ // mPanningScalingStateHandler handles events only
// if this is the current state since it uses ScaleGestureDetector
// and a GestureDetector which need well formed event stream.
}
break;
default: {
- throw new IllegalStateException("Unknown state: " + mCurrentState);
+ throw new IllegalStateException("Unknown state: " + currentState);
}
}
}
@@ -215,8 +249,8 @@ class MagnificationGestureHandler implements EventStreamTransformation {
@Override
public void clearEvents(int inputSource) {
- if (inputSource == InputDevice.SOURCE_TOUCHSCREEN) {
- clear();
+ if (inputSource == SOURCE_TOUCHSCREEN) {
+ clearAndTransitionToStateDetecting();
}
if (mNext != null) {
@@ -229,20 +263,25 @@ class MagnificationGestureHandler implements EventStreamTransformation {
if (mScreenStateReceiver != null) {
mScreenStateReceiver.unregister();
}
- clear();
+ clearAndTransitionToStateDetecting();
}
void notifyShortcutTriggered() {
- if (mTriggerable) {
- if (mMagnificationController.resetIfNeeded(true)) {
- clear();
+ if (mDetectShortcutTrigger) {
+ boolean wasMagnifying = mMagnificationController.resetIfNeeded(/* animate */ true);
+ if (wasMagnifying) {
+ clearAndTransitionToStateDetecting();
} else {
- setMagnificationShortcutTriggered(!mShortcutTriggered);
+ toggleShortcutTriggered();
}
}
}
- private void setMagnificationShortcutTriggered(boolean state) {
+ private void toggleShortcutTriggered() {
+ setShortcutTriggered(!mShortcutTriggered);
+ }
+
+ private void setShortcutTriggered(boolean state) {
if (mShortcutTriggered == state) {
return;
}
@@ -251,27 +290,25 @@ class MagnificationGestureHandler implements EventStreamTransformation {
mMagnificationController.setForceShowMagnifiableBounds(state);
}
- private void clear() {
+ void clearAndTransitionToStateDetecting() {
+ setShortcutTriggered(false);
mCurrentState = STATE_DETECTING;
- setMagnificationShortcutTriggered(false);
mDetectingStateHandler.clear();
- mStateViewportDraggingHandler.clear();
- mMagnifiedContentInteractionStateHandler.clear();
+ mViewportDraggingStateHandler.clear();
+ mPanningScalingStateHandler.clear();
}
private void handleMotionEventStateDelegating(MotionEvent event,
MotionEvent rawEvent, int policyFlags) {
- switch (event.getActionMasked()) {
- case MotionEvent.ACTION_DOWN: {
- mDelegatingStateDownTime = event.getDownTime();
- }
- break;
- case MotionEvent.ACTION_UP: {
- if (mDetectingStateHandler.mDelayedEventQueue == null) {
- transitionToState(STATE_DETECTING);
- }
- }
- break;
+ if (event.getActionMasked() == ACTION_UP) {
+ transitionTo(STATE_DETECTING);
+ }
+ delegateEvent(event, rawEvent, policyFlags);
+ }
+
+ void delegateEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mDelegatingStateDownTime = event.getDownTime();
}
if (mNext != null) {
// We cache some events to see if the user wants to trigger magnification.
@@ -287,13 +324,15 @@ class MagnificationGestureHandler implements EventStreamTransformation {
private void dispatchTransformedEvent(MotionEvent event, MotionEvent rawEvent,
int policyFlags) {
- // If the event is within the magnified portion of the screen we have
+ if (mNext == null) return; // Nowhere to dispatch to
+
+ // If the touchscreen event is within the magnified portion of the screen we have
// to change its location to be where the user thinks he is poking the
// UI which may have been magnified and panned.
- final float eventX = event.getX();
- final float eventY = event.getY();
if (mMagnificationController.isMagnifying()
- && mMagnificationController.magnificationRegionContains(eventX, eventY)) {
+ && event.isFromSource(SOURCE_TOUCHSCREEN)
+ && mMagnificationController.magnificationRegionContains(
+ event.getX(), event.getY())) {
final float scale = mMagnificationController.getScale();
final float scaledOffsetX = mMagnificationController.getOffsetX();
final float scaledOffsetY = mMagnificationController.getOffsetY();
@@ -347,34 +386,27 @@ class MagnificationGestureHandler implements EventStreamTransformation {
return mTempPointerProperties;
}
- private void transitionToState(int state) {
+ private void transitionTo(int state) {
if (DEBUG_STATE_TRANSITIONS) {
- switch (state) {
- case STATE_DELEGATING: {
- Slog.i(LOG_TAG, "mCurrentState: STATE_DELEGATING");
- }
- break;
- case STATE_DETECTING: {
- Slog.i(LOG_TAG, "mCurrentState: STATE_DETECTING");
- }
- break;
- case STATE_VIEWPORT_DRAGGING: {
- Slog.i(LOG_TAG, "mCurrentState: STATE_VIEWPORT_DRAGGING");
- }
- break;
- case STATE_MAGNIFIED_INTERACTION: {
- Slog.i(LOG_TAG, "mCurrentState: STATE_MAGNIFIED_INTERACTION");
- }
- break;
- default: {
- throw new IllegalArgumentException("Unknown state: " + state);
- }
- }
+ Slog.i(LOG_TAG, (stateToString(mCurrentState) + " -> " + stateToString(state)
+ + " at " + asList(copyOfRange(new RuntimeException().getStackTrace(), 1, 5)))
+ .replace(getClass().getName(), ""));
}
mPreviousState = mCurrentState;
mCurrentState = state;
}
+ private static String stateToString(int state) {
+ switch (state) {
+ case STATE_DELEGATING: return "STATE_DELEGATING";
+ case STATE_DETECTING: return "STATE_DETECTING";
+ case STATE_VIEWPORT_DRAGGING: return "STATE_VIEWPORT_DRAGGING";
+ case STATE_PANNING_SCALING: return "STATE_PANNING_SCALING";
+ case 0: return "0";
+ default: throw new IllegalArgumentException("Unknown state: " + state);
+ }
+ }
+
private interface MotionEventHandler {
void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags);
@@ -384,21 +416,20 @@ class MagnificationGestureHandler implements EventStreamTransformation {
/**
* This class determines if the user is performing a scale or pan gesture.
+ *
+ * @see #STATE_PANNING_SCALING
*/
- private final class MagnifiedContentInteractionStateHandler extends SimpleOnGestureListener
+ final class PanningScalingStateHandler extends SimpleOnGestureListener
implements OnScaleGestureListener, MotionEventHandler {
private final ScaleGestureDetector mScaleGestureDetector;
-
private final GestureDetector mGestureDetector;
+ final float mScalingThreshold;
- private final float mScalingThreshold;
+ float mInitialScaleFactor = -1;
+ boolean mScaling;
- private float mInitialScaleFactor = -1;
-
- private boolean mScaling;
-
- public MagnifiedContentInteractionStateHandler(Context context) {
+ public PanningScalingStateHandler(Context context) {
final TypedValue scaleValue = new TypedValue();
context.getResources().getValue(
com.android.internal.R.dimen.config_screen_magnification_scaling_threshold,
@@ -411,26 +442,39 @@ class MagnificationGestureHandler implements EventStreamTransformation {
@Override
public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ // Dispatches #onScaleBegin, #onScale, #onScaleEnd
mScaleGestureDetector.onTouchEvent(event);
+ // Dispatches #onScroll
mGestureDetector.onTouchEvent(event);
- if (mCurrentState != STATE_MAGNIFIED_INTERACTION) {
+
+ if (mCurrentState != STATE_PANNING_SCALING) {
return;
}
- if (event.getActionMasked() == MotionEvent.ACTION_UP) {
- clear();
- mMagnificationController.persistScale();
- if (mPreviousState == STATE_VIEWPORT_DRAGGING) {
- transitionToState(STATE_VIEWPORT_DRAGGING);
- } else {
- transitionToState(STATE_DETECTING);
- }
+
+ int action = event.getActionMasked();
+ if (action == ACTION_POINTER_UP
+ && event.getPointerCount() == 2 // includes the pointer currently being released
+ && mPreviousState == STATE_VIEWPORT_DRAGGING) {
+
+ persistScaleAndTransitionTo(STATE_VIEWPORT_DRAGGING);
+
+ } else if (action == ACTION_UP) {
+
+ persistScaleAndTransitionTo(STATE_DETECTING);
+
}
}
+ public void persistScaleAndTransitionTo(int state) {
+ mMagnificationController.persistScale();
+ clear();
+ transitionTo(state);
+ }
+
@Override
- public boolean onScroll(MotionEvent first, MotionEvent second, float distanceX,
- float distanceY) {
- if (mCurrentState != STATE_MAGNIFIED_INTERACTION) {
+ public boolean onScroll(MotionEvent first, MotionEvent second,
+ float distanceX, float distanceY) {
+ if (mCurrentState != STATE_PANNING_SCALING) {
return true;
}
if (DEBUG_PANNING) {
@@ -447,14 +491,15 @@ class MagnificationGestureHandler implements EventStreamTransformation {
if (!mScaling) {
if (mInitialScaleFactor < 0) {
mInitialScaleFactor = detector.getScaleFactor();
+ return false;
+ }
+ final float deltaScale = detector.getScaleFactor() - mInitialScaleFactor;
+ if (abs(deltaScale) > mScalingThreshold) {
+ mScaling = true;
+ return true;
} else {
- final float deltaScale = detector.getScaleFactor() - mInitialScaleFactor;
- if (Math.abs(deltaScale) > mScalingThreshold) {
- mScaling = true;
- return true;
- }
+ return false;
}
- return false;
}
final float initialScale = mMagnificationController.getScale();
@@ -485,7 +530,7 @@ class MagnificationGestureHandler implements EventStreamTransformation {
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
- return (mCurrentState == STATE_MAGNIFIED_INTERACTION);
+ return (mCurrentState == STATE_PANNING_SCALING);
}
@Override
@@ -498,60 +543,65 @@ class MagnificationGestureHandler implements EventStreamTransformation {
mInitialScaleFactor = -1;
mScaling = false;
}
+
+ @Override
+ public String toString() {
+ return "MagnifiedContentInteractionStateHandler{" +
+ "mInitialScaleFactor=" + mInitialScaleFactor +
+ ", mScaling=" + mScaling +
+ '}';
+ }
}
/**
* This class handles motion events when the event dispatcher has
* determined that the user is performing a single-finger drag of the
* magnification viewport.
+ *
+ * @see #STATE_VIEWPORT_DRAGGING
*/
- private final class StateViewportDraggingHandler implements MotionEventHandler {
+ final class ViewportDraggingStateHandler implements MotionEventHandler {
+ /** Whether to disable zoom after dragging ends */
+ boolean mZoomedInBeforeDrag;
private boolean mLastMoveOutsideMagnifiedRegion;
@Override
public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
final int action = event.getActionMasked();
switch (action) {
- case MotionEvent.ACTION_DOWN: {
- throw new IllegalArgumentException("Unexpected event type: ACTION_DOWN");
- }
- case MotionEvent.ACTION_POINTER_DOWN: {
+ case ACTION_POINTER_DOWN: {
clear();
- transitionToState(STATE_MAGNIFIED_INTERACTION);
+ transitionTo(STATE_PANNING_SCALING);
}
break;
- case MotionEvent.ACTION_MOVE: {
+ case ACTION_MOVE: {
if (event.getPointerCount() != 1) {
throw new IllegalStateException("Should have one pointer down.");
}
final float eventX = event.getX();
final float eventY = event.getY();
if (mMagnificationController.magnificationRegionContains(eventX, eventY)) {
- if (mLastMoveOutsideMagnifiedRegion) {
- mLastMoveOutsideMagnifiedRegion = false;
- mMagnificationController.setCenter(eventX, eventY, true,
- AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
- } else {
- mMagnificationController.setCenter(eventX, eventY, false,
- AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
- }
+ mMagnificationController.setCenter(eventX, eventY,
+ /* animate */ mLastMoveOutsideMagnifiedRegion,
+ AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
+ mLastMoveOutsideMagnifiedRegion = false;
} else {
mLastMoveOutsideMagnifiedRegion = true;
}
}
break;
- case MotionEvent.ACTION_UP: {
- if (!mTranslationEnabledBeforePan) {
- mMagnificationController.reset(true);
- }
+ case ACTION_UP: {
+ if (!mZoomedInBeforeDrag) zoomOff();
clear();
- transitionToState(STATE_DETECTING);
+ transitionTo(STATE_DETECTING);
}
break;
- case MotionEvent.ACTION_POINTER_UP: {
+
+ case ACTION_DOWN:
+ case ACTION_POINTER_UP: {
throw new IllegalArgumentException(
- "Unexpected event type: ACTION_POINTER_UP");
+ "Unexpected event type: " + MotionEvent.actionToString(action));
}
}
}
@@ -560,211 +610,224 @@ class MagnificationGestureHandler implements EventStreamTransformation {
public void clear() {
mLastMoveOutsideMagnifiedRegion = false;
}
+
+ @Override
+ public String toString() {
+ return "ViewportDraggingStateHandler{" +
+ "mZoomedInBeforeDrag=" + mZoomedInBeforeDrag +
+ ", mLastMoveOutsideMagnifiedRegion=" + mLastMoveOutsideMagnifiedRegion +
+ '}';
+ }
}
/**
* This class handles motion events when the event dispatch has not yet
* determined what the user is doing. It watches for various tap events.
+ *
+ * @see #STATE_DETECTING
*/
- private final class DetectingStateHandler implements MotionEventHandler {
-
- private static final int MESSAGE_ON_ACTION_TAP_AND_HOLD = 1;
+ final class DetectingStateHandler implements MotionEventHandler, Handler.Callback {
+ private static final int MESSAGE_ON_TRIPLE_TAP_AND_HOLD = 1;
private static final int MESSAGE_TRANSITION_TO_DELEGATING_STATE = 2;
- private static final int ACTION_TAP_COUNT = 3;
-
- private final int mTapTimeSlop = ViewConfiguration.getJumpTapTimeout();
-
- private final int mMultiTapTimeSlop;
-
- private final int mTapDistanceSlop;
-
- private final int mMultiTapDistanceSlop;
+ final int mLongTapMinDelay = ViewConfiguration.getJumpTapTimeout();
+ final int mSwipeMinDistance;
+ final int mMultiTapMaxDelay;
+ final int mMultiTapMaxDistance;
private MotionEventInfo mDelayedEventQueue;
+ MotionEvent mLastDown;
+ private MotionEvent mPreLastDown;
+ private MotionEvent mLastUp;
+ private MotionEvent mPreLastUp;
- private MotionEvent mLastDownEvent;
-
- private MotionEvent mLastTapUpEvent;
-
- private int mTapCount;
+ Handler mHandler = new Handler(this);
public DetectingStateHandler(Context context) {
- mMultiTapTimeSlop = ViewConfiguration.getDoubleTapTimeout()
+ mMultiTapMaxDelay = ViewConfiguration.getDoubleTapTimeout()
+ context.getResources().getInteger(
com.android.internal.R.integer.config_screen_magnification_multi_tap_adjustment);
- mTapDistanceSlop = ViewConfiguration.get(context).getScaledTouchSlop();
- mMultiTapDistanceSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop();
- }
-
- private final Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message message) {
- final int type = message.what;
- switch (type) {
- case MESSAGE_ON_ACTION_TAP_AND_HOLD: {
- MotionEvent event = (MotionEvent) message.obj;
- final int policyFlags = message.arg1;
- onActionTapAndHold(event, policyFlags);
- }
- break;
- case MESSAGE_TRANSITION_TO_DELEGATING_STATE: {
- transitionToState(STATE_DELEGATING);
- sendDelayedMotionEvents();
- clear();
- }
- break;
- default: {
- throw new IllegalArgumentException("Unknown message type: " + type);
- }
+ mSwipeMinDistance = ViewConfiguration.get(context).getScaledTouchSlop();
+ mMultiTapMaxDistance = ViewConfiguration.get(context).getScaledDoubleTapSlop();
+ }
+
+ @Override
+ public boolean handleMessage(Message message) {
+ final int type = message.what;
+ switch (type) {
+ case MESSAGE_ON_TRIPLE_TAP_AND_HOLD: {
+ onTripleTapAndHold(/* down */ (MotionEvent) message.obj);
+ }
+ break;
+ case MESSAGE_TRANSITION_TO_DELEGATING_STATE: {
+ transitionToDelegatingState(/* andClear */ true);
+ }
+ break;
+ default: {
+ throw new IllegalArgumentException("Unknown message type: " + type);
}
}
- };
+ return true;
+ }
@Override
public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
cacheDelayedMotionEvent(event, rawEvent, policyFlags);
- final int action = event.getActionMasked();
- switch (action) {
+ switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
+
mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE);
+
if (!mMagnificationController.magnificationRegionContains(
event.getX(), event.getY())) {
- transitionToDelegatingState(!mShortcutTriggered);
- return;
- }
- if (mShortcutTriggered) {
- Message message = mHandler.obtainMessage(MESSAGE_ON_ACTION_TAP_AND_HOLD,
- policyFlags, 0, event);
- mHandler.sendMessageDelayed(message,
- ViewConfiguration.getLongPressTimeout());
- return;
- }
- if (mDetectTripleTap) {
- if ((mTapCount == ACTION_TAP_COUNT - 1) && (mLastDownEvent != null)
- && GestureUtils.isMultiTap(mLastDownEvent, event, mMultiTapTimeSlop,
- mMultiTapDistanceSlop, 0)) {
- Message message = mHandler.obtainMessage(MESSAGE_ON_ACTION_TAP_AND_HOLD,
- policyFlags, 0, event);
- mHandler.sendMessageDelayed(message,
- ViewConfiguration.getLongPressTimeout());
- } else if (mTapCount < ACTION_TAP_COUNT) {
- Message message = mHandler.obtainMessage(
- MESSAGE_TRANSITION_TO_DELEGATING_STATE);
- mHandler.sendMessageDelayed(message, mMultiTapTimeSlop);
- }
- clearLastDownEvent();
- mLastDownEvent = MotionEvent.obtain(event);
- } else if (mMagnificationController.isMagnifying()) {
- // If magnified, consume an ACTION_DOWN until mMultiTapTimeSlop or
- // mTapDistanceSlop is reached to ensure MAGNIFIED_INTERACTION is reachable.
- Message message = mHandler.obtainMessage(
- MESSAGE_TRANSITION_TO_DELEGATING_STATE);
- mHandler.sendMessageDelayed(message, mMultiTapTimeSlop);
- return;
+
+ transitionToDelegatingState(/* andClear */ !mShortcutTriggered);
+
+ } else if (isMultiTapTriggered(2 /* taps */)) {
+
+ // 3tap and hold
+ delayedTransitionToDraggingState(event);
+
+ } else if (mDetectTripleTap
+ // If magnified, delay an ACTION_DOWN for mMultiTapMaxDelay
+ // to ensure reachability of
+ // STATE_PANNING_SCALING(triggerable with ACTION_POINTER_DOWN)
+ || mMagnificationController.isMagnifying()) {
+
+ delayedTransitionToDelegatingState();
+
} else {
- transitionToDelegatingState(true);
- return;
+
+ // Delegate pending events without delay
+ transitionToDelegatingState(/* andClear */ true);
}
}
break;
- case MotionEvent.ACTION_POINTER_DOWN: {
+ case ACTION_POINTER_DOWN: {
if (mMagnificationController.isMagnifying()) {
- mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE);
- transitionToState(STATE_MAGNIFIED_INTERACTION);
+ transitionTo(STATE_PANNING_SCALING);
clear();
} else {
- transitionToDelegatingState(true);
+ transitionToDelegatingState(/* andClear */ true);
}
}
break;
- case MotionEvent.ACTION_MOVE: {
- if (mLastDownEvent != null && mTapCount < ACTION_TAP_COUNT - 1) {
- final double distance = GestureUtils.computeDistance(mLastDownEvent,
- event, 0);
- if (Math.abs(distance) > mTapDistanceSlop) {
- transitionToDelegatingState(true);
- }
+ case ACTION_MOVE: {
+ if (isFingerDown()
+ && distance(mLastDown, /* move */ event) > mSwipeMinDistance
+ // For convenience, viewport dragging on 3tap&hold takes precedence
+ // over insta-delegating on 3tap&swipe
+ // (which is a rare combo to be used aside from magnification)
+ && !isMultiTapTriggered(2 /* taps */)) {
+
+ // Swipe detected - delegate skipping timeout
+ transitionToDelegatingState(/* andClear */ true);
}
}
break;
- case MotionEvent.ACTION_UP: {
+ case ACTION_UP: {
+
+ mHandler.removeMessages(MESSAGE_ON_TRIPLE_TAP_AND_HOLD);
+
if (!mMagnificationController.magnificationRegionContains(
event.getX(), event.getY())) {
- transitionToDelegatingState(!mShortcutTriggered);
- return;
- }
- if (mShortcutTriggered) {
- clear();
- onActionTap(event, policyFlags);
- return;
- }
- if (mLastDownEvent == null) {
- return;
- }
- mHandler.removeMessages(MESSAGE_ON_ACTION_TAP_AND_HOLD);
- if (!GestureUtils.isTap(mLastDownEvent, event, mTapTimeSlop,
- mTapDistanceSlop, 0)) {
- transitionToDelegatingState(true);
- return;
- }
- if (mLastTapUpEvent != null && !GestureUtils.isMultiTap(
- mLastTapUpEvent, event, mMultiTapTimeSlop, mMultiTapDistanceSlop, 0)) {
- transitionToDelegatingState(true);
- return;
- }
- mTapCount++;
- if (DEBUG_DETECTING) {
- Slog.i(LOG_TAG, "Tap count:" + mTapCount);
- }
- if (mTapCount == ACTION_TAP_COUNT) {
- clear();
- onActionTap(event, policyFlags);
- return;
+
+ transitionToDelegatingState(/* andClear */ !mShortcutTriggered);
+
+ } else if (isMultiTapTriggered(3 /* taps */)) {
+
+ onTripleTap(/* up */ event);
+
+ } else if (
+ // Possible to be false on: 3tap&drag -> scale -> PTR_UP -> UP
+ isFingerDown()
+ //TODO long tap should never happen here
+ && (timeBetween(mLastDown, /* mLastUp */ event) >= mLongTapMinDelay)
+ || distance(mLastDown, /* mLastUp */ event)
+ >= mSwipeMinDistance) {
+
+ transitionToDelegatingState(/* andClear */ true);
+
}
- clearLastTapUpEvent();
- mLastTapUpEvent = MotionEvent.obtain(event);
- }
- break;
- case MotionEvent.ACTION_POINTER_UP: {
- /* do nothing */
}
break;
}
}
- @Override
- public void clear() {
- setMagnificationShortcutTriggered(false);
- mHandler.removeMessages(MESSAGE_ON_ACTION_TAP_AND_HOLD);
- mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE);
- clearTapDetectionState();
- clearDelayedMotionEvents();
+ public boolean isMultiTapTriggered(int numTaps) {
+
+ // Shortcut acts as the 2 initial taps
+ if (mShortcutTriggered) return tapCount() + 2 >= numTaps;
+
+ return mDetectTripleTap
+ && tapCount() >= numTaps
+ && isMultiTap(mPreLastDown, mLastDown)
+ && isMultiTap(mPreLastUp, mLastUp);
}
- private void clearTapDetectionState() {
- mTapCount = 0;
- clearLastTapUpEvent();
- clearLastDownEvent();
+ private boolean isMultiTap(MotionEvent first, MotionEvent second) {
+ return GestureUtils.isMultiTap(first, second, mMultiTapMaxDelay, mMultiTapMaxDistance);
}
- private void clearLastTapUpEvent() {
- if (mLastTapUpEvent != null) {
- mLastTapUpEvent.recycle();
- mLastTapUpEvent = null;
- }
+ public boolean isFingerDown() {
+ return mLastDown != null;
}
- private void clearLastDownEvent() {
- if (mLastDownEvent != null) {
- mLastDownEvent.recycle();
- mLastDownEvent = null;
- }
+ private long timeBetween(@Nullable MotionEvent a, @Nullable MotionEvent b) {
+ if (a == null && b == null) return 0;
+ return abs(timeOf(a) - timeOf(b));
+ }
+
+ /**
+ * Nullsafe {@link MotionEvent#getEventTime} that interprets null event as something that
+ * has happened long enough ago to be gone from the event queue.
+ * Thus the time for a null event is a small number, that is below any other non-null
+ * event's time.
+ *
+ * @return {@link MotionEvent#getEventTime}, or {@link Long#MIN_VALUE} if the event is null
+ */
+ private long timeOf(@Nullable MotionEvent event) {
+ return event != null ? event.getEventTime() : Long.MIN_VALUE;
+ }
+
+ public int tapCount() {
+ return MotionEventInfo.countOf(mDelayedEventQueue, ACTION_UP);
}
+ /** -> {@link #STATE_DELEGATING} */
+ public void delayedTransitionToDelegatingState() {
+ mHandler.sendEmptyMessageDelayed(
+ MESSAGE_TRANSITION_TO_DELEGATING_STATE,
+ mMultiTapMaxDelay);
+ }
+
+ /** -> {@link #STATE_VIEWPORT_DRAGGING} */
+ public void delayedTransitionToDraggingState(MotionEvent event) {
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(MESSAGE_ON_TRIPLE_TAP_AND_HOLD, event),
+ ViewConfiguration.getLongPressTimeout());
+ }
+
+ @Override
+ public void clear() {
+ setShortcutTriggered(false);
+ mHandler.removeMessages(MESSAGE_ON_TRIPLE_TAP_AND_HOLD);
+ mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE);
+ clearDelayedMotionEvents();
+ }
+
+
private void cacheDelayedMotionEvent(MotionEvent event, MotionEvent rawEvent,
int policyFlags) {
+ if (event.getActionMasked() == ACTION_DOWN) {
+ mPreLastDown = mLastDown;
+ mLastDown = event;
+ } else if (event.getActionMasked() == ACTION_UP) {
+ mPreLastUp = mLastUp;
+ mLastUp = event;
+ }
+
MotionEventInfo info = MotionEventInfo.obtain(event, rawEvent,
policyFlags);
if (mDelayedEventQueue == null) {
@@ -782,8 +845,13 @@ class MagnificationGestureHandler implements EventStreamTransformation {
while (mDelayedEventQueue != null) {
MotionEventInfo info = mDelayedEventQueue;
mDelayedEventQueue = info.mNext;
- MagnificationGestureHandler.this.onMotionEvent(info.mEvent, info.mRawEvent,
- info.mPolicyFlags);
+
+ // Because MagnifiedInteractionStateHandler requires well-formed event stream
+ mPanningScalingStateHandler.onMotionEvent(
+ info.event, info.rawEvent, info.policyFlags);
+
+ delegateEvent(info.event, info.rawEvent, info.policyFlags);
+
info.recycle();
}
}
@@ -794,91 +862,136 @@ class MagnificationGestureHandler implements EventStreamTransformation {
mDelayedEventQueue = info.mNext;
info.recycle();
}
+ mPreLastDown = null;
+ mPreLastUp = null;
+ mLastDown = null;
+ mLastUp = null;
}
- private void transitionToDelegatingState(boolean andClear) {
- transitionToState(STATE_DELEGATING);
+ void transitionToDelegatingState(boolean andClear) {
+ transitionTo(STATE_DELEGATING);
sendDelayedMotionEvents();
- if (andClear) {
- clear();
- }
+ if (andClear) clear();
}
- private void onActionTap(MotionEvent up, int policyFlags) {
+ private void onTripleTap(MotionEvent up) {
+
if (DEBUG_DETECTING) {
- Slog.i(LOG_TAG, "onActionTap()");
+ Slog.i(LOG_TAG, "onTripleTap(); delayed: "
+ + MotionEventInfo.toString(mDelayedEventQueue));
}
+ clear();
- if (!mMagnificationController.isMagnifying()) {
- final float targetScale = mMagnificationController.getPersistedScale();
- final float scale = MathUtils.constrain(targetScale, MIN_SCALE, MAX_SCALE);
- mMagnificationController.setScaleAndCenter(scale, up.getX(), up.getY(), true,
- AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
+ // Toggle zoom
+ if (mMagnificationController.isMagnifying()) {
+ zoomOff();
} else {
- mMagnificationController.reset(true);
+ zoomOn(up.getX(), up.getY());
}
}
- private void onActionTapAndHold(MotionEvent down, int policyFlags) {
- if (DEBUG_DETECTING) {
- Slog.i(LOG_TAG, "onActionTapAndHold()");
- }
+ void onTripleTapAndHold(MotionEvent down) {
+ if (DEBUG_DETECTING) Slog.i(LOG_TAG, "onTripleTapAndHold()");
clear();
- mTranslationEnabledBeforePan = mMagnificationController.isMagnifying();
- final float targetScale = mMagnificationController.getPersistedScale();
- final float scale = MathUtils.constrain(targetScale, MIN_SCALE, MAX_SCALE);
- mMagnificationController.setScaleAndCenter(scale, down.getX(), down.getY(), true,
- AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
+ mViewportDraggingStateHandler.mZoomedInBeforeDrag =
+ mMagnificationController.isMagnifying();
+
+ zoomOn(down.getX(), down.getY());
- transitionToState(STATE_VIEWPORT_DRAGGING);
+ transitionTo(STATE_VIEWPORT_DRAGGING);
+ }
+
+ @Override
+ public String toString() {
+ return "DetectingStateHandler{" +
+ "tapCount()=" + tapCount() +
+ ", mDelayedEventQueue=" + MotionEventInfo.toString(mDelayedEventQueue) +
+ '}';
}
}
+ private void zoomOn(float centerX, float centerY) {
+ final float scale = MathUtils.constrain(
+ mMagnificationController.getPersistedScale(),
+ MIN_SCALE, MAX_SCALE);
+ mMagnificationController.setScaleAndCenter(
+ scale, centerX, centerY,
+ /* animate */ true,
+ AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
+ }
+
+ private void zoomOff() {
+ mMagnificationController.reset(/* animate */ true);
+ }
+
+ private static MotionEvent recycleAndNullify(@Nullable MotionEvent event) {
+ if (event != null) {
+ event.recycle();
+ }
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return "MagnificationGestureHandler{" +
+ "mDetectingStateHandler=" + mDetectingStateHandler +
+ ", mMagnifiedInteractionStateHandler=" + mPanningScalingStateHandler +
+ ", mViewportDraggingStateHandler=" + mViewportDraggingStateHandler +
+ ", mDetectTripleTap=" + mDetectTripleTap +
+ ", mDetectShortcutTrigger=" + mDetectShortcutTrigger +
+ ", mCurrentState=" + stateToString(mCurrentState) +
+ ", mPreviousState=" + stateToString(mPreviousState) +
+ ", mShortcutTriggered=" + mShortcutTriggered +
+ ", mDelegatingStateDownTime=" + mDelegatingStateDownTime +
+ ", mMagnificationController=" + mMagnificationController +
+ '}';
+ }
+
private static final class MotionEventInfo {
private static final int MAX_POOL_SIZE = 10;
-
private static final Object sLock = new Object();
-
private static MotionEventInfo sPool;
-
private static int sPoolSize;
private MotionEventInfo mNext;
-
private boolean mInPool;
- public MotionEvent mEvent;
-
- public MotionEvent mRawEvent;
-
- public int mPolicyFlags;
+ public MotionEvent event;
+ public MotionEvent rawEvent;
+ public int policyFlags;
public static MotionEventInfo obtain(MotionEvent event, MotionEvent rawEvent,
int policyFlags) {
synchronized (sLock) {
- MotionEventInfo info;
- if (sPoolSize > 0) {
- sPoolSize--;
- info = sPool;
- sPool = info.mNext;
- info.mNext = null;
- info.mInPool = false;
- } else {
- info = new MotionEventInfo();
- }
+ MotionEventInfo info = obtainInternal();
info.initialize(event, rawEvent, policyFlags);
return info;
}
}
+ @NonNull
+ private static MotionEventInfo obtainInternal() {
+ MotionEventInfo info;
+ if (sPoolSize > 0) {
+ sPoolSize--;
+ info = sPool;
+ sPool = info.mNext;
+ info.mNext = null;
+ info.mInPool = false;
+ } else {
+ info = new MotionEventInfo();
+ }
+ return info;
+ }
+
private void initialize(MotionEvent event, MotionEvent rawEvent,
int policyFlags) {
- mEvent = MotionEvent.obtain(event);
- mRawEvent = MotionEvent.obtain(rawEvent);
- mPolicyFlags = policyFlags;
+ this.event = MotionEvent.obtain(event);
+ this.rawEvent = MotionEvent.obtain(rawEvent);
+ this.policyFlags = policyFlags;
}
public void recycle() {
@@ -897,11 +1010,22 @@ class MagnificationGestureHandler implements EventStreamTransformation {
}
private void clear() {
- mEvent.recycle();
- mEvent = null;
- mRawEvent.recycle();
- mRawEvent = null;
- mPolicyFlags = 0;
+ event = recycleAndNullify(event);
+ rawEvent = recycleAndNullify(rawEvent);
+ policyFlags = 0;
+ }
+
+ static int countOf(MotionEventInfo info, int eventType) {
+ if (info == null) return 0;
+ return (info.event.getAction() == eventType ? 1 : 0)
+ + countOf(info.mNext, eventType);
+ }
+
+ public static String toString(MotionEventInfo info) {
+ return info == null
+ ? ""
+ : MotionEvent.actionToString(info.event.getAction()).replace("ACTION_", "")
+ + " " + MotionEventInfo.toString(info.mNext);
}
}
@@ -927,7 +1051,7 @@ class MagnificationGestureHandler implements EventStreamTransformation {
@Override
public void onReceive(Context context, Intent intent) {
- mGestureHandler.setMagnificationShortcutTriggered(false);
+ mGestureHandler.setShortcutTriggered(false);
}
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 20ccee286fbc..2b8b25ef0fb4 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -522,10 +522,11 @@ final class AutofillManagerServiceImpl {
/**
* Updates the last fill selection when an authentication was selected.
*/
- void setAuthenticationSelected(int sessionId) {
+ void setAuthenticationSelected(int sessionId, @Nullable Bundle clientState) {
synchronized (mLock) {
if (isValidEventLocked("setAuthenticationSelected()", sessionId)) {
- mEventHistory.addEvent(new Event(Event.TYPE_AUTHENTICATION_SELECTED, null));
+ mEventHistory
+ .addEvent(new Event(Event.TYPE_AUTHENTICATION_SELECTED, null, clientState));
}
}
}
@@ -533,11 +534,13 @@ final class AutofillManagerServiceImpl {
/**
* Updates the last fill selection when an dataset authentication was selected.
*/
- void setDatasetAuthenticationSelected(@Nullable String selectedDataset, int sessionId) {
+ void setDatasetAuthenticationSelected(@Nullable String selectedDataset, int sessionId,
+ @Nullable Bundle clientState) {
synchronized (mLock) {
if (isValidEventLocked("setDatasetAuthenticationSelected()", sessionId)) {
mEventHistory.addEvent(
- new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset));
+ new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset,
+ clientState));
}
}
}
@@ -545,10 +548,10 @@ final class AutofillManagerServiceImpl {
/**
* Updates the last fill selection when an save Ui is shown.
*/
- void setSaveShown(int sessionId) {
+ void setSaveShown(int sessionId, @Nullable Bundle clientState) {
synchronized (mLock) {
if (isValidEventLocked("setSaveShown()", sessionId)) {
- mEventHistory.addEvent(new Event(Event.TYPE_SAVE_SHOWN, null));
+ mEventHistory.addEvent(new Event(Event.TYPE_SAVE_SHOWN, null, clientState));
}
}
}
@@ -556,10 +559,12 @@ final class AutofillManagerServiceImpl {
/**
* Updates the last fill response when a dataset was selected.
*/
- void setDatasetSelected(@Nullable String selectedDataset, int sessionId) {
+ void setDatasetSelected(@Nullable String selectedDataset, int sessionId,
+ @Nullable Bundle clientState) {
synchronized (mLock) {
if (isValidEventLocked("setDatasetSelected()", sessionId)) {
- mEventHistory.addEvent(new Event(Event.TYPE_DATASET_SELECTED, selectedDataset));
+ mEventHistory.addEvent(
+ new Event(Event.TYPE_DATASET_SELECTED, selectedDataset, clientState));
}
}
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 95db6039b696..8d9f0aa2f49b 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -597,7 +597,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
getFillContextByRequestIdLocked(requestId).getStructure(), extras);
}
- mService.setAuthenticationSelected(id);
+ mService.setAuthenticationSelected(id, mClientState);
final int authenticationId = AutofillManager.makeAuthenticationId(requestId, datasetIndex);
mHandlerCaller.getHandler().post(() -> startAuthentication(authenticationId,
@@ -970,7 +970,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
if (sDebug) Slog.d(TAG, "Good news, everyone! All checks passed, show save UI!");
- mService.setSaveShown(id);
+ mService.setSaveShown(id, mClientState);
final IAutoFillManagerClient client = getClient();
mPendingSaveUi = new PendingUi(mActivityToken);
getUiForShowing().showSaveUi(mService.getServiceLabel(), saveInfo,
@@ -1532,14 +1532,14 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
}
// Autofill it directly...
if (dataset.getAuthentication() == null) {
- mService.setDatasetSelected(dataset.getId(), id);
+ mService.setDatasetSelected(dataset.getId(), id, mClientState);
autoFillApp(dataset);
return;
}
// ...or handle authentication.
- mService.setDatasetAuthenticationSelected(dataset.getId(), id);
+ mService.setDatasetAuthenticationSelected(dataset.getId(), id, mClientState);
setViewStatesLocked(null, dataset, ViewState.STATE_WAITING_DATASET_AUTH, false);
final Intent fillInIntent = createAuthFillInIntent(
getFillContextByRequestIdLocked(requestId).getStructure(), mClientState);
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 29d562b17deb..c1a7f6882d18 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -10475,7 +10475,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF
public ComponentName[] listAllTransportComponents() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"listAllTransportComponents");
- return mTransportManager.getAllTransportCompenents();
+ return mTransportManager.getAllTransportComponents();
}
@Override
diff --git a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
index b01cfc572432..83b6693e7a70 100644
--- a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
@@ -2762,7 +2762,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter
public ComponentName[] listAllTransportComponents() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"listAllTransportComponents");
- return mTransportManager.getAllTransportCompenents();
+ return mTransportManager.getAllTransportComponents();
}
@Override
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
index fb2982eb0baa..098bc0778ac1 100644
--- a/services/backup/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -41,10 +41,12 @@ import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.backup.IBackupTransport;
import com.android.server.EventLogTags;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -57,7 +59,9 @@ public class TransportManager {
private static final String TAG = "BackupTransportManager";
- private static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST";
+ @VisibleForTesting
+ /* package */ static final String SERVICE_ACTION_TRANSPORT_HOST =
+ "android.backup.TRANSPORT_HOST";
private static final long REBINDING_TIMEOUT_UNPROVISIONED_MS = 30 * 1000; // 30 sec
private static final long REBINDING_TIMEOUT_PROVISIONED_MS = 5 * 60 * 1000; // 5 mins
@@ -95,7 +99,11 @@ public class TransportManager {
TransportBoundListener listener, Looper looper) {
mContext = context;
mPackageManager = context.getPackageManager();
- mTransportWhitelist = (whitelist != null) ? whitelist : new ArraySet<>();
+ if (whitelist != null) {
+ mTransportWhitelist = whitelist;
+ } else {
+ mTransportWhitelist = new ArraySet<>();
+ }
mCurrentTransportName = defaultTransport;
mTransportBoundListener = listener;
mHandler = new RebindOnTimeoutHandler(looper);
@@ -186,7 +194,7 @@ public class TransportManager {
}
}
- ComponentName[] getAllTransportCompenents() {
+ ComponentName[] getAllTransportComponents() {
synchronized (mTransportLock) {
return mValidTransports.keySet().toArray(new ComponentName[mValidTransports.size()]);
}
@@ -208,7 +216,8 @@ public class TransportManager {
}
}
- void ensureTransportReady(ComponentName transportComponent, SelectBackupTransportCallback listener) {
+ void ensureTransportReady(ComponentName transportComponent,
+ SelectBackupTransportCallback listener) {
synchronized (mTransportLock) {
TransportConnection conn = mValidTransports.get(transportComponent);
if (conn == null) {
@@ -252,7 +261,7 @@ public class TransportManager {
intent, 0, UserHandle.USER_SYSTEM);
if (hosts != null) {
for (ResolveInfo host : hosts) {
- final ComponentName infoComponentName = host.serviceInfo.getComponentName();
+ final ComponentName infoComponentName = getComponentName(host.serviceInfo);
boolean shouldBind = false;
if (components != null && packageName != null) {
for (String component : components) {
@@ -310,7 +319,7 @@ public class TransportManager {
Intent intent = new Intent(mTransportServiceIntent)
.setComponent(componentName);
return mContext.bindServiceAsUser(intent, connection, Context.BIND_AUTO_CREATE,
- UserHandle.SYSTEM);
+ createSystemUserHandle());
}
private class TransportConnection implements ServiceConnection {
@@ -333,7 +342,7 @@ public class TransportManager {
boolean success = false;
EventLog.writeEvent(EventLogTags.BACKUP_TRANSPORT_LIFECYCLE,
- component.flattenToShortString(), 1);
+ component.flattenToShortString(), 1);
try {
mTransportName = mBinder.name();
@@ -437,7 +446,8 @@ public class TransportManager {
}
private long getRebindTimeout() {
- final boolean isDeviceProvisioned = Settings.Global.getInt(mContext.getContentResolver(),
+ final boolean isDeviceProvisioned = Settings.Global.getInt(
+ mContext.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 0) != 0;
return isDeviceProvisioned
? REBINDING_TIMEOUT_PROVISIONED_MS
@@ -445,7 +455,7 @@ public class TransportManager {
}
}
- interface TransportBoundListener {
+ public interface TransportBoundListener {
/** Should return true if this is a valid transport. */
boolean onTransportBound(IBackupTransport binder);
}
@@ -465,7 +475,7 @@ public class TransportManager {
synchronized (mTransportLock) {
if (mBoundTransports.containsValue(transportComponent)) {
Slog.d(TAG, "Explicit rebinding timeout passed, but already bound to "
- + componentShortString + " so not attempting to rebind");
+ + componentShortString + " so not attempting to rebind");
return;
}
Slog.d(TAG, "Explicit rebinding timeout passed, attempting rebinding to: "
@@ -492,4 +502,18 @@ public class TransportManager {
Slog.v(TAG, message);
}
}
+
+ // These only exists to make it testable with Robolectric, which is not updated to API level 24
+ // yet.
+ // TODO: Get rid of this once Robolectric is updated.
+ private static ComponentName getComponentName(ServiceInfo serviceInfo) {
+ return new ComponentName(serviceInfo.packageName, serviceInfo.name);
+ }
+
+ // These only exists to make it testable with Robolectric, which is not updated to API level 24
+ // yet.
+ // TODO: Get rid of this once Robolectric is updated.
+ private static UserHandle createSystemUserHandle() {
+ return new UserHandle(UserHandle.USER_SYSTEM);
+ }
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 17292b449072..adf536bbf487 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2011,7 +2011,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
break;
}
case NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED: {
- handleUpdateLinkProperties(nai, (LinkProperties) msg.obj);
+ if (VDBG) {
+ log("Update of LinkProperties for " + nai.name() +
+ "; created=" + nai.created +
+ "; everConnected=" + nai.everConnected);
+ }
+ LinkProperties oldLp = nai.linkProperties;
+ synchronized (nai) {
+ nai.linkProperties = (LinkProperties)msg.obj;
+ }
+ if (nai.everConnected) updateLinkProperties(nai, oldLp);
break;
}
case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: {
@@ -2260,7 +2269,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
mNetworkAgentInfos.remove(msg.replyTo);
- nai.maybeStopClat();
+ maybeStopClat(nai);
synchronized (mNetworkForNetId) {
// Remove the NetworkAgent, but don't mark the netId as
// available until we've told netd to delete it below.
@@ -4374,7 +4383,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
updateDnses(newLp, oldLp, netId);
// Start or stop clat accordingly to network state.
- networkAgent.updateClat(mNetd);
+ updateClat(networkAgent);
if (isDefaultNetwork(networkAgent)) {
handleApplyDefaultProxy(newLp.getHttpProxy());
} else {
@@ -4389,6 +4398,32 @@ public class ConnectivityService extends IConnectivityManager.Stub
mKeepaliveTracker.handleCheckKeepalivesStillValid(networkAgent);
}
+ private void updateClat(NetworkAgentInfo nai) {
+ if (Nat464Xlat.requiresClat(nai)) {
+ maybeStartClat(nai);
+ } else {
+ maybeStopClat(nai);
+ }
+ }
+
+ /** Ensure clat has started for this network. */
+ private void maybeStartClat(NetworkAgentInfo nai) {
+ if (nai.clatd != null && nai.clatd.isStarted()) {
+ return;
+ }
+ nai.clatd = new Nat464Xlat(mNetd, mTrackerHandler, nai);
+ nai.clatd.start();
+ }
+
+ /** Ensure clat has stopped for this network. */
+ private void maybeStopClat(NetworkAgentInfo nai) {
+ if (nai.clatd == null) {
+ return;
+ }
+ nai.clatd.stop();
+ nai.clatd = null;
+ }
+
private void wakeupModifyInterface(String iface, NetworkCapabilities caps, boolean add) {
// Marks are only available on WiFi interaces. Checking for
// marks on unsupported interfaces is harmless.
@@ -4623,21 +4658,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- public void handleUpdateLinkProperties(NetworkAgentInfo nai, LinkProperties newLp) {
- if (VDBG) {
- log("Update of LinkProperties for " + nai.name() +
- "; created=" + nai.created +
- "; everConnected=" + nai.everConnected);
- }
- LinkProperties oldLp = nai.linkProperties;
- synchronized (nai) {
- nai.linkProperties = newLp;
- }
- if (nai.everConnected) {
- updateLinkProperties(nai, oldLp);
- }
- }
-
private void sendUpdatedScoreToFactories(NetworkAgentInfo nai) {
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest nr = nai.requestAt(i);
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 473384081656..046eb761d1c0 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -728,6 +728,9 @@ public class VibratorService extends IVibratorService.Stub
return timeout;
}
}
+ if (!prebaked.shouldFallback()) {
+ return 0;
+ }
final int id = prebaked.getId();
if (id < 0 || id >= mFallbackEffects.length || mFallbackEffects[id] == null) {
Slog.w(TAG, "Failed to play prebaked effect, no fallback");
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 7e90c9276ff0..8ae592f7978a 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -2191,7 +2191,7 @@ public class AccountManagerService
return false;
} else if (!isAccountManagedByCaller(account.type, callingUid, userId)) {
String msg = String.format(
- "uid %s cannot explicitly add accounts of type: %s",
+ "uid %s cannot explicitly remove accounts of type: %s",
callingUid,
account.type);
throw new SecurityException(msg);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 132ce1200eb5..8f68bd6c2781 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -197,7 +197,6 @@ import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackId;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityManager.TaskSnapshot;
-import android.app.ActivityManager.TaskThumbnailInfo;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal.SleepToken;
import android.app.ActivityOptions;
@@ -1685,6 +1684,7 @@ public class ActivityManagerService extends IActivityManager.Stub
static final int DISPATCH_PENDING_INTENT_CANCEL_MSG = 67;
static final int PUSH_TEMP_WHITELIST_UI_MSG = 68;
static final int SERVICE_FOREGROUND_CRASH_MSG = 69;
+ static final int USER_SWITCH_CALLBACKS_TIMEOUT_MSG = 70;
static final int START_USER_SWITCH_FG_MSG = 712;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
@@ -2143,6 +2143,10 @@ public class ActivityManagerService extends IActivityManager.Stub
mUserController.timeoutUserSwitch((UserState) msg.obj, msg.arg1, msg.arg2);
break;
}
+ case USER_SWITCH_CALLBACKS_TIMEOUT_MSG: {
+ mUserController.timeoutUserSwitchCallbacks(msg.arg1, msg.arg2);
+ break;
+ }
case IMMERSIVE_MODE_LOCK_MSG: {
final boolean nextState = (msg.arg1 != 0);
if (mUpdateLock.isHeld() != nextState) {
@@ -3089,7 +3093,7 @@ public class ActivityManagerService extends IActivityManager.Stub
*/
void setResumedActivityUncheckLocked(ActivityRecord r, String reason) {
final TaskRecord task = r.getTask();
- if (task.isApplicationTask()) {
+ if (task.isActivityTypeStandard()) {
if (mCurAppTimeTracker != r.appTimeTracker) {
// We are switching app tracking. Complete the current one.
if (mCurAppTimeTracker != null) {
@@ -9930,7 +9934,7 @@ public class ActivityManagerService extends IActivityManager.Stub
if (!allowed) {
// If the caller doesn't have the GET_TASKS permission, then only
// allow them to see a small subset of tasks -- their own and home.
- if (!tr.isHomeTask() && tr.effectiveUid != callingUid) {
+ if (!tr.isActivityTypeHome() && tr.effectiveUid != callingUid) {
if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + tr);
continue;
}
@@ -9991,20 +9995,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public ActivityManager.TaskThumbnail getTaskThumbnail(int id) {
- synchronized (this) {
- enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
- "getTaskThumbnail()");
- final TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(
- id, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS, INVALID_STACK_ID);
- if (tr != null) {
- return tr.getTaskThumbnailLocked();
- }
- }
- return null;
- }
-
- @Override
public ActivityManager.TaskDescription getTaskDescription(int id) {
synchronized (this) {
enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
@@ -10071,7 +10061,7 @@ public class ActivityManagerService extends IActivityManager.Stub
TaskRecord task = new TaskRecord(this,
mStackSupervisor.getNextTaskIdForUserLocked(r.userId),
- ainfo, intent, description, new TaskThumbnailInfo());
+ ainfo, intent, description);
int trimIdx = mRecentTasks.trimForTaskLocked(task, false);
if (trimIdx >= 0) {
@@ -10090,8 +10080,8 @@ public class ActivityManagerService extends IActivityManager.Stub
mRecentTasks.add(task);
r.getStack().addTask(task, false, "addAppTask");
- task.setLastThumbnailLocked(thumbnail);
- task.freeLastThumbnail();
+ // TODO: Send the thumbnail to WM to store it.
+
return task.taskId;
}
} finally {
@@ -12955,7 +12945,7 @@ public class ActivityManagerService extends IActivityManager.Stub
int userId;
synchronized (this) {
final ActivityStack focusedStack = getFocusedStack();
- if (focusedStack == null || focusedStack.isAssistantStack()) {
+ if (focusedStack == null || focusedStack.isActivityTypeAssistant()) {
return false;
}
@@ -13060,7 +13050,7 @@ public class ActivityManagerService extends IActivityManager.Stub
pae = new PendingAssistExtras(activity, extras, intent, hint, receiver, receiverExtras,
userHandle);
- pae.isHome = activity.isHomeActivity();
+ pae.isHome = activity.isActivityTypeHome();
// Increment the sessionId if necessary
if (newSessionId) {
@@ -13287,7 +13277,7 @@ public class ActivityManagerService extends IActivityManager.Stub
synchronized (this) {
final ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r != null) {
- final ActivityOptions activityOptions = r.pendingOptions;
+ final ActivityOptions activityOptions = r.takeOptionsLocked();
return activityOptions == null ? null : activityOptions.toBundle();
}
return null;
@@ -21874,7 +21864,7 @@ public class ActivityManagerService extends IActivityManager.Stub
int changes = 0;
if (app.curAdj != app.setAdj) {
- ProcessList.setOomAdj(app.pid, app.info.uid, app.curAdj);
+ ProcessList.setOomAdj(app.pid, app.uid, app.curAdj);
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
"Set " + app.pid + " " + app.processName + " adj " + app.curAdj + ": "
+ app.adjType);
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index ded202db8713..651d3a6a044e 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -16,13 +16,10 @@
package com.android.server.am;
-import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS;
import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
-import static android.app.ActivityManager.StackId;
import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.app.ActivityManager.TaskDescription.ATTR_TASKDESCRIPTION_PREFIX;
@@ -36,6 +33,12 @@ import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.OP_PICTURE_IN_PICTURE;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.activityTypeToString;
import static android.content.Intent.ACTION_MAIN;
import static android.content.Intent.CATEGORY_HOME;
import static android.content.Intent.CATEGORY_LAUNCHER;
@@ -48,11 +51,12 @@ import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
import static android.content.pm.ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
-import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
import static android.content.pm.ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE;
import static android.content.pm.ActivityInfo.FLAG_MULTIPROCESS;
+import static android.content.pm.ActivityInfo.FLAG_NO_HISTORY;
import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
+import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
import static android.content.pm.ActivityInfo.FLAG_STATE_NOT_NEEDED;
import static android.content.pm.ActivityInfo.FLAG_TURN_SCREEN_ON;
import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
@@ -65,7 +69,6 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
-import static android.content.pm.ActivityInfo.FLAG_NO_HISTORY;
import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
import static android.content.pm.ActivityInfo.isFixedOrientationPortrait;
import static android.content.res.Configuration.EMPTY;
@@ -79,13 +82,10 @@ import static android.os.Build.VERSION_CODES.O_MR1;
import static android.os.Process.SYSTEM_UID;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.view.WindowManagerPolicy.NAV_BAR_LEFT;
-
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SCREENSHOTS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_THUMBNAILS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBILITY;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SAVED_STATE;
@@ -96,7 +96,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_THUMBNAIL
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityManagerService.TAKE_FULLSCREEN_SCREENSHOTS;
import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING;
@@ -233,12 +232,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
private final boolean componentSpecified; // did caller specify an explicit component?
final boolean rootVoiceInteraction; // was this the root activity of a voice interaction?
- static final int APPLICATION_ACTIVITY_TYPE = 0;
- static final int HOME_ACTIVITY_TYPE = 1;
- static final int RECENTS_ACTIVITY_TYPE = 2;
- static final int ASSISTANT_ACTIVITY_TYPE = 3;
- int mActivityType;
-
private CharSequence nonLocalizedLabel; // the label information from the package mgr.
private int labelRes; // the label information from the package mgr.
private int icon; // resource identifier of activity's icon.
@@ -319,8 +312,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
int mStartingWindowState = STARTING_WINDOW_NOT_SHOWN;
boolean mTaskOverlay = false; // Task is always on-top of other activities in the task.
- boolean mUpdateTaskThumbnailWhenHidden;
-
TaskDescription taskDescription; // the recents information for this activity
boolean mLaunchTaskBehind; // this activity is actively being launched with
// ActivityOptions.setLaunchTaskBehind, will be cleared once launch is completed.
@@ -397,7 +388,8 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
pw.print(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded);
pw.print(" componentSpecified="); pw.print(componentSpecified);
- pw.print(" mActivityType="); pw.println(mActivityType);
+ pw.print(" mActivityType="); pw.println(
+ activityTypeToString(getActivityType()));
if (rootVoiceInteraction) {
pw.print(prefix); pw.print("rootVoiceInteraction="); pw.println(rootVoiceInteraction);
}
@@ -504,7 +496,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
pw.print(prefix); pw.print("frozenBeforeDestroy="); pw.print(frozenBeforeDestroy);
pw.print(" forceNewConfig="); pw.println(forceNewConfig);
pw.print(prefix); pw.print("mActivityType=");
- pw.println(activityTypeToString(mActivityType));
+ pw.println(activityTypeToString(getActivityType()));
if (requestedVrComponent != null) {
pw.print(prefix);
pw.print("requestedVrComponent=");
@@ -661,14 +653,14 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
}
- void updatePictureInPictureMode(Rect targetStackBounds) {
+ void updatePictureInPictureMode(Rect targetStackBounds, boolean forceUpdate) {
if (task == null || task.getStack() == null || app == null || app.thread == null) {
return;
}
final boolean inPictureInPictureMode = (task.getStackId() == PINNED_STACK_ID) &&
(targetStackBounds != null);
- if (inPictureInPictureMode != mLastReportedPictureInPictureMode) {
+ if (inPictureInPictureMode != mLastReportedPictureInPictureMode || forceUpdate) {
// Picture-in-picture mode changes also trigger a multi-window mode change as well, so
// update that here in order
mLastReportedPictureInPictureMode = inPictureInPictureMode;
@@ -683,8 +675,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
private void schedulePictureInPictureModeChanged(Configuration overrideConfig) {
try {
app.thread.schedulePictureInPictureModeChanged(appToken,
- mLastReportedPictureInPictureMode,
- overrideConfig);
+ mLastReportedPictureInPictureMode, overrideConfig);
} catch (Exception e) {
// If process died, no one cares.
}
@@ -947,7 +938,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
task.voiceSession != null, mLaunchTaskBehind, isAlwaysFocusable(),
appInfo.targetSdkVersion, mRotationAnimationHint,
ActivityManagerService.getInputDispatchingTimeoutLocked(this) * 1000000L,
- getOverrideConfiguration(), mBounds);
+ new Configuration(getOverrideConfiguration()), mBounds);
task.addActivityToTop(this);
@@ -1037,10 +1028,11 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
private void setActivityType(boolean componentSpecified, int launchedFromUid, Intent intent,
ActivityOptions options, ActivityRecord sourceRecord) {
+ int activityType = ACTIVITY_TYPE_UNDEFINED;
if ((!componentSpecified || canLaunchHomeActivity(launchedFromUid, sourceRecord))
&& isHomeIntent(intent) && !isResolverActivity()) {
// This sure looks like a home activity!
- mActivityType = HOME_ACTIVITY_TYPE;
+ activityType = ACTIVITY_TYPE_HOME;
if (info.resizeMode == RESIZE_MODE_FORCE_RESIZEABLE
|| info.resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
@@ -1048,13 +1040,12 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
}
} else if (realActivity.getClassName().contains(RECENTS_PACKAGE_NAME)) {
- mActivityType = RECENTS_ACTIVITY_TYPE;
+ activityType = ACTIVITY_TYPE_RECENTS;
} else if (options != null && options.getLaunchStackId() == ASSISTANT_STACK_ID
&& canLaunchAssistActivity(launchedFromPackage)) {
- mActivityType = ASSISTANT_ACTIVITY_TYPE;
- } else {
- mActivityType = APPLICATION_ACTIVITY_TYPE;
+ activityType = ACTIVITY_TYPE_ASSISTANT;
}
+ setActivityType(activityType);
}
void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) {
@@ -1105,18 +1096,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
return stack != null && stack.isInStackLocked(this) != null;
}
- boolean isHomeActivity() {
- return mActivityType == HOME_ACTIVITY_TYPE;
- }
-
- boolean isRecentsActivity() {
- return mActivityType == RECENTS_ACTIVITY_TYPE;
- }
-
- boolean isAssistantActivity() {
- return mActivityType == ASSISTANT_ACTIVITY_TYPE;
- }
-
boolean isPersistable() {
return (info.persistableMode == PERSIST_ROOT_ONLY ||
info.persistableMode == PERSIST_ACROSS_REBOOTS) &&
@@ -1143,7 +1122,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
* @return whether this activity supports PiP multi-window and can be put in the pinned stack.
*/
boolean supportsPictureInPicture() {
- return service.mSupportsPictureInPicture && !isHomeActivity()
+ return service.mSupportsPictureInPicture && isActivityTypeStandard()
&& info.supportsPictureInPicture();
}
@@ -1169,7 +1148,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
* @return whether this activity supports non-PiP multi-window.
*/
private boolean supportsResizeableMultiWindow() {
- return service.mSupportsMultiWindow && !isHomeActivity()
+ return service.mSupportsMultiWindow && !isActivityTypeHome()
&& (ActivityInfo.isResizeableMode(info.resizeMode)
|| service.mForceResizableActivities);
}
@@ -1496,72 +1475,10 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
}
- void updateThumbnailLocked(Bitmap newThumbnail, CharSequence description) {
- if (newThumbnail != null) {
- if (DEBUG_THUMBNAILS) Slog.i(TAG_THUMBNAILS,
- "Setting thumbnail of " + this + " to " + newThumbnail);
- boolean thumbnailUpdated = task.setLastThumbnailLocked(newThumbnail);
- if (thumbnailUpdated && isPersistable()) {
- service.notifyTaskPersisterLocked(task, false);
- }
- }
+ private void updateTaskDescription(CharSequence description) {
task.lastDescription = description;
}
- final Bitmap screenshotActivityLocked() {
- if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "screenshotActivityLocked: " + this);
-
- if (ENABLE_TASK_SNAPSHOTS) {
- // No need to screenshot if snapshots are enabled.
- if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS,
- "\tSnapshots are enabled, abort taking screenshot");
- return null;
- }
-
- if (noDisplay) {
- if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tNo display");
- return null;
- }
-
- final ActivityStack stack = getStack();
- if (stack.isHomeOrRecentsStack()) {
- // This is an optimization -- since we never show Home or Recents within Recents itself,
- // we can just go ahead and skip taking the screenshot if this is the home stack.
- if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, stack.getStackId() == HOME_STACK_ID ?
- "\tHome stack" : "\tRecents stack");
- return null;
- }
-
- int w = service.mThumbnailWidth;
- int h = service.mThumbnailHeight;
-
- if (w <= 0) {
- Slog.e(TAG, "\tInvalid thumbnail dimensions: " + w + "x" + h);
- return null;
- }
-
- if (stack.mStackId == DOCKED_STACK_ID && mStackSupervisor.mIsDockMinimized) {
- // When the docked stack is minimized its app windows are cropped significantly so any
- // screenshot taken will not display the apps contain. So, we avoid taking a screenshot
- // in that case.
- if (DEBUG_SCREENSHOTS) Slog.e(TAG, "\tIn minimized docked stack");
- return null;
- }
-
- float scale = 0;
- if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tTaking screenshot");
-
- // When this flag is set, we currently take the fullscreen screenshot of the activity but
- // scaled to half the size. This gives us a "good-enough" fullscreen thumbnail to use within
- // SystemUI while keeping memory usage low.
- if (TAKE_FULLSCREEN_SCREENSHOTS) {
- w = h = -1;
- scale = service.mFullscreenThumbnailScale;
- }
-
- return mWindowContainerController.screenshotApplications(getDisplayId(), w, h, scale);
- }
-
void setDeferHidingClient(boolean deferHidingClient) {
if (mDeferHidingClient == deferHidingClient) {
return;
@@ -1575,8 +1492,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
void setVisibility(boolean visible) {
- mWindowContainerController.setVisibility(visible, visibleIgnoringKeyguard,
- mDeferHidingClient);
+ mWindowContainerController.setVisibility(visible, mDeferHidingClient);
mStackSupervisor.mActivityMetricsLogger.notifyVisibilityChanged(this, visible);
}
@@ -1584,10 +1500,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
void setVisible(boolean newVisible) {
visible = newVisible;
mDeferHidingClient = !visible && mDeferHidingClient;
- if (!visible && mUpdateTaskThumbnailWhenHidden) {
- updateThumbnailLocked(screenshotActivityLocked(), null /* description */);
- mUpdateTaskThumbnailWhenHidden = false;
- }
setVisibility(visible);
mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
}
@@ -1597,7 +1509,12 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
}
void notifyUnknownVisibilityLaunched() {
- mWindowContainerController.notifyUnknownVisibilityLaunched();
+
+ // No display activities never add a window, so there is no point in waiting them for
+ // relayout.
+ if (!noDisplay) {
+ mWindowContainerController.notifyUnknownVisibilityLaunched();
+ }
}
/**
@@ -1613,7 +1530,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
boolean isVisible = !behindFullscreenActivity || mLaunchTaskBehind;
- if (service.mSupportsLeanbackOnly && isVisible && isRecentsActivity()) {
+ if (service.mSupportsLeanbackOnly && isVisible && isActivityTypeRecents()) {
// On devices that support leanback only (Android TV), Recents activity can only be
// visible if the home stack is the focused stack or we are in split-screen mode.
isVisible = mStackSupervisor.getStack(DOCKED_STACK_ID) != null
@@ -1691,7 +1608,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
newIntents = null;
stopped = false;
- if (isHomeActivity()) {
+ if (isActivityTypeHome()) {
ProcessRecord app = task.mActivities.get(0).app;
if (app != null && app != service.mHomeProcess) {
service.mHomeProcess = app;
@@ -1753,7 +1670,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
icicle = newIcicle;
haveState = true;
launchCount = 0;
- updateThumbnailLocked(null /* newThumbnail */, description);
+ updateTaskDescription(description);
}
if (!stopped) {
if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to STOPPED: " + this + " (stop complete)");
@@ -2221,7 +2138,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
config.getOverrideConfiguration());
}
- void setLastReportedConfiguration(Configuration global, Configuration override) {
+ private void setLastReportedConfiguration(Configuration global, Configuration override) {
mLastReportedConfiguration.setConfiguration(global, override);
}
@@ -2794,16 +2711,6 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo
return r;
}
- private static String activityTypeToString(int type) {
- switch (type) {
- case APPLICATION_ACTIVITY_TYPE: return "APPLICATION_ACTIVITY_TYPE";
- case HOME_ACTIVITY_TYPE: return "HOME_ACTIVITY_TYPE";
- case RECENTS_ACTIVITY_TYPE: return "RECENTS_ACTIVITY_TYPE";
- case ASSISTANT_ACTIVITY_TYPE: return "ASSISTANT_ACTIVITY_TYPE";
- default: return Integer.toString(type);
- }
- }
-
private static boolean isInVrUiMode(Configuration config) {
return (config.uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_VR_HEADSET;
}
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 89d62d19214d..4560d3a6e4f7 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -23,8 +23,12 @@ import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
+import static android.app.ActivityManager.StackId.getActivityTypeForStackId;
import static android.app.ActivityManager.StackId.getWindowingModeForStackId;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
@@ -66,9 +70,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_USER_LEAV
import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.ASSISTANT_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
import static com.android.server.am.ActivityStackSupervisor.FindTaskResult;
@@ -486,6 +487,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (windowingMode != WINDOWING_MODE_UNDEFINED) {
setWindowingMode(windowingMode);
}
+ final int activityType = getActivityTypeForStackId(mStackId);
+ if (activityType != ACTIVITY_TYPE_UNDEFINED) {
+ setActivityType(activityType);
+ }
}
/** Adds the stack to specified display and calls WindowManager to do the same. */
@@ -831,14 +836,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
return hadit;
}
- final boolean isHomeStack() {
- return mStackId == HOME_STACK_ID;
- }
-
- final boolean isRecentsStack() {
- return mStackId == RECENTS_STACK_ID;
- }
-
final boolean isHomeOrRecentsStack() {
return StackId.isHomeOrRecentsStack(mStackId);
}
@@ -851,10 +848,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
return mStackId == PINNED_STACK_ID;
}
- final boolean isAssistantStack() {
- return mStackId == ASSISTANT_STACK_ID;
- }
-
final boolean isOnHomeDisplay() {
return isAttached() && mDisplayId == DEFAULT_DISPLAY;
}
@@ -975,7 +968,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch root " + r);
continue;
}
- if (r.mActivityType != target.mActivityType) {
+ if (!r.hasCompatibleActivityType(target)) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch activity type");
continue;
}
@@ -1341,11 +1334,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
prev.getTask().touchActiveTime();
clearLaunchTime(prev);
final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
- if (mService.mHasRecents
- && (next == null || next.noDisplay || next.getTask() != prev.getTask()
- || uiSleeping)) {
- prev.mUpdateTaskThumbnailWhenHidden = true;
- }
+
stopFullyDrawnTraceIfNeeded();
mService.updateCpuStats();
@@ -1660,7 +1649,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
if (!isHomeOrRecentsStack() && r.frontOfTask && task.isOverHomeStack()
- && !StackId.isHomeOrRecentsStack(stackBehindId) && !isAssistantStack()) {
+ && !StackId.isHomeOrRecentsStack(stackBehindId)
+ && !isActivityTypeAssistant()) {
// Stack isn't translucent if it's top activity should have the home stack
// behind it and the stack currently behind it isn't the home or recents stack
// or the assistant stack.
@@ -1707,7 +1697,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (mStackId == DOCKED_STACK_ID) {
// If the assistant stack is focused and translucent, then the docked stack is always
// visible
- if (topStack.isAssistantStack()) {
+ if (topStack.isActivityTypeAssistant()) {
return (topStack.isStackTranslucent(starting, DOCKED_STACK_ID)) ? STACK_VISIBLE
: STACK_INVISIBLE;
}
@@ -1839,14 +1829,6 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
if (r.finishing) {
- // Normally the screenshot will be taken in makeInvisible(). When an activity
- // is finishing, we no longer change its visibility, but we still need to take
- // the screenshots if startPausingLocked decided it should be taken.
- if (r.mUpdateTaskThumbnailWhenHidden) {
- r.updateThumbnailLocked(r.screenshotActivityLocked(),
- null /* description */);
- r.mUpdateTaskThumbnailWhenHidden = false;
- }
continue;
}
final boolean isTop = r == top;
@@ -1917,39 +1899,22 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// status of an activity in a previous task affects other.
behindFullscreenActivity = stackVisibility == STACK_INVISIBLE;
} else if (mStackId == HOME_STACK_ID) {
- if (task.isHomeTask()) {
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Home task: at " + task
- + " stackInvisible=" + stackInvisible
- + " behindFullscreenActivity=" + behindFullscreenActivity);
- // No other task in the home stack should be visible behind the home activity.
- // Home activities is usually a translucent activity with the wallpaper behind
- // them. However, when they don't have the wallpaper behind them, we want to
- // show activities in the next application stack behind them vs. another
- // task in the home stack like recents.
- behindFullscreenActivity = true;
- } else if (task.isRecentsTask()
- && task.getTaskToReturnTo() == APPLICATION_ACTIVITY_TYPE) {
- if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
- "Recents task returning to app: at " + task
- + " stackInvisible=" + stackInvisible
- + " behindFullscreenActivity=" + behindFullscreenActivity);
- // We don't want any other tasks in the home stack visible if the recents
- // activity is going to be returning to an application activity type.
- // We do this to preserve the visible order the user used to get into the
- // recents activity. The recents activity is normally translucent and if it
- // doesn't have the wallpaper behind it the next activity in the home stack
- // shouldn't be visible when the home stack is brought to the front to display
- // the recents activity from an app.
- behindFullscreenActivity = true;
- }
+ if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Home task: at " + task
+ + " stackInvisible=" + stackInvisible
+ + " behindFullscreenActivity=" + behindFullscreenActivity);
+ // No other task in the home stack should be visible behind the home activity.
+ // Home activities is usually a translucent activity with the wallpaper behind
+ // them. However, when they don't have the wallpaper behind them, we want to
+ // show activities in the next application stack behind them vs. another
+ // task in the home stack like recents.
+ behindFullscreenActivity = true;
} else if (mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Skipping after task=" + task
+ " returning to non-application type=" + task.getTaskToReturnTo());
// Once we reach a fullscreen stack task that has a running activity and should
// return to another stack task, then no other activities behind that one should
// be visible.
- if (task.topRunningActivityLocked() != null &&
- task.getTaskToReturnTo() != APPLICATION_ACTIVITY_TYPE) {
+ if (task.topRunningActivityLocked() != null && !task.returnsToStandardTask()) {
behindFullscreenActivity = true;
}
}
@@ -2346,10 +2311,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// This task is going away but it was supposed to return to the home stack.
// Now the task above it has to return to the home task instead.
final int taskNdx = mTaskHistory.indexOf(prevTask) + 1;
- mTaskHistory.get(taskNdx).setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+ mTaskHistory.get(taskNdx).setTaskToReturnTo(ACTIVITY_TYPE_HOME);
} else if (!isOnHomeDisplay()) {
return false;
- } else if (!isHomeStack()){
+ } else if (!isActivityTypeHome()){
if (DEBUG_STATES) Slog.d(TAG_STATES,
"resumeTopActivityLocked: Launching home next");
return isOnHomeDisplay() &&
@@ -2832,7 +2797,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// If this is not on the default display, then just set the return type to application
if (!isOnHomeDisplay()) {
- task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
+ task.setTaskToReturnTo(ACTIVITY_TYPE_STANDARD);
return;
}
@@ -2844,8 +2809,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
// If the task was launched from the assistant stack, set the return type to assistant
- if (lastStack.isAssistantStack()) {
- task.setTaskToReturnTo(ASSISTANT_ACTIVITY_TYPE);
+ if (lastStack.isActivityTypeAssistant()) {
+ task.setTaskToReturnTo(ACTIVITY_TYPE_ASSISTANT);
return;
}
@@ -2857,9 +2822,10 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// If it's a last task over home - we default to keep its return to type not to
// make underlying task focused when this one will be finished.
int returnToType = isLastTaskOverHome
- ? task.getTaskToReturnTo() : APPLICATION_ACTIVITY_TYPE;
+ ? task.getTaskToReturnTo() : ACTIVITY_TYPE_STANDARD;
if (fromHomeOrRecents && StackId.allowTopTaskToReturnHome(mStackId)) {
- returnToType = topTask == null ? HOME_ACTIVITY_TYPE : topTask.taskType;
+ returnToType = topTask == null
+ ? ACTIVITY_TYPE_HOME : topTask.getActivityType();
}
task.setTaskToReturnTo(returnToType);
}
@@ -3111,7 +3077,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
} else {
targetTask = createTaskRecord(
mStackSupervisor.getNextTaskIdForUserLocked(target.userId),
- target.info, null, null, null, false, target.mActivityType);
+ target.info, null, null, null, false);
targetTask.affinityIntent = target.intent;
if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + target
+ " out to new task " + targetTask);
@@ -3422,8 +3388,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
throw new IllegalStateException("activity no longer associated with task:" + r);
}
- final boolean isAssistantOrOverAssistant = task.getStack().isAssistantStack() ||
- task.isOverAssistantStack();
+ final boolean isAssistantOrOverAssistant =
+ task.getStack().isActivityTypeAssistant() || task.isOverAssistantStack();
if (r.frontOfTask && isATopFinishingTask(task)
&& (task.isOverHomeStack() || isAssistantOrOverAssistant)) {
// For non-fullscreen or assistant stack, we want to move the focus to the next
@@ -3458,8 +3424,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
* @param allowFocusSelf Is the focus allowed to remain on the same stack.
*/
private boolean adjustFocusToNextFocusableStackLocked(String reason, boolean allowFocusSelf) {
- if (isAssistantStack() && bottomTask() != null &&
- bottomTask().getTaskToReturnTo() == HOME_ACTIVITY_TYPE) {
+ if (isActivityTypeAssistant() && bottomTask() != null
+ && bottomTask().returnsToHomeTask()) {
// If the current stack is the assistant stack, then use the return-to type to determine
// whether to return to the home screen. This is needed to workaround an issue where
// launching a fullscreen task (and subequently returning from that task) will cause
@@ -3484,8 +3450,8 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
return mStackSupervisor.moveHomeStackTaskToTop(reason);
}
- if (stack.isAssistantStack() && top != null
- && top.getTask().getTaskToReturnTo() == HOME_ACTIVITY_TYPE) {
+ if (stack.isActivityTypeAssistant() && top != null
+ && top.getTask().returnsToHomeTask()) {
// It is possible for the home stack to not be directly underneath the assistant stack.
// For example, the assistant may start an activity in the fullscreen stack. Upon
// returning to the assistant stack, we must ensure that the home stack is underneath
@@ -3623,7 +3589,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (r.state == ActivityState.RESUMED
|| r.state == ActivityState.PAUSING
|| r.state == ActivityState.PAUSED) {
- if (!r.isHomeActivity() || mService.mHomeProcess != r.app) {
+ if (!r.isActivityTypeHome() || mService.mHomeProcess != r.app) {
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
finishActivityLocked(r, Activity.RESULT_CANCELED, null, reason, false);
@@ -3940,7 +3906,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (srec.frontOfTask && task != null && task.getBaseIntent() != null
&& task.getBaseIntent().isDocument()) {
// Okay, this activity is at the root of its task. What to do, what to do...
- if (task.getTaskToReturnTo() != ActivityRecord.APPLICATION_ACTIVITY_TYPE) {
+ if (!task.returnsToStandardTask()) {
// Finishing won't return to an application, so we need to recreate.
return true;
}
@@ -3950,11 +3916,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
Slog.w(TAG, "shouldUpRecreateTask: task not in history for " + srec);
return false;
}
- if (taskIdx == 0) {
- // At the bottom of the stack, nothing to go back to.
- return true;
- }
- TaskRecord prevTask = mTaskHistory.get(taskIdx);
+ final TaskRecord prevTask = mTaskHistory.get(taskIdx);
if (!task.affinity.equals(prevTask.affinity)) {
// These are different apps, so need to recreate.
return true;
@@ -4539,17 +4501,18 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
void moveHomeStackTaskToTop() {
+ if (!isActivityTypeHome()) {
+ throw new IllegalStateException("Calling moveHomeStackTaskToTop() on non-home stack: "
+ + this);
+ }
final int top = mTaskHistory.size() - 1;
- for (int taskNdx = top; taskNdx >= 0; --taskNdx) {
- final TaskRecord task = mTaskHistory.get(taskNdx);
- if (task.taskType == HOME_ACTIVITY_TYPE) {
- if (DEBUG_TASKS || DEBUG_STACK) Slog.d(TAG_STACK,
- "moveHomeStackTaskToTop: moving " + task);
- mTaskHistory.remove(taskNdx);
- mTaskHistory.add(top, task);
- updateTaskMovement(task, true);
- return;
- }
+ if (top >= 0) {
+ final TaskRecord task = mTaskHistory.get(top);
+ if (DEBUG_TASKS || DEBUG_STACK) Slog.d(TAG_STACK,
+ "moveHomeStackTaskToTop: moving " + task);
+ mTaskHistory.remove(top);
+ mTaskHistory.add(top, task);
+ updateTaskMovement(task, true);
}
}
@@ -4672,7 +4635,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// If true, we should resume the home activity next if the task we are moving to the
// back is over the home stack. We force to false if the task we are moving to back
// is the home task and we don't want it resumed after moving to the back.
- final boolean canGoHome = !tr.isHomeTask() && tr.isOverHomeStack();
+ final boolean canGoHome = !tr.isActivityTypeHome() && tr.isOverHomeStack();
if (canGoHome) {
final TaskRecord nextTask = getNextTask(tr);
if (nextTask != null) {
@@ -4707,7 +4670,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
if (taskNdx == 1) {
// Set the last task before tr to go to home.
- task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+ task.setTaskToReturnTo(ACTIVITY_TYPE_HOME);
}
}
@@ -4717,7 +4680,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
// Not ready yet!
return false;
}
- tr.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
+ tr.setTaskToReturnTo(ACTIVITY_TYPE_STANDARD);
return mStackSupervisor.resumeHomeStackTask(null, "moveTaskToBack");
}
@@ -4931,7 +4894,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
return true;
}
- if (r.isHomeActivity()) {
+ if (r.isActivityTypeHome()) {
if (homeActivity != null && homeActivity.equals(r.realActivity)) {
Slog.i(TAG, "Skip force-stop again " + r);
continue;
@@ -4974,7 +4937,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
int numActivities = 0;
int numRunning = 0;
final ArrayList<ActivityRecord> activities = task.mActivities;
- if (!allowed && !task.isHomeTask() && task.effectiveUid != callingUid) {
+ if (!allowed && !task.isActivityTypeHome() && task.effectiveUid != callingUid) {
continue;
}
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
@@ -5074,24 +5037,29 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
}
boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
- boolean dumpClient, String dumpPackage, boolean needSep, String header) {
- boolean printed = false;
+ boolean dumpClient, String dumpPackage, boolean needSep) {
+
+ if (mTaskHistory.isEmpty()) {
+ return false;
+ }
+ final String prefix = " ";
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
- printed |= ActivityStackSupervisor.dumpHistoryList(fd, pw,
- mTaskHistory.get(taskNdx).mActivities, " ", "Hist", true, !dumpAll,
- dumpClient, dumpPackage, needSep, header,
- " Task id #" + task.taskId + "\n" +
- " mFullscreen=" + task.mFullscreen + "\n" +
- " mBounds=" + task.mBounds + "\n" +
- " mMinWidth=" + task.mMinWidth + "\n" +
- " mMinHeight=" + task.mMinHeight + "\n" +
- " mLastNonFullscreenBounds=" + task.mLastNonFullscreenBounds);
- if (printed) {
- header = null;
- }
+ if (needSep) {
+ pw.println("");
+ }
+ pw.println(prefix + "Task id #" + task.taskId);
+ pw.println(prefix + "mFullscreen=" + task.mFullscreen);
+ pw.println(prefix + "mBounds=" + task.mBounds);
+ pw.println(prefix + "mMinWidth=" + task.mMinWidth);
+ pw.println(prefix + "mMinHeight=" + task.mMinHeight);
+ pw.println(prefix + "mLastNonFullscreenBounds=" + task.mLastNonFullscreenBounds);
+ pw.println(prefix + "* " + task);
+ task.dump(pw, prefix + " ");
+ ActivityStackSupervisor.dumpHistoryList(fd, pw, mTaskHistory.get(taskNdx).mActivities,
+ prefix, "Hist", true, !dumpAll, dumpClient, dumpPackage, false, null, task);
}
- return printed;
+ return true;
}
ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) {
@@ -5165,7 +5133,7 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
if (task.isOverHomeStack() && taskNdx < topTaskNdx) {
final TaskRecord nextTask = mTaskHistory.get(taskNdx + 1);
if (!nextTask.isOverHomeStack() && !nextTask.isOverAssistantStack()) {
- nextTask.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+ nextTask.setTaskToReturnTo(ACTIVITY_TYPE_HOME);
}
}
mTaskHistory.remove(task);
@@ -5221,9 +5189,9 @@ class ActivityStack<T extends StackWindowController> extends ConfigurationContai
TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
- boolean toTop, int type) {
- TaskRecord task = new TaskRecord(mService, taskId, info, intent, voiceSession,
- voiceInteractor, type);
+ boolean toTop) {
+ final TaskRecord task = new TaskRecord(mService, taskId, info, intent, voiceSession,
+ voiceInteractor);
// add the task to stack first, mTaskPositioner might need the stack association
addTask(task, toTop, "createTaskRecord");
final boolean isLockscreenShown =
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 6ae07d4e6766..e4a2273387be 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -20,7 +20,6 @@ import static android.Manifest.permission.ACTIVITY_EMBEDDING;
import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
import static android.Manifest.permission.START_ANY_ACTIVITY;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
-import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
@@ -34,6 +33,9 @@ import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY;
import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.PowerManager.PARTIAL_WAKE_LOCK;
@@ -68,8 +70,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityManagerService.ANIMATE;
import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
-import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING;
@@ -690,7 +690,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
}
if (prev != null) {
- prev.getTask().setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
+ prev.getTask().setTaskToReturnTo(ACTIVITY_TYPE_STANDARD);
}
mHomeStack.moveHomeStackTaskToTop();
@@ -1344,7 +1344,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
+ " newIntents=" + newIntents + " andResume=" + andResume);
EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY, r.userId,
System.identityHashCode(r), task.taskId, r.shortComponentName);
- if (r.isHomeActivity()) {
+ if (r.isActivityTypeHome()) {
// Home process is the root process of the task.
mService.mHomeProcess = task.mActivities.get(0).app;
}
@@ -2079,7 +2079,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
if ((flags & ActivityManager.MOVE_TASK_WITH_HOME) != 0) {
// Caller wants the home activity moved with it. To accomplish this,
// we'll just indicate that this task returns to the home task.
- task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+ task.setTaskToReturnTo(ACTIVITY_TYPE_HOME);
}
ActivityStack currentStack = task.getStack();
if (currentStack == null) {
@@ -2265,11 +2265,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
final ArrayList<TaskRecord> tasks = mHomeStack.getAllTasks();
for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = tasks.get(taskNdx);
- if (task.isHomeTask()) {
+ if (task.isActivityTypeHome()) {
final ArrayList<ActivityRecord> activities = task.mActivities;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
- if (r.isHomeActivity()
+ if (r.isActivityTypeHome()
&& ((userId == UserHandle.USER_ALL) || (r.userId == userId))) {
return r;
}
@@ -2402,8 +2402,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// Update the return-to to reflect where the pinned stack task was moved
// from so that we retain the stack that was previously visible if the
// pinned stack is recreated. See moveActivityToPinnedStackLocked().
- task.setTaskToReturnTo(isFullscreenStackVisible && onTop ?
- APPLICATION_ACTIVITY_TYPE : HOME_ACTIVITY_TYPE);
+ task.setTaskToReturnTo(isFullscreenStackVisible ?
+ ACTIVITY_TYPE_STANDARD : ACTIVITY_TYPE_HOME);
}
// Defer resume until all the tasks have been moved to the fullscreen stack
task.reparent(FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP,
@@ -2923,7 +2923,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// move the home stack forward if we are currently entering picture-in-picture
// while pausing because that changes the focused stack and may prevent the new
// starting activity from resuming.
- if (moveHomeStackToFront && task.getTaskToReturnTo() == HOME_ACTIVITY_TYPE
+ if (moveHomeStackToFront && task.returnsToHomeTask()
&& (r.state == RESUMED || !r.supportsEnterPipOnTaskSwitch)) {
// Move the home stack forward if the task we just moved to the pinned stack
// was launched from home so home should be visible behind it.
@@ -2942,8 +2942,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
// ensures that all the necessary work to migrate states in the old and new stacks
// is also done.
final TaskRecord newTask = task.getStack().createTaskRecord(
- getNextTaskIdForUserLocked(r.userId), r.info, r.intent, null, null, true,
- r.mActivityType);
+ getNextTaskIdForUserLocked(r.userId), r.info, r.intent, null, null, true);
r.reparent(newTask, MAX_VALUE, "moveActivityToStack");
// Defer resume until below, and do not schedule PiP changes until we animate below
@@ -3015,7 +3014,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
- if (!checkActivityBelongsInStack(r, stack)) {
+ if (!r.hasCompatibleActivityType(stack)) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) "
+ stack);
continue;
@@ -3043,21 +3042,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
return affinityMatch;
}
- /**
- * Checks that for the given activity {@param r}, its activity type matches the {@param stack}
- * type.
- */
- private boolean checkActivityBelongsInStack(ActivityRecord r, ActivityStack stack) {
- if (r.isHomeActivity()) {
- return stack.isHomeStack();
- } else if (r.isRecentsActivity()) {
- return stack.isRecentsStack();
- } else if (r.isAssistantActivity()) {
- return stack.isAssistantStack();
- }
- return true;
- }
-
ActivityRecord findActivityLocked(Intent intent, ActivityInfo info,
boolean compareIntentFilters) {
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
@@ -3267,7 +3251,6 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
final ActivityStack stack = task.getStack();
r.mLaunchTaskBehind = false;
- task.setLastThumbnailLocked(r.screenshotActivityLocked());
mRecentTasks.addLocked(task);
mService.mTaskChangeNotificationController.notifyTaskStackChanged();
r.setVisibility(false);
@@ -3441,7 +3424,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
if (stack == null) {
stack = mHomeStack;
}
- final boolean homeInFront = stack.isHomeStack();
+ final boolean homeInFront = stack.isActivityTypeHome();
if (stack.isOnHomeDisplay()) {
stack.moveToFront("switchUserOnHomeDisplay");
} else {
@@ -3647,25 +3630,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
ArrayList<ActivityStack> stacks = activityDisplay.mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
- StringBuilder stackHeader = new StringBuilder(128);
- stackHeader.append(" Stack #");
- stackHeader.append(stack.mStackId);
- stackHeader.append(":");
- stackHeader.append("\n");
- stackHeader.append(" mFullscreen=" + stack.mFullscreen);
- stackHeader.append("\n");
- stackHeader.append(" isSleeping=" + stack.shouldSleepActivities());
- stackHeader.append("\n");
- stackHeader.append(" mBounds=" + stack.mBounds);
-
- final boolean printedStackHeader = stack.dumpActivitiesLocked(fd, pw, dumpAll,
- dumpClient, dumpPackage, needSep, stackHeader.toString());
- printed |= printedStackHeader;
- if (!printedStackHeader) {
- // Ensure we always dump the stack header even if there are no activities
- pw.println();
- pw.println(stackHeader);
- }
+ pw.println();
+ pw.println(" Stack #" + stack.mStackId + ":");
+ pw.println(" mFullscreen=" + stack.mFullscreen);
+ pw.println(" isSleeping=" + stack.shouldSleepActivities());
+ pw.println(" mBounds=" + stack.mBounds);
+
+ printed |= stack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage,
+ needSep);
printed |= dumpHistoryList(fd, pw, stack.mLRUActivities, " ", "Run", false,
!dumpAll, false, dumpPackage, true,
@@ -3713,8 +3685,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
static boolean dumpHistoryList(FileDescriptor fd, PrintWriter pw, List<ActivityRecord> list,
String prefix, String label, boolean complete, boolean brief, boolean client,
- String dumpPackage, boolean needNL, String header1, String header2) {
- TaskRecord lastTask = null;
+ String dumpPackage, boolean needNL, String header, TaskRecord lastTask) {
String innerPrefix = null;
String[] args = null;
boolean printed = false;
@@ -3733,13 +3704,9 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
pw.println("");
needNL = false;
}
- if (header1 != null) {
- pw.println(header1);
- header1 = null;
- }
- if (header2 != null) {
- pw.println(header2);
- header2 = null;
+ if (header != null) {
+ pw.println(header);
+ header = null;
}
if (lastTask != r.getTask()) {
lastTask = r.getTask();
@@ -4057,7 +4024,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
(preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY)
|| StackId.isDynamicStack(preferredStackId);
if (((!isStackDockedInEffect(actualStackId) && preferredStackId != DOCKED_STACK_ID)
- && !isSecondaryDisplayPreferred) || task.isHomeTask()) {
+ && !isSecondaryDisplayPreferred) || task.isActivityTypeHome()) {
return;
}
@@ -4154,31 +4121,29 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
return;
}
- scheduleUpdatePictureInPictureModeIfNeeded(task, stack.mBounds, false /* immediate */);
+ scheduleUpdatePictureInPictureModeIfNeeded(task, stack.mBounds);
}
- void scheduleUpdatePictureInPictureModeIfNeeded(TaskRecord task, Rect targetStackBounds,
- boolean immediate) {
-
- if (immediate) {
- mHandler.removeMessages(REPORT_PIP_MODE_CHANGED_MSG);
- for (int i = task.mActivities.size() - 1; i >= 0; i--) {
- final ActivityRecord r = task.mActivities.get(i);
- if (r.app != null && r.app.thread != null) {
- r.updatePictureInPictureMode(targetStackBounds);
- }
- }
- } else {
- for (int i = task.mActivities.size() - 1; i >= 0; i--) {
- final ActivityRecord r = task.mActivities.get(i);
- if (r.app != null && r.app.thread != null) {
- mPipModeChangedActivities.add(r);
- }
+ void scheduleUpdatePictureInPictureModeIfNeeded(TaskRecord task, Rect targetStackBounds) {
+ for (int i = task.mActivities.size() - 1; i >= 0; i--) {
+ final ActivityRecord r = task.mActivities.get(i);
+ if (r.app != null && r.app.thread != null) {
+ mPipModeChangedActivities.add(r);
}
- mPipModeChangedTargetStackBounds = targetStackBounds;
+ }
+ mPipModeChangedTargetStackBounds = targetStackBounds;
- if (!mHandler.hasMessages(REPORT_PIP_MODE_CHANGED_MSG)) {
- mHandler.sendEmptyMessage(REPORT_PIP_MODE_CHANGED_MSG);
+ if (!mHandler.hasMessages(REPORT_PIP_MODE_CHANGED_MSG)) {
+ mHandler.sendEmptyMessage(REPORT_PIP_MODE_CHANGED_MSG);
+ }
+ }
+
+ void updatePictureInPictureMode(TaskRecord task, Rect targetStackBounds, boolean forceUpdate) {
+ mHandler.removeMessages(REPORT_PIP_MODE_CHANGED_MSG);
+ for (int i = task.mActivities.size() - 1; i >= 0; i--) {
+ final ActivityRecord r = task.mActivities.get(i);
+ if (r.app != null && r.app.thread != null) {
+ r.updatePictureInPictureMode(targetStackBounds, forceUpdate);
}
}
}
@@ -4240,7 +4205,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D
synchronized (mService) {
for (int i = mPipModeChangedActivities.size() - 1; i >= 0; i--) {
final ActivityRecord r = mPipModeChangedActivities.remove(i);
- r.updatePictureInPictureMode(mPipModeChangedTargetStackBounds);
+ r.updatePictureInPictureMode(mPipModeChangedTargetStackBounds,
+ false /* forceUpdate */);
}
}
} break;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 235477e24a27..16abcfb620d9 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -36,6 +36,9 @@ import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
import static android.app.ActivityManager.StackId.isDynamicStack;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
@@ -72,9 +75,6 @@ import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_USER_LEAV
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.am.ActivityManagerService.ANIMATE;
-import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.ASSISTANT_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
import static com.android.server.am.ActivityStack.STACK_INVISIBLE;
import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED;
@@ -1507,7 +1507,7 @@ class ActivityStarter {
// There can be one and only one instance of single instance activity in the
// history, and it is always in its own unique task, so we do a special search.
intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info,
- mStartActivity.isHomeActivity());
+ mStartActivity.isActivityTypeHome());
} else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
// For the launch adjacent case we only want to put the activity in an existing
// task if the activity already exists in the history.
@@ -1669,21 +1669,21 @@ class ActivityStarter {
if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
// Caller wants to appear on home activity.
- task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+ task.setTaskToReturnTo(ACTIVITY_TYPE_HOME);
return;
- } else if (focusedStack == null || focusedStack.isHomeStack()) {
+ } else if (focusedStack == null || focusedStack.isActivityTypeHome()) {
// Task will be launched over the home stack, so return home.
- task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+ task.setTaskToReturnTo(ACTIVITY_TYPE_HOME);
return;
} else if (focusedStack != null && focusedStack != task.getStack() &&
- focusedStack.isAssistantStack()) {
+ focusedStack.isActivityTypeAssistant()) {
// Task was launched over the assistant stack, so return there
- task.setTaskToReturnTo(ASSISTANT_ACTIVITY_TYPE);
+ task.setTaskToReturnTo(ACTIVITY_TYPE_ASSISTANT);
return;
}
// Else we are coming from an application stack so return to an application.
- task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
+ task.setTaskToReturnTo(ACTIVITY_TYPE_STANDARD);
}
private void setTaskFromIntentActivity(ActivityRecord intentActivity) {
@@ -1791,7 +1791,7 @@ class ActivityStarter {
mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId),
mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
- mVoiceInteractor, !mLaunchTaskBehind /* toTop */, mStartActivity.mActivityType);
+ mVoiceInteractor, !mLaunchTaskBehind /* toTop */);
addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask");
if (mLaunchBounds != null) {
final int stackId = mTargetStack.mStackId;
@@ -1995,7 +1995,7 @@ class ActivityStarter {
final ActivityRecord prev = mTargetStack.topActivity();
final TaskRecord task = (prev != null) ? prev.getTask() : mTargetStack.createTaskRecord(
mSupervisor.getNextTaskIdForUserLocked(mStartActivity.userId), mStartActivity.info,
- mIntent, null, null, true, mStartActivity.mActivityType);
+ mIntent, null, null, true);
addOrReparentStartingActivity(task, "setTaskToCurrentTopOrCreateNewTask");
mTargetStack.positionChildWindowContainerAtTop(task);
if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
@@ -2124,7 +2124,7 @@ class ActivityStarter {
canUseFocusedStack = true;
break;
case ASSISTANT_STACK_ID:
- canUseFocusedStack = r.isAssistantActivity();
+ canUseFocusedStack = r.isActivityTypeAssistant();
break;
case DOCKED_STACK_ID:
// Any activity which supports split screen can go in the docked stack.
@@ -2155,13 +2155,13 @@ class ActivityStarter {
// If the activity is of a specific type, return the associated stack, creating it if
// necessary
- if (r.isHomeActivity()) {
+ if (r.isActivityTypeHome()) {
return mSupervisor.mHomeStack;
}
- if (r.isRecentsActivity()) {
+ if (r.isActivityTypeRecents()) {
return mSupervisor.getStack(RECENTS_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
}
- if (r.isAssistantActivity()) {
+ if (r.isActivityTypeAssistant()) {
return mSupervisor.getStack(ASSISTANT_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
}
@@ -2254,9 +2254,9 @@ class ActivityStarter {
case PINNED_STACK_ID:
return r.supportsPictureInPicture();
case RECENTS_STACK_ID:
- return r.isRecentsActivity();
+ return r.isActivityTypeRecents();
case ASSISTANT_STACK_ID:
- return r.isAssistantActivity();
+ return r.isActivityTypeAssistant();
default:
if (StackId.isDynamicStack(stackId)) {
return r.canBeLaunchedOnDisplay(displayId);
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index fc03db1203bd..d1424c8d43f2 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -55,7 +55,6 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
-import java.util.List;
import java.util.Set;
import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
@@ -676,7 +675,7 @@ class AppErrors {
&& (mService.mHomeProcess.info.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
- if (r.isHomeActivity()) {
+ if (r.isActivityTypeHome()) {
Log.i(TAG, "Clearing package preferred activities from " + r.packageName);
try {
ActivityThread.getPackageManager()
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index 5ff04798110f..5fac397c428f 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -38,6 +38,7 @@ import com.android.internal.os.BatteryStatsImpl;
import libcore.util.EmptyArray;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@@ -116,6 +117,10 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
}
public synchronized Future<?> scheduleWrite() {
+ if (mExecutorService.isShutdown()) {
+ return CompletableFuture.failedFuture(new IllegalStateException("worker shutdown"));
+ }
+
scheduleSyncLocked("write", UPDATE_ALL);
// Since we use a single threaded executor, we can assume the next scheduled task's
// Future finishes after the sync.
@@ -127,7 +132,9 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
* within the task, never wait on the resulting Future. This will result in a deadlock.
*/
public synchronized void scheduleRunnable(Runnable runnable) {
- mExecutorService.submit(runnable);
+ if (!mExecutorService.isShutdown()) {
+ mExecutorService.submit(runnable);
+ }
}
public void shutdown() {
@@ -135,6 +142,10 @@ class BatteryExternalStatsWorker implements BatteryStatsImpl.ExternalStatsSync {
}
private Future<?> scheduleSyncLocked(String reason, int flags) {
+ if (mExecutorService.isShutdown()) {
+ return CompletableFuture.failedFuture(new IllegalStateException("worker shutdown"));
+ }
+
if (mCurrentFuture == null) {
mUpdateFlags = flags;
mCurrentReason = reason;
diff --git a/services/core/java/com/android/server/am/LockTaskController.java b/services/core/java/com/android/server/am/LockTaskController.java
index c03ac86a2bf9..d8706bcc5e35 100644
--- a/services/core/java/com/android/server/am/LockTaskController.java
+++ b/services/core/java/com/android/server/am/LockTaskController.java
@@ -28,6 +28,7 @@ import static android.app.StatusBarManager.DISABLE_RECENT;
import static android.content.Context.DEVICE_POLICY_SERVICE;
import static android.content.Context.STATUS_BAR_SERVICE;
import static android.os.UserHandle.USER_ALL;
+import static android.os.UserHandle.USER_CURRENT;
import static android.provider.Settings.Secure.LOCK_TO_APP_EXIT_LOCKED;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
@@ -320,9 +321,10 @@ public class LockTaskController {
}
getLockTaskNotify().show(false);
try {
- boolean shouldLockKeyguard = Settings.Secure.getInt(
+ boolean shouldLockKeyguard = Settings.Secure.getIntForUser(
mContext.getContentResolver(),
- LOCK_TO_APP_EXIT_LOCKED) != 0;
+ LOCK_TO_APP_EXIT_LOCKED,
+ USER_CURRENT) != 0;
if (mLockTaskModeState == LOCK_TASK_MODE_PINNED && shouldLockKeyguard) {
mWindowManager.lockNow(null);
mWindowManager.dismissKeyguard(null /* callback */);
diff --git a/services/core/java/com/android/server/am/PinnedActivityStack.java b/services/core/java/com/android/server/am/PinnedActivityStack.java
index a1b95f9de05a..86ee3f4ba215 100644
--- a/services/core/java/com/android/server/am/PinnedActivityStack.java
+++ b/services/core/java/com/android/server/am/PinnedActivityStack.java
@@ -92,15 +92,16 @@ class PinnedActivityStack extends ActivityStack<PinnedStackWindowController>
return mWindowContainerController.deferScheduleMultiWindowModeChanged();
}
- public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds) {
+ public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
+ boolean forceUpdate) {
// It is guaranteed that the activities requiring the update will be in the pinned stack at
// this point (either reparented before the animation into PiP, or before reparenting after
// the animation out of PiP)
synchronized(this) {
ArrayList<TaskRecord> tasks = getAllTasks();
for (int i = 0; i < tasks.size(); i++ ) {
- mStackSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(tasks.get(i),
- targetStackBounds, true /* immediate */);
+ mStackSupervisor.updatePictureInPictureMode(tasks.get(i), targetStackBounds,
+ forceUpdate);
}
}
}
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index a6ebac44062e..365c5b1d005c 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -193,10 +193,6 @@ class RecentTasks extends ArrayList<TaskRecord> {
return mTaskPersister.getTaskDescriptionIcon(path);
}
- Bitmap getImageFromWriteQueue(String path) {
- return mTaskPersister.getImageFromWriteQueue(path);
- }
-
void saveImage(Bitmap image, String path) {
mTaskPersister.saveImage(image, path);
}
@@ -651,9 +647,6 @@ class RecentTasks extends ArrayList<TaskRecord> {
if (task.userId != tr.userId) {
continue;
}
- if (i > MAX_RECENT_BITMAPS) {
- tr.freeLastThumbnail();
- }
final Intent trIntent = tr.intent;
final boolean sameAffinity =
task.affinity != null && task.affinity.equals(tr.affinity);
@@ -706,7 +699,6 @@ class RecentTasks extends ArrayList<TaskRecord> {
// Either task and tr are the same or, their affinities match or their intents match
// and neither of them is a document, or they are documents using the same activity
// and their maxRecents has been reached.
- tr.disposeThumbnail();
remove(i);
if (task != tr) {
tr.removedFromRecents();
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index c7e600138e19..5c0d587a1202 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -16,6 +16,58 @@
package com.android.server.am;
+import static android.app.ActivityManager.RESIZE_MODE_FORCED;
+import static android.app.ActivityManager.RESIZE_MODE_SYSTEM;
+import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
+import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
+import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_ADD_REMOVE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityRecord.STARTING_WINDOW_SHOWN;
+import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING;
+import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING_TO_TOP;
+import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY;
+import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
+
+import static java.lang.Integer.MAX_VALUE;
+
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.Activity;
@@ -23,11 +75,10 @@ import android.app.ActivityManager;
import android.app.ActivityManager.StackId;
import android.app.ActivityManager.TaskDescription;
import android.app.ActivityManager.TaskSnapshot;
-import android.app.ActivityManager.TaskThumbnail;
-import android.app.ActivityManager.TaskThumbnailInfo;
import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.app.IActivityManager;
+import android.app.WindowConfiguration;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -35,11 +86,8 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
-import android.graphics.Bitmap;
-import android.graphics.Point;
import android.graphics.Rect;
import android.os.Debug;
-import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.Trace;
import android.os.UserHandle;
@@ -51,7 +99,6 @@ import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.util.XmlUtils;
-
import com.android.server.wm.AppWindowContainerController;
import com.android.server.wm.ConfigurationContainer;
import com.android.server.wm.StackWindowController;
@@ -63,7 +110,6 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
-import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -71,58 +117,6 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Objects;
-import static android.app.ActivityManager.RESIZE_MODE_FORCED;
-import static android.app.ActivityManager.RESIZE_MODE_SYSTEM;
-import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.HOME_STACK_ID;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
-import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
-import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
-import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
-import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
-import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
-import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_ADD_REMOVE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.ASSISTANT_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.STARTING_WINDOW_SHOWN;
-import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING;
-import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING_TO_TOP;
-import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY;
-import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
-
-import static java.lang.Integer.MAX_VALUE;
-
class TaskRecord extends ConfigurationContainer implements TaskWindowContainerListener {
private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
@@ -145,6 +139,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
private static final String ATTR_USERID = "user_id";
private static final String ATTR_USER_SETUP_COMPLETE = "user_setup_complete";
private static final String ATTR_EFFECTIVE_UID = "effective_uid";
+ @Deprecated
private static final String ATTR_TASKTYPE = "task_type";
private static final String ATTR_FIRSTACTIVETIME = "first_active_time";
private static final String ATTR_LASTACTIVETIME = "last_active_time";
@@ -258,9 +253,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
/** Current stack. Setter must always be used to update the value. */
private ActivityStack mStack;
- /** Takes on same set of values as ActivityRecord.mActivityType */
- int taskType;
-
/** Takes on same value as first root activity */
boolean isPersistable = false;
int maxRecents;
@@ -270,10 +262,11 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
* (positive) or back (negative). Absolute value indicates time. */
long mLastTimeMoved = System.currentTimeMillis();
- /** Indication of what to run next when task exits. Use ActivityRecord types.
- * ActivityRecord.APPLICATION_ACTIVITY_TYPE indicates to resume the task below this one in the
- * task stack. */
- private int mTaskToReturnTo = APPLICATION_ACTIVITY_TYPE;
+ /** Indication of what to run next when task exits. */
+ // TODO: Shouldn't be needed if we have things in visual order. I.e. we stop using stacks or
+ // have a stack per standard application type...
+ /*@WindowConfiguration.ActivityType*/
+ private int mTaskToReturnTo = ACTIVITY_TYPE_STANDARD;
/** If original intent did not allow relinquishing task identity, save that information */
private boolean mNeverRelinquishIdentity = true;
@@ -282,10 +275,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
// do not want to delete the stack when the task goes empty.
private boolean mReuseTask = false;
- private Bitmap mLastThumbnail; // Last thumbnail captured for this item.
- private final File mLastThumbnailFile; // File containing last thumbnail.
private final String mFilename;
- private TaskThumbnailInfo mLastThumbnailInfo;
CharSequence lastDescription; // Last description captured for this item.
int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent.
@@ -329,13 +319,11 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
private TaskWindowContainerController mWindowContainerController;
TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
- IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor, int type) {
+ IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
mService = service;
mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
TaskPersister.IMAGE_EXTENSION;
userId = UserHandle.getUserId(info.applicationInfo.uid);
- mLastThumbnailFile = new File(TaskPersister.getUserImagesDir(userId), mFilename);
- mLastThumbnailInfo = new TaskThumbnailInfo();
taskId = _taskId;
mAffiliatedTaskId = _taskId;
voiceSession = _voiceSession;
@@ -344,7 +332,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
mActivities = new ArrayList<>();
mCallingUid = info.applicationInfo.uid;
mCallingPackage = info.packageName;
- taskType = type;
setIntent(_intent, info);
setMinDimensions(info);
touchActiveTime();
@@ -352,13 +339,11 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
}
TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
- TaskDescription _taskDescription, TaskThumbnailInfo thumbnailInfo) {
+ TaskDescription _taskDescription) {
mService = service;
mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
TaskPersister.IMAGE_EXTENSION;
userId = UserHandle.getUserId(info.applicationInfo.uid);
- mLastThumbnailFile = new File(TaskPersister.getUserImagesDir(userId), mFilename);
- mLastThumbnailInfo = thumbnailInfo;
taskId = _taskId;
mAffiliatedTaskId = _taskId;
voiceSession = null;
@@ -375,8 +360,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
maxRecents = Math.min(Math.max(info.maxRecents, 1),
ActivityManager.getMaxAppRecentsLimitStatic());
- taskType = APPLICATION_ACTIVITY_TYPE;
- mTaskToReturnTo = HOME_ACTIVITY_TYPE;
+ mTaskToReturnTo = ACTIVITY_TYPE_HOME;
lastTaskDescription = _taskDescription;
touchActiveTime();
mService.mTaskChangeNotificationController.notifyTaskCreated(_taskId, realActivity);
@@ -385,20 +369,17 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
private TaskRecord(ActivityManagerService service, int _taskId, Intent _intent,
Intent _affinityIntent, String _affinity, String _rootAffinity,
ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
- boolean _autoRemoveRecents, boolean _askedCompatMode, int _taskType, int _userId,
+ boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId,
int _effectiveUid, String _lastDescription, ArrayList<ActivityRecord> activities,
long _firstActiveTime, long _lastActiveTime, long lastTimeMoved,
boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription,
- TaskThumbnailInfo lastThumbnailInfo, int taskAffiliation, int prevTaskId,
- int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
- int resizeMode, boolean supportsPictureInPicture, boolean privileged,
- boolean _realActivitySuspended, boolean userSetupComplete, int minWidth,
- int minHeight) {
+ int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor,
+ int callingUid, String callingPackage, int resizeMode, boolean supportsPictureInPicture,
+ boolean privileged, boolean _realActivitySuspended, boolean userSetupComplete,
+ int minWidth, int minHeight) {
mService = service;
mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
TaskPersister.IMAGE_EXTENSION;
- mLastThumbnailFile = new File(TaskPersister.getUserImagesDir(_userId), mFilename);
- mLastThumbnailInfo = lastThumbnailInfo;
taskId = _taskId;
intent = _intent;
affinityIntent = _affinityIntent;
@@ -413,8 +394,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
isAvailable = true;
autoRemoveRecents = _autoRemoveRecents;
askedCompatMode = _askedCompatMode;
- taskType = _taskType;
- mTaskToReturnTo = HOME_ACTIVITY_TYPE;
+ mTaskToReturnTo = ACTIVITY_TYPE_HOME;
userId = _userId;
mUserSetupComplete = userSetupComplete;
effectiveUid = _effectiveUid;
@@ -453,8 +433,8 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
final Configuration overrideConfig = getOverrideConfiguration();
setWindowContainerController(new TaskWindowContainerController(taskId, this,
getStack().getWindowContainerController(), userId, bounds, overrideConfig,
- mResizeMode, mSupportsPictureInPicture, isHomeTask(), onTop, showForAllUsers,
- lastTaskDescription));
+ mResizeMode, mSupportsPictureInPicture, onTop,
+ showForAllUsers, lastTaskDescription));
}
/**
@@ -907,16 +887,16 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
return this.intent.filterEquals(intent);
}
- void setTaskToReturnTo(int taskToReturnTo) {
- mTaskToReturnTo = (taskToReturnTo == RECENTS_ACTIVITY_TYPE)
- ? HOME_ACTIVITY_TYPE : taskToReturnTo;
+ void setTaskToReturnTo(/*@WindowConfiguration.ActivityType*/ int taskToReturnTo) {
+ mTaskToReturnTo = taskToReturnTo == ACTIVITY_TYPE_RECENTS
+ ? ACTIVITY_TYPE_HOME : taskToReturnTo;
}
void setTaskToReturnTo(ActivityRecord source) {
- if (source.isRecentsActivity()) {
- setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);
- } else if (source.isAssistantActivity()) {
- setTaskToReturnTo(ASSISTANT_ACTIVITY_TYPE);
+ if (source.isActivityTypeRecents()) {
+ setTaskToReturnTo(ACTIVITY_TYPE_RECENTS);
+ } else if (source.isActivityTypeAssistant()) {
+ setTaskToReturnTo(ACTIVITY_TYPE_ASSISTANT);
}
}
@@ -924,6 +904,14 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
return mTaskToReturnTo;
}
+ boolean returnsToHomeTask() {
+ return mTaskToReturnTo == ACTIVITY_TYPE_HOME;
+ }
+
+ boolean returnsToStandardTask() {
+ return mTaskToReturnTo == ACTIVITY_TYPE_STANDARD;
+ }
+
void setPrevAffiliate(TaskRecord prevAffiliate) {
mPrevAffiliate = prevAffiliate;
mPrevAffiliateTaskId = prevAffiliate == null ? INVALID_TASK_ID : prevAffiliate.taskId;
@@ -991,7 +979,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
}
void removedFromRecents() {
- disposeThumbnail();
closeRecentsChain();
if (inRecents) {
inRecents = false;
@@ -1025,89 +1012,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
setNextAffiliate(null);
}
- /**
- * Sets the last thumbnail with the current task bounds and the system orientation.
- * @return whether the thumbnail was set
- */
- boolean setLastThumbnailLocked(Bitmap thumbnail) {
- int taskWidth = 0;
- int taskHeight = 0;
- if (mBounds != null) {
- // Non-fullscreen tasks
- taskWidth = mBounds.width();
- taskHeight = mBounds.height();
- } else if (mStack != null) {
- // Fullscreen tasks
- final Point displaySize = new Point();
- mStack.getDisplaySize(displaySize);
- taskWidth = displaySize.x;
- taskHeight = displaySize.y;
- } else {
- Slog.e(TAG, "setLastThumbnailLocked() called on Task without stack");
- }
- // We need to provide the current orientation of the display on which this task resides,
- // not the orientation of the task.
- final int orientation = getStack().getDisplay().getConfiguration().orientation;
- return setLastThumbnailLocked(thumbnail, taskWidth, taskHeight, orientation);
- }
-
- /**
- * Sets the last thumbnail with the current task bounds.
- * @return whether the thumbnail was set
- */
- private boolean setLastThumbnailLocked(Bitmap thumbnail, int taskWidth, int taskHeight,
- int screenOrientation) {
- if (mLastThumbnail != thumbnail) {
- mLastThumbnail = thumbnail;
- mLastThumbnailInfo.taskWidth = taskWidth;
- mLastThumbnailInfo.taskHeight = taskHeight;
- mLastThumbnailInfo.screenOrientation = screenOrientation;
- if (thumbnail == null) {
- if (mLastThumbnailFile != null) {
- mLastThumbnailFile.delete();
- }
- } else {
- mService.mRecentTasks.saveImage(thumbnail, mLastThumbnailFile.getAbsolutePath());
- }
- return true;
- }
- return false;
- }
-
- void getLastThumbnail(TaskThumbnail thumbs) {
- thumbs.mainThumbnail = mLastThumbnail;
- thumbs.thumbnailInfo = mLastThumbnailInfo;
- thumbs.thumbnailFileDescriptor = null;
- if (mLastThumbnail == null) {
- thumbs.mainThumbnail = mService.mRecentTasks.getImageFromWriteQueue(
- mLastThumbnailFile.getAbsolutePath());
- }
- // Only load the thumbnail file if we don't have a thumbnail
- if (thumbs.mainThumbnail == null && mLastThumbnailFile.exists()) {
- try {
- thumbs.thumbnailFileDescriptor = ParcelFileDescriptor.open(mLastThumbnailFile,
- ParcelFileDescriptor.MODE_READ_ONLY);
- } catch (IOException e) {
- }
- }
- }
-
- /**
- * Removes in-memory thumbnail data when the max number of in-memory task thumbnails is reached.
- */
- void freeLastThumbnail() {
- mLastThumbnail = null;
- }
-
- /**
- * Removes all associated thumbnail data when a task is removed or pruned from recents.
- */
- void disposeThumbnail() {
- mLastThumbnailInfo.reset();
- mLastThumbnail = null;
- lastDescription = null;
- }
-
/** Returns the intent for the root activity for this task */
Intent getBaseIntent() {
return intent != null ? intent : affinityIntent;
@@ -1237,6 +1141,16 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
addActivityAtIndex(mActivities.size(), r);
}
+ @Override
+ /*@WindowConfiguration.ActivityType*/
+ public int getActivityType() {
+ final int applicationType = super.getActivityType();
+ if (applicationType != ACTIVITY_TYPE_UNDEFINED || mActivities.isEmpty()) {
+ return applicationType;
+ }
+ return mActivities.get(0).getActivityType();
+ }
+
/**
* Adds an activity {@param r} at the given {@param index}. The activity {@param r} must either
* be in the current task or unparented to any task.
@@ -1257,7 +1171,17 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
}
// Only set this based on the first activity
if (mActivities.isEmpty()) {
- taskType = r.mActivityType;
+ // TODO: propagating this change to the WM side...Should probably be done by having
+ // ConfigurationContainer change listener that the WindowContainerController registers
+ // for.
+ if (r.getActivityType() == ACTIVITY_TYPE_UNDEFINED) {
+ // Normally non-standard activity type for the activity record will be set when the
+ // object is created, however we delay setting the standard application type until
+ // this point so that the task can set the type for additional activities added in
+ // the else condition below.
+ r.setActivityType(ACTIVITY_TYPE_STANDARD);
+ }
+ setActivityType(r.getActivityType());
isPersistable = r.isPersistable();
mCallingUid = r.launchedFromUid;
mCallingPackage = r.launchedFromPackage;
@@ -1266,7 +1190,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
ActivityManager.getMaxAppRecentsLimitStatic());
} else {
// Otherwise make all added activities match this one.
- r.mActivityType = taskType;
+ r.setActivityType(getActivityType());
}
final int size = mActivities.size();
@@ -1468,19 +1392,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
return null;
}
- TaskThumbnail getTaskThumbnailLocked() {
- if (mStack != null) {
- final ActivityRecord resumedActivity = mStack.mResumedActivity;
- if (resumedActivity != null && resumedActivity.getTask() == this) {
- final Bitmap thumbnail = resumedActivity.screenshotActivityLocked();
- setLastThumbnailLocked(thumbnail);
- }
- }
- final TaskThumbnail taskThumbnail = new TaskThumbnail();
- getLastThumbnail(taskThumbnail);
- return taskThumbnail;
- }
-
void removeTaskActivitiesLocked(boolean pauseImmediately) {
// Just remove the entire task.
performClearTaskAtIndexLocked(0, pauseImmediately);
@@ -1544,28 +1455,12 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
return false;
}
- boolean isHomeTask() {
- return taskType == HOME_ACTIVITY_TYPE;
- }
-
- boolean isRecentsTask() {
- return taskType == RECENTS_ACTIVITY_TYPE;
- }
-
- boolean isAssistantTask() {
- return taskType == ASSISTANT_ACTIVITY_TYPE;
- }
-
- boolean isApplicationTask() {
- return taskType == APPLICATION_ACTIVITY_TYPE;
- }
-
boolean isOverHomeStack() {
- return mTaskToReturnTo == HOME_ACTIVITY_TYPE;
+ return mTaskToReturnTo == ACTIVITY_TYPE_HOME;
}
boolean isOverAssistantStack() {
- return mTaskToReturnTo == ASSISTANT_ACTIVITY_TYPE;
+ return mTaskToReturnTo == ACTIVITY_TYPE_ASSISTANT;
}
private boolean isResizeable(boolean checkSupportsPip) {
@@ -1759,7 +1654,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
out.attribute(null, ATTR_USERID, String.valueOf(userId));
out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete));
out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
- out.attribute(null, ATTR_TASKTYPE, String.valueOf(taskType));
out.attribute(null, ATTR_FIRSTACTIVETIME, String.valueOf(firstActiveTime));
out.attribute(null, ATTR_LASTACTIVETIME, String.valueOf(lastActiveTime));
out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
@@ -1770,7 +1664,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
if (lastTaskDescription != null) {
lastTaskDescription.saveToXml(out);
}
- mLastThumbnailInfo.saveToXml(out);
out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
@@ -1830,7 +1723,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
boolean rootHasReset = false;
boolean autoRemoveRecents = false;
boolean askedCompatMode = false;
- int taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
+ int taskType = 0;
int userId = 0;
boolean userSetupComplete = true;
int effectiveUid = -1;
@@ -1842,7 +1735,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
int taskId = INVALID_TASK_ID;
final int outerDepth = in.getDepth();
TaskDescription taskDescription = new TaskDescription();
- TaskThumbnailInfo thumbnailInfo = new TaskThumbnailInfo();
int taskAffiliation = INVALID_TASK_ID;
int taskAffiliationColor = 0;
int prevTaskId = INVALID_TASK_ID;
@@ -1899,8 +1791,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
lastTimeOnTop = Long.parseLong(attrValue);
} else if (ATTR_NEVERRELINQUISH.equals(attrName)) {
neverRelinquishIdentity = Boolean.parseBoolean(attrValue);
- } else if (attrName.startsWith(TaskThumbnailInfo.ATTR_TASK_THUMBNAILINFO_PREFIX)) {
- thumbnailInfo.restoreFromXml(attrName, attrValue);
} else if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
taskDescription.restoreFromXml(attrName, attrValue);
} else if (ATTR_TASK_AFFILIATION.equals(attrName)) {
@@ -1988,7 +1878,7 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
// they are marked as RESIZE_MODE_RESIZEABLE to RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION
// since we didn't have that differentiation before version 1 and the system didn't
// resize home activities before then.
- if (taskType == HOME_ACTIVITY_TYPE && resizeMode == RESIZE_MODE_RESIZEABLE) {
+ if (taskType == 1 /* old home type */ && resizeMode == RESIZE_MODE_RESIZEABLE) {
resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
}
} else {
@@ -2004,12 +1894,11 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent,
affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset,
- autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription,
+ autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription,
activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
- taskDescription, thumbnailInfo, taskAffiliation, prevTaskId, nextTaskId,
- taskAffiliationColor, callingUid, callingPackage, resizeMode,
- supportsPictureInPicture, privileged, realActivitySuspended, userSetupComplete,
- minWidth, minHeight);
+ taskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor,
+ callingUid, callingPackage, resizeMode, supportsPictureInPicture, privileged,
+ realActivitySuspended, userSetupComplete, minWidth, minHeight);
task.updateOverrideConfiguration(bounds);
for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
@@ -2227,13 +2116,13 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
* The task will be moved (and stack focus changed) later if necessary.
*/
int getLaunchStackId() {
- if (isRecentsTask()) {
+ if (isActivityTypeRecents()) {
return RECENTS_STACK_ID;
}
- if (isHomeTask()) {
+ if (isActivityTypeHome()) {
return HOME_STACK_ID;
}
- if (isAssistantTask()) {
+ if (isActivityTypeAssistant()) {
return ASSISTANT_STACK_ID;
}
if (mBounds != null) {
@@ -2312,12 +2201,12 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
pw.print(prefix); pw.print("realActivity=");
pw.println(realActivity.flattenToShortString());
}
- if (autoRemoveRecents || isPersistable || taskType != 0 || mTaskToReturnTo != 0
- || numFullscreen != 0) {
+ if (autoRemoveRecents || isPersistable || !isActivityTypeStandard()
+ || mTaskToReturnTo != ACTIVITY_TYPE_STANDARD || numFullscreen != 0) {
pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents);
pw.print(" isPersistable="); pw.print(isPersistable);
pw.print(" numFullscreen="); pw.print(numFullscreen);
- pw.print(" taskType="); pw.print(taskType);
+ pw.print(" activityType="); pw.print(getActivityType());
pw.print(" mTaskToReturnTo="); pw.println(mTaskToReturnTo);
}
if (rootWasReset || mNeverRelinquishIdentity || mReuseTask
@@ -2353,8 +2242,6 @@ class TaskRecord extends ConfigurationContainer implements TaskWindowContainerLi
pw.print(" inRecents="); pw.print(inRecents);
pw.print(" isAvailable="); pw.println(isAvailable);
}
- pw.print(prefix); pw.print("lastThumbnail="); pw.print(mLastThumbnail);
- pw.print(" lastThumbnailFile="); pw.println(mLastThumbnailFile);
if (lastDescription != null) {
pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription);
}
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 29445673dfff..db6bb7d8e653 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -36,6 +36,7 @@ import static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_MS
import static com.android.server.am.ActivityManagerService.SYSTEM_USER_CURRENT_MSG;
import static com.android.server.am.ActivityManagerService.SYSTEM_USER_START_MSG;
import static com.android.server.am.ActivityManagerService.SYSTEM_USER_UNLOCK_MSG;
+import static com.android.server.am.ActivityManagerService.USER_SWITCH_CALLBACKS_TIMEOUT_MSG;
import static com.android.server.am.ActivityManagerService.USER_SWITCH_TIMEOUT_MSG;
import static com.android.server.am.UserState.STATE_BOOTING;
import static com.android.server.am.UserState.STATE_RUNNING_LOCKED;
@@ -115,7 +116,12 @@ class UserController {
// Amount of time we wait for observers to handle a user switch before
// giving up on them and unfreezing the screen.
- static final int USER_SWITCH_TIMEOUT = 3 * 1000;
+ static final int USER_SWITCH_TIMEOUT_MS = 3 * 1000;
+
+ // If a callback wasn't called within USER_SWITCH_CALLBACKS_TIMEOUT_MS after
+ // USER_SWITCH_TIMEOUT_MS, an error is reported. Usually it indicates a problem in the observer
+ // when it never calls back.
+ private static final int USER_SWITCH_CALLBACKS_TIMEOUT_MS = 5 * 1000;
private final Object mLock;
private final Injector mInjector;
@@ -171,6 +177,12 @@ class UserController {
@GuardedBy("mLock")
private volatile ArraySet<String> mCurWaitingUserSwitchCallbacks;
+ /**
+ * Callbacks that are still active after {@link #USER_SWITCH_TIMEOUT_MS}
+ */
+ @GuardedBy("mLock")
+ private ArraySet<String> mTimeoutUserSwitchCallbacks;
+
private final LockPatternUtils mLockPatternUtils;
UserController(ActivityManagerService service) {
@@ -924,7 +936,7 @@ class UserController {
mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG,
oldUserId, userId, uss));
mHandler.sendMessageDelayed(mHandler.obtainMessage(USER_SWITCH_TIMEOUT_MSG,
- oldUserId, userId, uss), USER_SWITCH_TIMEOUT);
+ oldUserId, userId, uss), USER_SWITCH_TIMEOUT_MS);
}
if (needStart) {
@@ -1130,8 +1142,23 @@ class UserController {
void timeoutUserSwitch(UserState uss, int oldUserId, int newUserId) {
synchronized (mLock) {
- Slog.wtf(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId);
+ Slog.e(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId);
+ mTimeoutUserSwitchCallbacks = mCurWaitingUserSwitchCallbacks;
+ mHandler.removeMessages(USER_SWITCH_CALLBACKS_TIMEOUT_MSG);
sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
+ // Report observers that never called back (USER_SWITCH_CALLBACKS_TIMEOUT)
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(USER_SWITCH_CALLBACKS_TIMEOUT_MSG,
+ oldUserId, newUserId), USER_SWITCH_CALLBACKS_TIMEOUT_MS);
+ }
+ }
+
+ void timeoutUserSwitchCallbacks(int oldUserId, int newUserId) {
+ synchronized (mLock) {
+ if (mTimeoutUserSwitchCallbacks != null && !mTimeoutUserSwitchCallbacks.isEmpty()) {
+ Slog.wtf(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId
+ + ". Observers that didn't respond: " + mTimeoutUserSwitchCallbacks);
+ mTimeoutUserSwitchCallbacks = null;
+ }
}
}
@@ -1158,18 +1185,16 @@ class UserController {
public void sendResult(Bundle data) throws RemoteException {
synchronized (mLock) {
long delay = SystemClock.elapsedRealtime() - dispatchStartedTime;
- if (delay > USER_SWITCH_TIMEOUT) {
- Slog.wtf(TAG, "User switch timeout: observer " + name
+ if (delay > USER_SWITCH_TIMEOUT_MS) {
+ Slog.e(TAG, "User switch timeout: observer " + name
+ " sent result after " + delay + " ms");
}
- // Early return if this session is no longer valid
- if (curWaitingUserSwitchCallbacks
- != mCurWaitingUserSwitchCallbacks) {
- return;
- }
curWaitingUserSwitchCallbacks.remove(name);
- // Continue switching if all callbacks have been notified
- if (waitingCallbacksCount.decrementAndGet() == 0) {
+ // Continue switching if all callbacks have been notified and
+ // user switching session is still valid
+ if (waitingCallbacksCount.decrementAndGet() == 0
+ && (curWaitingUserSwitchCallbacks
+ == mCurWaitingUserSwitchCallbacks)) {
sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
}
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index f88f779b1676..91b15912fcb5 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -801,12 +801,23 @@ public class AudioService extends IAudioService.Stub
public void systemReady() {
sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
0, 0, null, 0);
- try {
- ActivityManager.getService().registerUidObserver(mUidObserver,
- ActivityManager.UID_OBSERVER_CACHED | ActivityManager.UID_OBSERVER_GONE,
- ActivityManager.PROCESS_STATE_UNKNOWN, null);
- } catch (RemoteException e) {
- // ignored; both services live in system_server
+ if (false) {
+ // This is turned off for now, because it is racy and thus causes apps to break.
+ // Currently banning a uid means that if an app tries to start playing an audio
+ // stream, that will be preventing, and unbanning it will not allow that stream
+ // to resume. However these changes in uid state are racy with what the app is doing,
+ // so that after taking a process out of the cached state we can't guarantee that
+ // we will unban the uid before the app actually tries to start playing audio.
+ // (To do that, the activity manager would need to wait until it knows for sure
+ // that the ban has been removed, before telling the app to do whatever it is
+ // supposed to do that caused it to go out of the cached state.)
+ try {
+ ActivityManager.getService().registerUidObserver(mUidObserver,
+ ActivityManager.UID_OBSERVER_CACHED | ActivityManager.UID_OBSERVER_GONE,
+ ActivityManager.PROCESS_STATE_UNKNOWN, null);
+ } catch (RemoteException e) {
+ // ignored; both services live in system_server
+ }
}
}
@@ -6973,6 +6984,10 @@ public class AudioService extends IAudioService.Stub
mPlaybackMonitor.playerEvent(piid, event, Binder.getCallingUid());
}
+ public void playerHasOpPlayAudio(int piid, boolean hasOpPlayAudio) {
+ mPlaybackMonitor.playerHasOpPlayAudio(piid, hasOpPlayAudio, Binder.getCallingUid());
+ }
+
public void releasePlayer(int piid) {
mPlaybackMonitor.releasePlayer(piid, Binder.getCallingUid());
}
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index c075cdceb685..3e5eed320ccd 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -214,6 +214,11 @@ public final class PlaybackActivityMonitor
}
}
+ public void playerHasOpPlayAudio(int piid, boolean hasOpPlayAudio, int binderUid) {
+ // no check on UID yet because this is only for logging at the moment
+ mEventLogger.log(new PlayerOpPlayAudioEvent(piid, hasOpPlayAudio, binderUid));
+ }
+
public void releasePlayer(int piid, int binderUid) {
if (DEBUG) { Log.v(TAG, "releasePlayer() for piid=" + piid); }
synchronized(mPlayerLock) {
@@ -702,8 +707,28 @@ public final class PlaybackActivityMonitor
@Override
public String eventToString() {
- return new String("player piid:" + mPlayerIId + " state:"
- + AudioPlaybackConfiguration.toLogFriendlyPlayerState(mState));
+ return new StringBuilder("player piid:").append(mPlayerIId).append(" state:")
+ .append(AudioPlaybackConfiguration.toLogFriendlyPlayerState(mState)).toString();
+ }
+ }
+
+ private final static class PlayerOpPlayAudioEvent extends AudioEventLogger.Event {
+ // only keeping the player interface ID as it uniquely identifies the player in the event
+ final int mPlayerIId;
+ final boolean mHasOp;
+ final int mUid;
+
+ PlayerOpPlayAudioEvent(int piid, boolean hasOp, int uid) {
+ mPlayerIId = piid;
+ mHasOp = hasOp;
+ mUid = uid;
+ }
+
+ @Override
+ public String eventToString() {
+ return new StringBuilder("player piid:").append(mPlayerIId)
+ .append(" has OP_PLAY_AUDIO:").append(mHasOp)
+ .append(" in uid:").append(mUid).toString();
}
}
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 10c8b8b1e0aa..f8d23d4c8d51 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -20,21 +20,22 @@ import android.net.InterfaceConfiguration;
import android.net.ConnectivityManager;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.NetworkAgent;
import android.net.RouteInfo;
+import android.os.Handler;
+import android.os.Message;
import android.os.INetworkManagementService;
import android.os.RemoteException;
import android.util.Slog;
-import com.android.internal.util.ArrayUtils;
import com.android.server.net.BaseNetworkObserver;
+import com.android.internal.util.ArrayUtils;
import java.net.Inet4Address;
import java.util.Objects;
/**
- * Class to manage a 464xlat CLAT daemon. Nat464Xlat is not thread safe and should be manipulated
- * from a consistent and unique thread context. It is the responsability of ConnectivityService to
- * call into this class from its own Handler thread.
+ * Class to manage a 464xlat CLAT daemon.
*
* @hide
*/
@@ -54,6 +55,9 @@ public class Nat464Xlat extends BaseNetworkObserver {
private final INetworkManagementService mNMService;
+ // ConnectivityService Handler for LinkProperties updates.
+ private final Handler mHandler;
+
// The network we're running on, and its type.
private final NetworkAgentInfo mNetwork;
@@ -63,12 +67,16 @@ public class Nat464Xlat extends BaseNetworkObserver {
RUNNING; // start() called, and the stacked iface is known to be up.
}
+ // Once mIface is non-null and isStarted() is true, methods called by ConnectivityService on
+ // its handler thread must not modify any internal state variables; they are only updated by the
+ // interface observers, called on the notification threads.
private String mBaseIface;
private String mIface;
- private State mState = State.IDLE;
+ private volatile State mState = State.IDLE;
- public Nat464Xlat(INetworkManagementService nmService, NetworkAgentInfo nai) {
+ public Nat464Xlat(INetworkManagementService nmService, Handler handler, NetworkAgentInfo nai) {
mNMService = nmService;
+ mHandler = handler;
mNetwork = nai;
}
@@ -97,13 +105,6 @@ public class Nat464Xlat extends BaseNetworkObserver {
}
/**
- * @return true if clatd has been started but the stacked interface is not yet up.
- */
- public boolean isStarting() {
- return mState == State.STARTING;
- }
-
- /**
* @return true if clatd has been started and the stacked interface is up.
*/
public boolean isRunning() {
@@ -120,7 +121,7 @@ public class Nat464Xlat extends BaseNetworkObserver {
}
/**
- * Clears internal state.
+ * Clears internal state. Must not be called by ConnectivityService.
*/
private void enterIdleState() {
mIface = null;
@@ -129,7 +130,7 @@ public class Nat464Xlat extends BaseNetworkObserver {
}
/**
- * Starts the clat daemon.
+ * Starts the clat daemon. Called by ConnectivityService on the handler thread.
*/
public void start() {
if (isStarted()) {
@@ -166,7 +167,7 @@ public class Nat464Xlat extends BaseNetworkObserver {
}
/**
- * Stops the clat daemon.
+ * Stops the clat daemon. Called by ConnectivityService on the handler thread.
*/
public void stop() {
if (!isStarted()) {
@@ -180,8 +181,15 @@ public class Nat464Xlat extends BaseNetworkObserver {
} catch(RemoteException|IllegalStateException e) {
Slog.e(TAG, "Error stopping clatd on " + mBaseIface, e);
}
- // When clatd stops and its interface is deleted, handleInterfaceRemoved() will trigger
- // ConnectivityService#handleUpdateLinkProperties and call enterIdleState().
+ // When clatd stops and its interface is deleted, interfaceRemoved() will notify
+ // ConnectivityService and call enterIdleState().
+ }
+
+ private void updateConnectivityService(LinkProperties lp) {
+ Message msg = mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED, lp);
+ msg.replyTo = mNetwork.messenger;
+ Slog.i(TAG, "sending message to ConnectivityService: " + msg);
+ msg.sendToTarget();
}
/**
@@ -249,15 +257,19 @@ public class Nat464Xlat extends BaseNetworkObserver {
}
/**
- * Adds stacked link on base link and transitions to RUNNING state.
+ * Adds stacked link on base link and transitions to Running state
+ * This is called by the InterfaceObserver on its own thread, so can race with stop().
*/
- private void handleInterfaceLinkStateChanged(String iface, boolean up) {
- if (!isStarting() || !up || !Objects.equals(mIface, iface)) {
+ @Override
+ public void interfaceLinkStateChanged(String iface, boolean up) {
+ if (!isStarted() || !up || !Objects.equals(mIface, iface)) {
+ return;
+ }
+ if (isRunning()) {
return;
}
LinkAddress clatAddress = getLinkAddress(iface);
if (clatAddress == null) {
- Slog.e(TAG, "cladAddress was null for stacked iface " + iface);
return;
}
mState = State.RUNNING;
@@ -267,14 +279,15 @@ public class Nat464Xlat extends BaseNetworkObserver {
maybeSetIpv6NdOffload(mBaseIface, false);
LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
lp.addStackedLink(makeLinkProperties(clatAddress));
- mNetwork.connService.handleUpdateLinkProperties(mNetwork, lp);
+ updateConnectivityService(lp);
}
- /**
- * Removes stacked link on base link and transitions to IDLE state.
- */
- private void handleInterfaceRemoved(String iface) {
- if (!isRunning() || !Objects.equals(mIface, iface)) {
+ @Override
+ public void interfaceRemoved(String iface) {
+ if (!isStarted() || !Objects.equals(mIface, iface)) {
+ return;
+ }
+ if (!isRunning()) {
return;
}
@@ -282,28 +295,21 @@ public class Nat464Xlat extends BaseNetworkObserver {
// The interface going away likely means clatd has crashed. Ask netd to stop it,
// because otherwise when we try to start it again on the same base interface netd
// will complain that it's already started.
+ //
+ // Note that this method can be called by the interface observer at the same time
+ // that ConnectivityService calls stop(). In this case, the second call to
+ // stopClatd() will just throw IllegalStateException, which we'll ignore.
try {
mNMService.unregisterObserver(this);
- // TODO: add STOPPING state to avoid calling stopClatd twice.
mNMService.stopClatd(mBaseIface);
- } catch(RemoteException|IllegalStateException e) {
- Slog.e(TAG, "Error stopping clatd on " + mBaseIface, e);
+ } catch (RemoteException|IllegalStateException e) {
+ // Well, we tried.
}
maybeSetIpv6NdOffload(mBaseIface, true);
LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
lp.removeStackedLink(mIface);
enterIdleState();
- mNetwork.connService.handleUpdateLinkProperties(mNetwork, lp);
- }
-
- @Override
- public void interfaceLinkStateChanged(String iface, boolean up) {
- mNetwork.handler.post(() -> { handleInterfaceLinkStateChanged(iface, up); });
- }
-
- @Override
- public void interfaceRemoved(String iface) {
- mNetwork.handler.post(() -> { handleInterfaceRemoved(iface); });
+ updateConnectivityService(lp);
}
@Override
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 7c4ef0f0f3b9..872923a03256 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -27,9 +27,7 @@ import android.net.NetworkMisc;
import android.net.NetworkRequest;
import android.net.NetworkState;
import android.os.Handler;
-import android.os.INetworkManagementService;
import android.os.Messenger;
-import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
import android.util.SparseArray;
@@ -249,9 +247,9 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
private static final String TAG = ConnectivityService.class.getSimpleName();
private static final boolean VDBG = false;
- public final ConnectivityService connService;
+ private final ConnectivityService mConnService;
private final Context mContext;
- final Handler handler;
+ private final Handler mHandler;
public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
@@ -263,10 +261,10 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
linkProperties = lp;
networkCapabilities = nc;
currentScore = score;
- this.connService = connService;
+ mConnService = connService;
mContext = context;
- this.handler = handler;
- networkMonitor = connService.createNetworkMonitor(context, handler, this, defaultRequest);
+ mHandler = handler;
+ networkMonitor = mConnService.createNetworkMonitor(context, handler, this, defaultRequest);
networkMisc = misc;
}
@@ -432,7 +430,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
private boolean ignoreWifiUnvalidationPenalty() {
boolean isWifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) &&
networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
- boolean avoidBadWifi = connService.avoidBadWifi() || avoidUnvalidated;
+ boolean avoidBadWifi = mConnService.avoidBadWifi() || avoidUnvalidated;
return isWifi && !avoidBadWifi && everValidated;
}
@@ -516,8 +514,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
}
if (newExpiry > 0) {
- mLingerMessage = connService.makeWakeupMessage(
- mContext, handler,
+ mLingerMessage = mConnService.makeWakeupMessage(
+ mContext, mHandler,
"NETWORK_LINGER_COMPLETE." + network.netId,
EVENT_NETWORK_LINGER_COMPLETE, this);
mLingerMessage.schedule(newExpiry);
@@ -553,32 +551,6 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
for (LingerTimer timer : mLingerTimers) { pw.println(timer); }
}
- public void updateClat(INetworkManagementService netd) {
- if (Nat464Xlat.requiresClat(this)) {
- maybeStartClat(netd);
- } else {
- maybeStopClat();
- }
- }
-
- /** Ensure clat has started for this network. */
- public void maybeStartClat(INetworkManagementService netd) {
- if (clatd != null && clatd.isStarted()) {
- return;
- }
- clatd = new Nat464Xlat(netd, this);
- clatd.start();
- }
-
- /** Ensure clat has stopped for this network. */
- public void maybeStopClat() {
- if (clatd == null) {
- return;
- }
- clatd.stop();
- clatd = null;
- }
-
public String toString() {
return "NetworkAgentInfo{ ni{" + networkInfo + "} " +
"network{" + network + "} nethandle{" + network.getNetworkHandle() + "} " +
diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java
index b3cf57b3564a..aafc6317bfae 100644
--- a/services/core/java/com/android/server/display/NightDisplayService.java
+++ b/services/core/java/com/android/server/display/NightDisplayService.java
@@ -110,23 +110,7 @@ public final class NightDisplayService extends SystemService
private float[] mMatrixNight = new float[16];
- /**
- * These coefficients were generated by an LLS quadratic regression fitted to the
- * overdetermined system based on experimental readings (and subsequent conversion from xy
- * chromaticity coordinates to gamma-corrected RGB values): { (temperature, R, G, B) } ->
- * { (7304, 1.0, 1.0, 1.0), (4082, 1.0, 0.857, 0.719), (2850, 1.0, .754, .516),
- * (2596, 1.0, 0.722, 0.454) }. The 3x3 matrix is formatted like so:
- * <table>
- * <tr><td>R: a coefficient</td><td>G: a coefficient</td><td>B: a coefficient</td></tr>
- * <tr><td>R: b coefficient</td><td>G: b coefficient</td><td>B: b coefficient</td></tr>
- * <tr><td>R: y-intercept</td><td>G: y-intercept</td><td>B: y-intercept</td></tr>
- * </table>
- */
- private static final float[] mColorTempCoefficients = new float[] {
- 0.0f, -0.00000000962353339f, -0.0000000189359041f,
- 0.0f, 0.000153045476f, 0.000302412211f,
- 1.0f, 0.390782778f, -0.198650895f
- };
+ private final float[] mColorTempCoefficients = new float[9];
private int mCurrentUser = UserHandle.USER_NULL;
private ContentObserver mUserSetupObserver;
@@ -140,6 +124,12 @@ public final class NightDisplayService extends SystemService
public NightDisplayService(Context context) {
super(context);
mHandler = new Handler(Looper.getMainLooper());
+
+ final String[] coefficients = context.getResources().getStringArray(
+ com.android.internal.R.array.config_nightDisplayColorTemperatureCoefficients);
+ for (int i = 0; i < 9 && i < coefficients.length; i++) {
+ mColorTempCoefficients[i] = Float.parseFloat(coefficients[i]);
+ }
}
@Override
@@ -414,11 +404,11 @@ public final class NightDisplayService extends SystemService
final float squareTemperature = colorTemperature * colorTemperature;
final float red = squareTemperature * mColorTempCoefficients[0]
- + colorTemperature * mColorTempCoefficients[3] + mColorTempCoefficients[6];
- final float green = squareTemperature * mColorTempCoefficients[1]
- + colorTemperature * mColorTempCoefficients[4] + mColorTempCoefficients[7];
- final float blue = squareTemperature * mColorTempCoefficients[2]
- + colorTemperature * mColorTempCoefficients[5] + mColorTempCoefficients[8];
+ + colorTemperature * mColorTempCoefficients[1] + mColorTempCoefficients[2];
+ final float green = squareTemperature * mColorTempCoefficients[3]
+ + colorTemperature * mColorTempCoefficients[4] + mColorTempCoefficients[5];
+ final float blue = squareTemperature * mColorTempCoefficients[6]
+ + colorTemperature * mColorTempCoefficients[7] + mColorTempCoefficients[8];
outTemp[0] = red;
outTemp[5] = green;
outTemp[10] = blue;
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 79bed73a0ca0..c6998d6a108c 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -520,11 +520,12 @@ public final class JobSchedulerService extends com.android.server.SystemService
if (DEBUG) {
Slog.d(TAG, "Receieved: " + action);
}
+ final String pkgName = getPackageName(intent);
+ final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+
if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
// Purge the app's jobs if the whole package was just disabled. When this is
// the case the component name will be a bare package name.
- final String pkgName = getPackageName(intent);
- final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
if (pkgName != null && pkgUid != -1) {
final String[] changedComponents = intent.getStringArrayExtra(
Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
@@ -544,7 +545,8 @@ public final class JobSchedulerService extends com.android.server.SystemService
Slog.d(TAG, "Removing jobs for package " + pkgName
+ " in user " + userId);
}
- cancelJobsForUid(pkgUid, "app package state changed");
+ cancelJobsForPackageAndUid(pkgName, pkgUid,
+ "app disabled");
}
} catch (RemoteException|IllegalArgumentException e) {
/*
@@ -573,7 +575,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
if (DEBUG) {
Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
}
- cancelJobsForUid(uidRemoved, "app uninstalled");
+ cancelJobsForPackageAndUid(pkgName, uidRemoved, "app uninstalled");
}
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
@@ -584,8 +586,6 @@ public final class JobSchedulerService extends com.android.server.SystemService
} else if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
// Has this package scheduled any jobs, such that we will take action
// if it were to be force-stopped?
- final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
- final String pkgName = intent.getData().getSchemeSpecificPart();
if (pkgUid != -1) {
List<JobStatus> jobsForUid;
synchronized (mLock) {
@@ -604,13 +604,11 @@ public final class JobSchedulerService extends com.android.server.SystemService
}
} else if (Intent.ACTION_PACKAGE_RESTARTED.equals(action)) {
// possible force-stop
- final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
- final String pkgName = intent.getData().getSchemeSpecificPart();
if (pkgUid != -1) {
if (DEBUG) {
Slog.d(TAG, "Removing jobs for pkg " + pkgName + " at uid " + pkgUid);
}
- cancelJobsForPackageAndUid(pkgName, pkgUid);
+ cancelJobsForPackageAndUid(pkgName, pkgUid, "app force stopped");
}
}
}
@@ -790,13 +788,17 @@ public final class JobSchedulerService extends com.android.server.SystemService
}
}
- void cancelJobsForPackageAndUid(String pkgName, int uid) {
+ void cancelJobsForPackageAndUid(String pkgName, int uid, String reason) {
+ if ("android".equals(pkgName)) {
+ Slog.wtfStack(TAG, "Can't cancel all jobs for system package");
+ return;
+ }
synchronized (mLock) {
final List<JobStatus> jobsForUid = mJobs.getJobsByUid(uid);
for (int i = jobsForUid.size() - 1; i >= 0; i--) {
final JobStatus job = jobsForUid.get(i);
if (job.getSourcePackageName().equals(pkgName)) {
- cancelJobImplLocked(job, null, "app force stopped");
+ cancelJobImplLocked(job, null, reason);
}
}
}
@@ -811,8 +813,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
*/
public void cancelJobsForUid(int uid, String reason) {
if (uid == Process.SYSTEM_UID) {
- // This really shouldn't happen.
- Slog.wtfStack(TAG, "cancelJobsForUid() called for system uid");
+ Slog.wtfStack(TAG, "Can't cancel all jobs for system uid");
return;
}
synchronized (mLock) {
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 031bdd0ee39c..d3fd3a992a31 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -261,6 +261,13 @@ public final class JobServiceContext implements ServiceConnection {
return mRunningJob;
}
+ /**
+ * Used only for debugging. Will return <code>"&lt;null&gt;"</code> if there is no job running.
+ */
+ private String getRunningJobNameLocked() {
+ return mRunningJob != null ? mRunningJob.toShortString() : "<null>";
+ }
+
/** Called externally when a job that was scheduled for execution should be cancelled. */
void cancelExecutingJobLocked(int reason, String debugReason) {
doCancelLocked(reason, debugReason);
@@ -522,7 +529,7 @@ public final class JobServiceContext implements ServiceConnection {
/** Start the job on the service. */
private void handleServiceBoundLocked() {
if (DEBUG) {
- Slog.d(TAG, "handleServiceBound for " + mRunningJob.toShortString());
+ Slog.d(TAG, "handleServiceBound for " + getRunningJobNameLocked());
}
if (mVerb != VERB_BINDING) {
Slog.e(TAG, "Sending onStartJob for a job that isn't pending. "
@@ -639,36 +646,34 @@ public final class JobServiceContext implements ServiceConnection {
private void handleOpTimeoutLocked() {
switch (mVerb) {
case VERB_BINDING:
- Slog.w(TAG, "Time-out while trying to bind " + mRunningJob.toShortString() +
- ", dropping.");
+ Slog.w(TAG, "Time-out while trying to bind " + getRunningJobNameLocked()
+ + ", dropping.");
closeAndCleanupJobLocked(false /* needsReschedule */, "timed out while binding");
break;
case VERB_STARTING:
// Client unresponsive - wedged or failed to respond in time. We don't really
// know what happened so let's log it and notify the JobScheduler
// FINISHED/NO-RETRY.
- Slog.w(TAG, "No response from client for onStartJob " +
- mRunningJob != null ? mRunningJob.toShortString() : "<null>");
+ Slog.w(TAG, "No response from client for onStartJob "
+ + getRunningJobNameLocked());
closeAndCleanupJobLocked(false /* needsReschedule */, "timed out while starting");
break;
case VERB_STOPPING:
// At least we got somewhere, so fail but ask the JobScheduler to reschedule.
- Slog.w(TAG, "No response from client for onStopJob " +
- mRunningJob != null ? mRunningJob.toShortString() : "<null>");
+ Slog.w(TAG, "No response from client for onStopJob "
+ + getRunningJobNameLocked());
closeAndCleanupJobLocked(true /* needsReschedule */, "timed out while stopping");
break;
case VERB_EXECUTING:
// Not an error - client ran out of time.
Slog.i(TAG, "Client timed out while executing (no jobFinished received), " +
- "sending onStop: " +
- mRunningJob != null ? mRunningJob.toShortString() : "<null>");
+ "sending onStop: " + getRunningJobNameLocked());
mParams.setStopReason(JobParameters.REASON_TIMEOUT);
sendStopMessageLocked("timeout while executing");
break;
default:
- Slog.e(TAG, "Handling timeout for an invalid job state: " +
- mRunningJob != null ? mRunningJob.toShortString() : "<null>"
- + ", dropping.");
+ Slog.e(TAG, "Handling timeout for an invalid job state: "
+ + getRunningJobNameLocked() + ", dropping.");
closeAndCleanupJobLocked(false /* needsReschedule */, "invalid timeout");
}
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 5927b2f050fc..a1b84568943f 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -74,6 +74,7 @@ import android.security.KeyStore;
import android.security.keystore.AndroidKeyStoreProvider;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
+import android.security.keystore.UserNotAuthenticatedException;
import android.service.gatekeeper.GateKeeperResponse;
import android.service.gatekeeper.IGateKeeperService;
import android.text.TextUtils;
@@ -503,12 +504,34 @@ public class LockSettingsService extends ILockSettings.Stub {
maybeShowEncryptionNotificationForUser(userId);
}
+ /**
+ * Check if profile got unlocked but the keystore is still locked. This happens on full disk
+ * encryption devices since the profile may not yet be running when we consider unlocking it
+ * during the normal flow. In this case unlock the keystore for the profile.
+ */
+ private void ensureProfileKeystoreUnlocked(int userId) {
+ final KeyStore ks = KeyStore.getInstance();
+ if (ks.state(userId) == KeyStore.State.LOCKED
+ && tiedManagedProfileReadyToUnlock(mUserManager.getUserInfo(userId))) {
+ Slog.i(TAG, "Managed profile got unlocked, will unlock its keystore");
+ try {
+ // If boot took too long and the password in vold got expired, parent keystore will
+ // be still locked, we ignore this case since the user will be prompted to unlock
+ // the device after boot.
+ unlockChildProfile(userId, true /* ignoreUserNotAuthenticated */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to unlock child profile");
+ }
+ }
+ }
+
public void onUnlockUser(final int userId) {
// Perform tasks which require locks in LSS on a handler, as we are callbacks from
// ActivityManager.unlockUser()
mHandler.post(new Runnable() {
@Override
public void run() {
+ ensureProfileKeystoreUnlocked(userId);
// Hide notification first, as tie managed profile lock takes time
hideEncryptionNotification(new UserHandle(userId));
@@ -1027,7 +1050,8 @@ public class LockSettingsService extends ILockSettings.Stub {
return new String(decryptionResult, StandardCharsets.UTF_8);
}
- private void unlockChildProfile(int profileHandle) throws RemoteException {
+ private void unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated)
+ throws RemoteException {
try {
doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle),
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
@@ -1038,6 +1062,8 @@ public class LockSettingsService extends ILockSettings.Stub {
| BadPaddingException | CertificateException | IOException e) {
if (e instanceof FileNotFoundException) {
Slog.i(TAG, "Child profile key not found");
+ } else if (ignoreUserNotAuthenticated && e instanceof UserNotAuthenticatedException) {
+ Slog.i(TAG, "Parent keystore seems locked, ignoring");
} else {
Slog.e(TAG, "Failed to decrypt child profile key", e);
}
@@ -1081,11 +1107,8 @@ public class LockSettingsService extends ILockSettings.Stub {
final List<UserInfo> profiles = mUserManager.getProfiles(userId);
for (UserInfo pi : profiles) {
// Unlock managed profile with unified lock
- if (pi.isManagedProfile()
- && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id)
- && mStorage.hasChildProfileLock(pi.id)
- && mUserManager.isUserRunning(pi.id)) {
- unlockChildProfile(pi.id);
+ if (tiedManagedProfileReadyToUnlock(pi)) {
+ unlockChildProfile(pi.id, false /* ignoreUserNotAuthenticated */);
}
}
}
@@ -1094,6 +1117,13 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
+ private boolean tiedManagedProfileReadyToUnlock(UserInfo userInfo) {
+ return userInfo.isManagedProfile()
+ && !mLockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id)
+ && mStorage.hasChildProfileLock(userInfo.id)
+ && mUserManager.isUserRunning(userInfo.id);
+ }
+
private Map<Integer, String> getDecryptedPasswordsForAllTiedProfiles(int userId) {
if (mUserManager.getUserInfo(userId).isManagedProfile()) {
return null;
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 922df1e3dba8..3795b7f3091c 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -18,9 +18,7 @@ package com.android.server.media;
import com.android.internal.util.DumpUtils;
import com.android.server.Watchdog;
-import com.android.server.media.AudioPlaybackMonitor.OnAudioPlayerActiveStateChangedListener;
-import android.Manifest;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -96,9 +94,10 @@ public final class MediaRouterService extends IMediaRouterService.Stub
private final ArrayMap<IBinder, ClientRecord> mAllClientRecords =
new ArrayMap<IBinder, ClientRecord>();
private int mCurrentUserId = -1;
- private boolean mHasBluetoothRoute = false;
+ private boolean mGlobalBluetoothA2dpOn = false;
private final IAudioService mAudioService;
private final AudioPlaybackMonitor mAudioPlaybackMonitor;
+ private final AudioRoutesInfo mCurAudioRoutesInfo = new AudioRoutesInfo();
public MediaRouterService(Context context) {
mContext = context;
@@ -137,13 +136,39 @@ public final class MediaRouterService extends IMediaRouterService.Stub
audioRoutes = mAudioService.startWatchingRoutes(new IAudioRoutesObserver.Stub() {
@Override
public void dispatchAudioRoutesChanged(final AudioRoutesInfo newRoutes) {
- mHasBluetoothRoute = newRoutes.bluetoothName != null;
+ synchronized (mLock) {
+ if (newRoutes.mainType != mCurAudioRoutesInfo.mainType) {
+ if ((newRoutes.mainType & (AudioRoutesInfo.MAIN_HEADSET
+ | AudioRoutesInfo.MAIN_HEADPHONES
+ | AudioRoutesInfo.MAIN_USB)) == 0) {
+ // headset was plugged out.
+ mGlobalBluetoothA2dpOn = newRoutes.bluetoothName != null;
+ } else {
+ // headset was plugged in.
+ mGlobalBluetoothA2dpOn = false;
+ }
+ mCurAudioRoutesInfo.mainType = newRoutes.mainType;
+ }
+ if (!TextUtils.equals(
+ newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) {
+ if (newRoutes.bluetoothName == null) {
+ // BT was disconnected.
+ mGlobalBluetoothA2dpOn = false;
+ } else {
+ // BT was connected or changed.
+ mGlobalBluetoothA2dpOn = true;
+ }
+ mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName;
+ }
+ }
}
});
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException in the audio service.");
}
- mHasBluetoothRoute = (audioRoutes != null && audioRoutes.bluetoothName != null);
+ synchronized (mLock) {
+ mGlobalBluetoothA2dpOn = (audioRoutes != null && audioRoutes.bluetoothName != null);
+ }
}
public void systemRunning() {
@@ -246,6 +271,14 @@ public final class MediaRouterService extends IMediaRouterService.Stub
// Binder call
@Override
+ public boolean isGlobalBluetoothA2doOn() {
+ synchronized (mLock) {
+ return mGlobalBluetoothA2dpOn;
+ }
+ }
+
+ // Binder call
+ @Override
public void setDiscoveryRequest(IMediaRouterClient client,
int routeTypes, boolean activeScan) {
if (client == null) {
@@ -346,7 +379,12 @@ public final class MediaRouterService extends IMediaRouterService.Stub
void restoreBluetoothA2dp() {
try {
- mAudioService.setBluetoothA2dpOn(mHasBluetoothRoute);
+ boolean a2dpOn = false;
+ synchronized (mLock) {
+ a2dpOn = mGlobalBluetoothA2dpOn;
+ }
+ Slog.v(TAG, "restoreBluetoothA2dp( " + a2dpOn + ")");
+ mAudioService.setBluetoothA2dpOn(a2dpOn);
} catch (RemoteException e) {
Slog.w(TAG, "RemoteException while calling setBluetoothA2dpOn.");
}
@@ -354,12 +392,14 @@ public final class MediaRouterService extends IMediaRouterService.Stub
void restoreRoute(int uid) {
ClientRecord clientRecord = null;
- UserRecord userRecord = mUserRecords.get(UserHandle.getUserId(uid));
- if (userRecord != null && userRecord.mClientRecords != null) {
- for (ClientRecord cr : userRecord.mClientRecords) {
- if (validatePackageName(uid, cr.mPackageName)) {
- clientRecord = cr;
- break;
+ synchronized (mLock) {
+ UserRecord userRecord = mUserRecords.get(UserHandle.getUserId(uid));
+ if (userRecord != null && userRecord.mClientRecords != null) {
+ for (ClientRecord cr : userRecord.mClientRecords) {
+ if (validatePackageName(uid, cr.mPackageName)) {
+ clientRecord = cr;
+ break;
+ }
}
}
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 93458c8daf9c..b224069d04f8 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -33,6 +33,7 @@ import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLE
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED;
import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED;
@@ -191,8 +192,6 @@ import com.android.server.power.BatterySaverPolicy.ServiceType;
import libcore.io.IoUtils;
-import com.google.android.collect.Lists;
-
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
@@ -373,8 +372,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
/** Defined network policies. */
final ArrayMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = new ArrayMap<>();
- /** Currently active network rules for ifaces. */
- final ArrayMap<NetworkPolicy, String[]> mNetworkRules = new ArrayMap<>();
/** Map from subId to subscription plans. */
final SparseArray<SubscriptionPlan[]> mSubscriptionPlans = new SparseArray<>();
@@ -927,7 +924,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
/**
* Receiver that watches for {@link WifiConfiguration} to be loaded so that
- * we can perform upgrade logic.
+ * we can perform upgrade logic. After initial upgrade logic, it updates
+ * {@link #mMeteredIfaces} based on configuration changes.
*/
final private BroadcastReceiver mWifiReceiver = new BroadcastReceiver() {
@Override
@@ -935,10 +933,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
synchronized (mUidRulesFirstLock) {
synchronized (mNetworkPoliciesSecondLock) {
upgradeWifiMeteredOverrideAL();
+ updateNetworkRulesNL();
}
}
- // Only need to perform upgrade logic once
- mContext.unregisterReceiver(this);
}
};
@@ -1445,6 +1442,22 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
/**
+ * Collect all ifaces from a {@link NetworkState} into the given set.
+ */
+ private static void collectIfaces(ArraySet<String> ifaces, NetworkState state) {
+ final String baseIface = state.linkProperties.getInterfaceName();
+ if (baseIface != null) {
+ ifaces.add(baseIface);
+ }
+ for (LinkProperties stackedLink : state.linkProperties.getStackedLinks()) {
+ final String stackedIface = stackedLink.getInterfaceName();
+ if (stackedIface != null) {
+ ifaces.add(stackedIface);
+ }
+ }
+ }
+
+ /**
* Examine all connected {@link NetworkState}, looking for
* {@link NetworkPolicy} that need to be enforced. When matches found, set
* remaining quota based on usage cycle and historical stats.
@@ -1462,60 +1475,33 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// First, generate identities of all connected networks so we can
// quickly compare them against all defined policies below.
- final ArrayList<Pair<String, NetworkIdentity>> connIdents = new ArrayList<>(states.length);
- final ArraySet<String> connIfaces = new ArraySet<String>(states.length);
+ final ArrayMap<NetworkState, NetworkIdentity> identified = new ArrayMap<>();
for (NetworkState state : states) {
if (state.networkInfo != null && state.networkInfo.isConnected()) {
final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
-
- final String baseIface = state.linkProperties.getInterfaceName();
- if (baseIface != null) {
- connIdents.add(Pair.create(baseIface, ident));
- }
-
- // Stacked interfaces are considered to have same identity as
- // their parent network.
- final List<LinkProperties> stackedLinks = state.linkProperties.getStackedLinks();
- for (LinkProperties stackedLink : stackedLinks) {
- final String stackedIface = stackedLink.getInterfaceName();
- if (stackedIface != null) {
- connIdents.add(Pair.create(stackedIface, ident));
- }
- }
+ identified.put(state, ident);
}
}
- // Apply policies against all connected interfaces found above
- mNetworkRules.clear();
- final ArrayList<String> ifaceList = Lists.newArrayList();
+ final ArraySet<String> newMeteredIfaces = new ArraySet<>();
+ long lowestRule = Long.MAX_VALUE;
+
+ // For every well-defined policy, compute remaining data based on
+ // current cycle and historical stats, and push to kernel.
+ final ArraySet<String> matchingIfaces = new ArraySet<>();
for (int i = mNetworkPolicy.size() - 1; i >= 0; i--) {
- final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
+ final NetworkPolicy policy = mNetworkPolicy.valueAt(i);
- ifaceList.clear();
- for (int j = connIdents.size() - 1; j >= 0; j--) {
- final Pair<String, NetworkIdentity> ident = connIdents.get(j);
- if (policy.template.matches(ident.second)) {
- ifaceList.add(ident.first);
+ // Collect all ifaces that match this policy
+ matchingIfaces.clear();
+ for (int j = identified.size() - 1; j >= 0; j--) {
+ if (policy.template.matches(identified.valueAt(j))) {
+ collectIfaces(matchingIfaces, identified.keyAt(j));
}
}
- if (ifaceList.size() > 0) {
- final String[] ifaces = ifaceList.toArray(new String[ifaceList.size()]);
- mNetworkRules.put(policy, ifaces);
- }
- }
-
- long lowestRule = Long.MAX_VALUE;
- final ArraySet<String> newMeteredIfaces = new ArraySet<String>(states.length);
-
- // apply each policy that we found ifaces for; compute remaining data
- // based on current cycle and historical stats, and push to kernel.
- for (int i = mNetworkRules.size()-1; i >= 0; i--) {
- final NetworkPolicy policy = mNetworkRules.keyAt(i);
- final String[] ifaces = mNetworkRules.valueAt(i);
-
if (LOGD) {
- Slog.d(TAG, "applying policy " + policy + " to ifaces " + Arrays.toString(ifaces));
+ Slog.d(TAG, "Applying " + policy + " to ifaces " + matchingIfaces);
}
final boolean hasWarning = policy.warningBytes != LIMIT_DISABLED;
@@ -1545,16 +1531,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
quotaBytes = Long.MAX_VALUE;
}
- if (ifaces.length > 1) {
+ if (matchingIfaces.size() > 1) {
// TODO: switch to shared quota once NMS supports
Slog.w(TAG, "shared quota unsupported; generating rule for each iface");
}
- for (String iface : ifaces) {
- // long quotaBytes split up into two ints to fit in message
- mHandler.obtainMessage(MSG_UPDATE_INTERFACE_QUOTA,
- (int) (quotaBytes >> 32), (int) (quotaBytes & 0xFFFFFFFF), iface)
- .sendToTarget();
+ for (int j = matchingIfaces.size() - 1; j >= 0; j--) {
+ final String iface = matchingIfaces.valueAt(j);
+ setInterfaceQuotaAsync(iface, quotaBytes);
newMeteredIfaces.add(iface);
}
}
@@ -1568,29 +1552,36 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
- for (int i = connIfaces.size()-1; i >= 0; i--) {
- String iface = connIfaces.valueAt(i);
- // long quotaBytes split up into two ints to fit in message
- mHandler.obtainMessage(MSG_UPDATE_INTERFACE_QUOTA,
- (int) (Long.MAX_VALUE >> 32), (int) (Long.MAX_VALUE & 0xFFFFFFFF), iface)
- .sendToTarget();
- newMeteredIfaces.add(iface);
+ // One final pass to catch any metered ifaces that don't have explicitly
+ // defined policies; typically Wi-Fi networks.
+ for (NetworkState state : states) {
+ if (state.networkInfo != null && state.networkInfo.isConnected()
+ && !state.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED)) {
+ matchingIfaces.clear();
+ collectIfaces(matchingIfaces, state);
+ for (int j = matchingIfaces.size() - 1; j >= 0; j--) {
+ final String iface = matchingIfaces.valueAt(j);
+ if (!newMeteredIfaces.contains(iface)) {
+ setInterfaceQuotaAsync(iface, Long.MAX_VALUE);
+ newMeteredIfaces.add(iface);
+ }
+ }
+ }
}
- mHandler.obtainMessage(MSG_ADVISE_PERSIST_THRESHOLD, lowestRule).sendToTarget();
-
- // remove quota on any trailing interfaces
+ // Remove quota from any interfaces that are no longer metered.
for (int i = mMeteredIfaces.size() - 1; i >= 0; i--) {
final String iface = mMeteredIfaces.valueAt(i);
if (!newMeteredIfaces.contains(iface)) {
- mHandler.obtainMessage(MSG_REMOVE_INTERFACE_QUOTA, iface)
- .sendToTarget();
+ removeInterfaceQuotaAsync(iface);
}
}
mMeteredIfaces = newMeteredIfaces;
final String[] meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
mHandler.obtainMessage(MSG_METERED_IFACES_CHANGED, meteredIfaces).sendToTarget();
+
+ mHandler.obtainMessage(MSG_ADVISE_PERSIST_THRESHOLD, lowestRule).sendToTarget();
}
/**
@@ -3973,6 +3964,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
+ private void setInterfaceQuotaAsync(String iface, long quotaBytes) {
+ // long quotaBytes split up into two ints to fit in message
+ mHandler.obtainMessage(MSG_UPDATE_INTERFACE_QUOTA, (int) (quotaBytes >> 32),
+ (int) (quotaBytes & 0xFFFFFFFF), iface).sendToTarget();
+ }
+
private void setInterfaceQuota(String iface, long quotaBytes) {
try {
mNetworkManager.setInterfaceQuota(iface, quotaBytes);
@@ -3983,6 +3980,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
+ private void removeInterfaceQuotaAsync(String iface) {
+ mHandler.obtainMessage(MSG_REMOVE_INTERFACE_QUOTA, iface).sendToTarget();
+ }
+
private void removeInterfaceQuota(String iface) {
try {
mNetworkManager.removeInterfaceQuota(iface);
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 03543007c80e..8837c157aebe 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -28,6 +28,8 @@ import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_REMOVED;
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
+import static com.android.server.net.NetworkStatsService.TAG;
+
import android.net.NetworkIdentity;
import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
@@ -37,20 +39,24 @@ import android.os.Binder;
import android.service.NetworkStatsCollectionKeyProto;
import android.service.NetworkStatsCollectionProto;
import android.service.NetworkStatsCollectionStatsProto;
+import android.telephony.SubscriptionPlan;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.IntArray;
+import android.util.Pair;
+import android.util.Slog;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
+import libcore.io.IoUtils;
+
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
-import libcore.io.IoUtils;
-
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -60,9 +66,11 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.ProtocolException;
+import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.Objects;
/**
@@ -140,6 +148,35 @@ public class NetworkStatsCollection implements FileRotator.Reader {
return mStartMillis == Long.MAX_VALUE && mEndMillis == Long.MIN_VALUE;
}
+ @VisibleForTesting
+ public long roundUp(long time) {
+ if (time == Long.MIN_VALUE || time == Long.MAX_VALUE
+ || time == SubscriptionPlan.TIME_UNKNOWN) {
+ return time;
+ } else {
+ final long mod = time % mBucketDuration;
+ if (mod > 0) {
+ time -= mod;
+ time += mBucketDuration;
+ }
+ return time;
+ }
+ }
+
+ @VisibleForTesting
+ public long roundDown(long time) {
+ if (time == Long.MIN_VALUE || time == Long.MAX_VALUE
+ || time == SubscriptionPlan.TIME_UNKNOWN) {
+ return time;
+ } else {
+ final long mod = time % mBucketDuration;
+ if (mod > 0) {
+ time -= mod;
+ }
+ return time;
+ }
+ }
+
public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) {
return getRelevantUids(accessLevel, Binder.getCallingUid());
}
@@ -165,60 +202,110 @@ public class NetworkStatsCollection implements FileRotator.Reader {
* Combine all {@link NetworkStatsHistory} in this collection which match
* the requested parameters.
*/
- public NetworkStatsHistory getHistory(
- NetworkTemplate template, int uid, int set, int tag, int fields,
- @NetworkStatsAccess.Level int accessLevel) {
- return getHistory(template, uid, set, tag, fields, Long.MIN_VALUE, Long.MAX_VALUE,
- accessLevel);
- }
-
- /**
- * Combine all {@link NetworkStatsHistory} in this collection which match
- * the requested parameters.
- */
- public NetworkStatsHistory getHistory(
- NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end,
- @NetworkStatsAccess.Level int accessLevel) {
- return getHistory(template, uid, set, tag, fields, start, end, accessLevel,
- Binder.getCallingUid());
- }
-
- /**
- * Combine all {@link NetworkStatsHistory} in this collection which match
- * the requested parameters.
- */
- public NetworkStatsHistory getHistory(
- NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end,
+ public NetworkStatsHistory getHistory(NetworkTemplate template, SubscriptionPlan augmentPlan,
+ int uid, int set, int tag, int fields, long start, long end,
@NetworkStatsAccess.Level int accessLevel, int callerUid) {
if (!NetworkStatsAccess.isAccessibleToUser(uid, callerUid, accessLevel)) {
throw new SecurityException("Network stats history of uid " + uid
+ " is forbidden for caller " + callerUid);
}
+ final int bucketEstimate = (int) ((end - start) / mBucketDuration);
final NetworkStatsHistory combined = new NetworkStatsHistory(
- mBucketDuration, start == end ? 1 : estimateBuckets(), fields);
+ mBucketDuration, bucketEstimate, fields);
// shortcut when we know stats will be empty
if (start == end) return combined;
+ // Figure out the window of time that we should be augmenting (if any)
+ long augmentStart = SubscriptionPlan.TIME_UNKNOWN;
+ long augmentEnd = (augmentPlan != null) ? augmentPlan.getDataUsageTime()
+ : SubscriptionPlan.TIME_UNKNOWN;
+ // And if augmenting, we might need to collect more data to adjust with
+ long collectStart = start;
+ long collectEnd = end;
+
+ if (augmentEnd != SubscriptionPlan.TIME_UNKNOWN) {
+ final Iterator<Pair<ZonedDateTime, ZonedDateTime>> it = augmentPlan.cycleIterator();
+ while (it.hasNext()) {
+ final Pair<ZonedDateTime, ZonedDateTime> cycle = it.next();
+ final long cycleStart = cycle.first.toInstant().toEpochMilli();
+ final long cycleEnd = cycle.second.toInstant().toEpochMilli();
+ if (cycleStart <= augmentEnd && augmentEnd < cycleEnd) {
+ augmentStart = cycleStart;
+ collectStart = Long.min(collectStart, augmentStart);
+ collectEnd = Long.max(collectEnd, augmentEnd);
+ break;
+ }
+ }
+ }
+
+ if (augmentStart != SubscriptionPlan.TIME_UNKNOWN) {
+ // Shrink augmentation window so we don't risk undercounting.
+ augmentStart = roundUp(augmentStart);
+ augmentEnd = roundDown(augmentEnd);
+ // Grow collection window so we get all the stats needed.
+ collectStart = roundDown(collectStart);
+ collectEnd = roundUp(collectEnd);
+ }
+
for (int i = 0; i < mStats.size(); i++) {
final Key key = mStats.keyAt(i);
if (key.uid == uid && NetworkStats.setMatches(set, key.set) && key.tag == tag
&& templateMatches(template, key.ident)) {
final NetworkStatsHistory value = mStats.valueAt(i);
- combined.recordHistory(value, start, end);
+ combined.recordHistory(value, collectStart, collectEnd);
}
}
- return combined;
- }
- /**
- * Summarize all {@link NetworkStatsHistory} in this collection which match
- * the requested parameters.
- */
- public NetworkStats getSummary(NetworkTemplate template, long start, long end,
- @NetworkStatsAccess.Level int accessLevel) {
- return getSummary(template, start, end, accessLevel, Binder.getCallingUid());
+ if (augmentStart != SubscriptionPlan.TIME_UNKNOWN) {
+ final NetworkStatsHistory.Entry entry = combined.getValues(
+ augmentStart, augmentEnd, null);
+
+ // If we don't have any recorded data for this time period, give
+ // ourselves something to scale with.
+ if (entry.rxBytes == 0 || entry.txBytes == 0) {
+ combined.recordData(augmentStart, augmentEnd,
+ new NetworkStats.Entry(1, 0, 1, 0, 0));
+ combined.getValues(augmentStart, augmentEnd, entry);
+ }
+
+ final long rawBytes = entry.rxBytes + entry.txBytes;
+ final long rawRxBytes = entry.rxBytes;
+ final long rawTxBytes = entry.txBytes;
+ final long targetBytes = augmentPlan.getDataUsageBytes();
+ final long targetRxBytes = (rawRxBytes * targetBytes) / rawBytes;
+ final long targetTxBytes = (rawTxBytes * targetBytes) / rawBytes;
+
+ // Scale all matching buckets to reach anchor target
+ final long beforeTotal = combined.getTotalBytes();
+ for (int i = 0; i < combined.size(); i++) {
+ combined.getValues(i, entry);
+ if (entry.bucketStart >= augmentStart
+ && entry.bucketStart + entry.bucketDuration <= augmentEnd) {
+ entry.rxBytes = (entry.rxBytes * targetRxBytes) / rawRxBytes;
+ entry.txBytes = (entry.txBytes * targetTxBytes) / rawTxBytes;
+ // We purposefully clear out packet counters to indicate
+ // that this data has been augmented.
+ entry.rxPackets = 0;
+ entry.txPackets = 0;
+ combined.setValues(i, entry);
+ }
+ }
+
+ final long deltaTotal = combined.getTotalBytes() - beforeTotal;
+ if (deltaTotal != 0) {
+ Slog.d(TAG, "Augmented network usage by " + deltaTotal + " bytes");
+ }
+
+ // Finally we can slice data as originally requested
+ final NetworkStatsHistory sliced = new NetworkStatsHistory(
+ mBucketDuration, bucketEstimate, fields);
+ sliced.recordHistory(combined, start, end);
+ return sliced;
+ } else {
+ return combined;
+ }
}
/**
@@ -230,6 +317,7 @@ public class NetworkStatsCollection implements FileRotator.Reader {
final long now = System.currentTimeMillis();
final NetworkStats stats = new NetworkStats(end - start, 24);
+
// shortcut when we know stats will be empty
if (start == end) return stats;
diff --git a/services/core/java/com/android/server/net/NetworkStatsObservers.java b/services/core/java/com/android/server/net/NetworkStatsObservers.java
index a256cbcf9030..741c2062bd57 100644
--- a/services/core/java/com/android/server/net/NetworkStatsObservers.java
+++ b/services/core/java/com/android/server/net/NetworkStatsObservers.java
@@ -17,28 +17,26 @@
package com.android.server.net;
import static android.net.TrafficStats.MB_IN_BYTES;
+
import static com.android.internal.util.Preconditions.checkArgument;
import android.app.usage.NetworkStatsManager;
import android.net.DataUsageRequest;
import android.net.NetworkStats;
-import android.net.NetworkStats.NonMonotonicObserver;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
-import android.os.Binder;
import android.os.Bundle;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
import android.os.Process;
import android.os.RemoteException;
import android.util.ArrayMap;
-import android.util.IntArray;
-import android.util.SparseArray;
import android.util.Slog;
+import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.net.VpnInfo;
@@ -410,7 +408,7 @@ class NetworkStatsObservers {
*/
private long getTotalBytesForNetworkUid(NetworkTemplate template, int uid) {
try {
- NetworkStatsHistory history = mCollection.getHistory(template, uid,
+ NetworkStatsHistory history = mCollection.getHistory(template, null, uid,
NetworkStats.SET_ALL, NetworkStats.TAG_NONE,
NetworkStatsHistory.FIELD_ALL,
Long.MIN_VALUE /* start */, Long.MAX_VALUE /* end */,
diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
index 80309e19eb42..4bee55ef8b22 100644
--- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
@@ -20,6 +20,7 @@ import static android.net.NetworkStats.TAG_NONE;
import static android.net.TrafficStats.KB_IN_BYTES;
import static android.net.TrafficStats.MB_IN_BYTES;
import static android.text.format.DateUtils.YEAR_IN_MILLIS;
+
import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.Nullable;
@@ -28,6 +29,7 @@ import android.net.NetworkStats.NonMonotonicObserver;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.TrafficStats;
+import android.os.Binder;
import android.os.DropBoxManager;
import android.service.NetworkStatsRecorderProto;
import android.util.Log;
@@ -38,6 +40,9 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.net.VpnInfo;
import com.android.internal.util.FileRotator;
import com.android.internal.util.IndentingPrintWriter;
+
+import libcore.io.IoUtils;
+
import com.google.android.collect.Sets;
import java.io.ByteArrayOutputStream;
@@ -52,8 +57,6 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
-import libcore.io.IoUtils;
-
/**
* Logic to record deltas between periodic {@link NetworkStats} snapshots into
* {@link NetworkStatsHistory} that belong to {@link NetworkStatsCollection}.
@@ -150,7 +153,7 @@ public class NetworkStatsRecorder {
public NetworkStats.Entry getTotalSinceBootLocked(NetworkTemplate template) {
return mSinceBoot.getSummary(template, Long.MIN_VALUE, Long.MAX_VALUE,
- NetworkStatsAccess.Level.DEVICE).getTotal(null);
+ NetworkStatsAccess.Level.DEVICE, Binder.getCallingUid()).getTotal(null);
}
public NetworkStatsCollection getSinceBoot() {
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index b14aa13bfb28..4bd927d4970e 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -26,6 +26,8 @@ import static android.content.Intent.EXTRA_UID;
import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.ConnectivityManager.isNetworkTypeMobile;
import static android.net.NetworkStats.IFACE_ALL;
+import static android.net.NetworkStats.METERED_ALL;
+import static android.net.NetworkStats.ROAMING_ALL;
import static android.net.NetworkStats.SET_ALL;
import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.SET_FOREGROUND;
@@ -33,10 +35,12 @@ import static android.net.NetworkStats.STATS_PER_IFACE;
import static android.net.NetworkStats.STATS_PER_UID;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
+import static android.net.NetworkStatsHistory.FIELD_ALL;
import static android.net.NetworkTemplate.buildTemplateMobileWildcard;
import static android.net.NetworkTemplate.buildTemplateWifiWildcard;
import static android.net.TrafficStats.KB_IN_BYTES;
import static android.net.TrafficStats.MB_IN_BYTES;
+import static android.provider.Settings.Global.NETSTATS_AUGMENT_ENABLED;
import static android.provider.Settings.Global.NETSTATS_DEV_BUCKET_DURATION;
import static android.provider.Settings.Global.NETSTATS_DEV_DELETE_AGE;
import static android.provider.Settings.Global.NETSTATS_DEV_PERSIST_BYTES;
@@ -65,6 +69,7 @@ import static com.android.server.NetworkManagementSocketTagger.setKernelCounterS
import android.app.AlarmManager;
import android.app.PendingIntent;
+import android.app.usage.NetworkStatsManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -104,6 +109,8 @@ import android.provider.Settings;
import android.provider.Settings.Global;
import android.service.NetworkInterfaceProto;
import android.service.NetworkStatsServiceDumpProto;
+import android.telephony.SubscriptionManager;
+import android.telephony.SubscriptionPlan;
import android.telephony.TelephonyManager;
import android.text.format.DateUtils;
import android.util.ArrayMap;
@@ -139,8 +146,8 @@ import java.util.List;
* other system services.
*/
public class NetworkStatsService extends INetworkStatsService.Stub {
- private static final String TAG = "NetworkStats";
- private static final boolean LOGV = false;
+ static final String TAG = "NetworkStats";
+ static final boolean LOGV = false;
private static final int MSG_PERFORM_POLL = 1;
private static final int MSG_UPDATE_IFACES = 2;
@@ -194,6 +201,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
public long getPollInterval();
public long getTimeCacheMaxAge();
public boolean getSampleEnabled();
+ public boolean getAugmentEnabled();
public static class Config {
public final long bucketDuration;
@@ -466,18 +474,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@Override
public INetworkStatsSession openSession() {
- return createSession(null, /* poll on create */ false);
+ // NOTE: if callers want to get non-augmented data, they should go
+ // through the public API
+ return openSessionInternal(NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, null);
}
@Override
- public INetworkStatsSession openSessionForUsageStats(final String callingPackage) {
- return createSession(callingPackage, /* poll on create */ true);
+ public INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage) {
+ return openSessionInternal(flags, callingPackage);
}
- private INetworkStatsSession createSession(final String callingPackage, boolean pollOnCreate) {
+ private INetworkStatsSession openSessionInternal(final int flags, final String callingPackage) {
assertBandwidthControlEnabled();
- if (pollOnCreate) {
+ if ((flags & NetworkStatsManager.FLAG_POLL_ON_OPEN) != 0) {
final long ident = Binder.clearCallingIdentity();
try {
performPoll(FLAG_PERSIST_ALL);
@@ -490,9 +500,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// for its lifetime; when caller closes only weak references remain.
return new INetworkStatsSession.Stub() {
+ private final int mCallingUid = Binder.getCallingUid();
+ private final String mCallingPackage = callingPackage;
+ private final @NetworkStatsAccess.Level int mAccessLevel = checkAccessLevel(
+ callingPackage);
+
private NetworkStatsCollection mUidComplete;
private NetworkStatsCollection mUidTagComplete;
- private String mCallingPackage = callingPackage;
private NetworkStatsCollection getUidComplete() {
synchronized (mStatsLock) {
@@ -514,55 +528,38 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@Override
public int[] getRelevantUids() {
- return getUidComplete().getRelevantUids(checkAccessLevel(mCallingPackage));
+ return getUidComplete().getRelevantUids(mAccessLevel);
}
@Override
- public NetworkStats getDeviceSummaryForNetwork(NetworkTemplate template, long start,
- long end) {
- @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
- if (accessLevel < NetworkStatsAccess.Level.DEVICESUMMARY) {
- throw new SecurityException("Calling package " + mCallingPackage
- + " cannot access device summary network stats");
- }
- NetworkStats result = new NetworkStats(end - start, 1);
- final long ident = Binder.clearCallingIdentity();
- try {
- // Using access level higher than the one we checked for above.
- // Reason is that we are combining usage data in a way that is not PII
- // anymore.
- result.combineAllValues(
- internalGetSummaryForNetwork(template, start, end,
- NetworkStatsAccess.Level.DEVICE));
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- return result;
+ public NetworkStats getDeviceSummaryForNetwork(
+ NetworkTemplate template, long start, long end) {
+ return internalGetSummaryForNetwork(template, flags, start, end, mAccessLevel,
+ mCallingUid);
}
@Override
public NetworkStats getSummaryForNetwork(
NetworkTemplate template, long start, long end) {
- @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
- return internalGetSummaryForNetwork(template, start, end, accessLevel);
+ return internalGetSummaryForNetwork(template, flags, start, end, mAccessLevel,
+ mCallingUid);
}
@Override
public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) {
- @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
- return internalGetHistoryForNetwork(template, fields, accessLevel);
+ return internalGetHistoryForNetwork(template, flags, fields, mAccessLevel,
+ mCallingUid);
}
@Override
public NetworkStats getSummaryForAllUid(
NetworkTemplate template, long start, long end, boolean includeTags) {
try {
- @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
- final NetworkStats stats =
- getUidComplete().getSummary(template, start, end, accessLevel);
+ final NetworkStats stats = getUidComplete()
+ .getSummary(template, start, end, mAccessLevel, mCallingUid);
if (includeTags) {
final NetworkStats tagStats = getUidTagComplete()
- .getSummary(template, start, end, accessLevel);
+ .getSummary(template, start, end, mAccessLevel, mCallingUid);
stats.combineAllValues(tagStats);
}
return stats;
@@ -576,13 +573,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
@Override
public NetworkStatsHistory getHistoryForUid(
NetworkTemplate template, int uid, int set, int tag, int fields) {
- @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
+ // NOTE: We don't augment UID-level statistics
if (tag == TAG_NONE) {
- return getUidComplete().getHistory(template, uid, set, tag, fields,
- accessLevel);
+ return getUidComplete().getHistory(template, null, uid, set, tag, fields,
+ Long.MIN_VALUE, Long.MAX_VALUE, mAccessLevel, mCallingUid);
} else {
- return getUidTagComplete().getHistory(template, uid, set, tag, fields,
- accessLevel);
+ return getUidTagComplete().getHistory(template, null, uid, set, tag, fields,
+ Long.MIN_VALUE, Long.MAX_VALUE, mAccessLevel, mCallingUid);
}
}
@@ -590,13 +587,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
public NetworkStatsHistory getHistoryIntervalForUid(
NetworkTemplate template, int uid, int set, int tag, int fields,
long start, long end) {
- @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage);
+ // NOTE: We don't augment UID-level statistics
if (tag == TAG_NONE) {
- return getUidComplete().getHistory(template, uid, set, tag, fields, start, end,
- accessLevel);
+ return getUidComplete().getHistory(template, null, uid, set, tag, fields,
+ start, end, mAccessLevel, mCallingUid);
} else if (uid == Binder.getCallingUid()) {
- return getUidTagComplete().getHistory(template, uid, set, tag, fields,
- start, end, accessLevel);
+ return getUidTagComplete().getHistory(template, null, uid, set, tag, fields,
+ start, end, mAccessLevel, mCallingUid);
} else {
throw new SecurityException("Calling package " + mCallingPackage
+ " cannot access tag information from a different uid");
@@ -617,36 +614,84 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
/**
+ * Find the most relevant {@link SubscriptionPlan} for the given
+ * {@link NetworkTemplate} and flags. This is typically used to augment
+ * local measurement results to match a known anchor from the carrier.
+ */
+ private SubscriptionPlan resolveSubscriptionPlan(NetworkTemplate template, int flags) {
+ SubscriptionPlan plan = null;
+ if ((flags & NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN) != 0
+ && (template.getMatchRule() == NetworkTemplate.MATCH_MOBILE_ALL)
+ && mSettings.getAugmentEnabled()) {
+ Slog.d(TAG, "Resolving plan for " + template);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ final SubscriptionManager sm = mContext.getSystemService(SubscriptionManager.class);
+ final TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+ for (int subId : sm.getActiveSubscriptionIdList()) {
+ if (template.matchesSubscriberId(tm.getSubscriberId(subId))) {
+ Slog.d(TAG, "Found active matching subId " + subId);
+ final List<SubscriptionPlan> plans = sm.getSubscriptionPlans(subId);
+ if (!plans.isEmpty()) {
+ plan = plans.get(0);
+ }
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ Slog.d(TAG, "Resolved to plan " + plan);
+ }
+ return plan;
+ }
+
+ /**
* Return network summary, splicing between DEV and XT stats when
* appropriate.
*/
- private NetworkStats internalGetSummaryForNetwork(
- NetworkTemplate template, long start, long end,
- @NetworkStatsAccess.Level int accessLevel) {
+ private NetworkStats internalGetSummaryForNetwork(NetworkTemplate template, int flags,
+ long start, long end, @NetworkStatsAccess.Level int accessLevel, int callingUid) {
// We've been using pure XT stats long enough that we no longer need to
// splice DEV and XT together.
- return mXtStatsCached.getSummary(template, start, end, accessLevel);
+ final NetworkStatsHistory history = internalGetHistoryForNetwork(template, flags, FIELD_ALL,
+ accessLevel, callingUid);
+
+ final long now = System.currentTimeMillis();
+ final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null);
+
+ final NetworkStats stats = new NetworkStats(end - start, 1);
+ stats.addValues(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL,
+ ROAMING_ALL, entry.rxBytes, entry.rxPackets, entry.txBytes, entry.txPackets,
+ entry.operations));
+ return stats;
}
/**
* Return network history, splicing between DEV and XT stats when
* appropriate.
*/
- private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template, int fields,
- @NetworkStatsAccess.Level int accessLevel) {
+ private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template,
+ int flags, int fields, @NetworkStatsAccess.Level int accessLevel, int callingUid) {
// We've been using pure XT stats long enough that we no longer need to
// splice DEV and XT together.
- return mXtStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields, accessLevel);
+ return mXtStatsCached.getHistory(template, resolveSubscriptionPlan(template, flags),
+ UID_ALL, SET_ALL, TAG_NONE, fields, Long.MIN_VALUE, Long.MAX_VALUE,
+ accessLevel, callingUid);
}
@Override
public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) {
- // Special case - since this is for internal use only, don't worry about a full access level
- // check and just require the signature/privileged permission.
+ // Special case - since this is for internal use only, don't worry about
+ // a full access level check and just require the signature/privileged
+ // permission.
mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
assertBandwidthControlEnabled();
- return internalGetSummaryForNetwork(template, start, end, NetworkStatsAccess.Level.DEVICE)
- .getTotalBytes();
+
+ // NOTE: if callers want to get non-augmented data, they should go
+ // through the public API
+ return internalGetSummaryForNetwork(template,
+ NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, start, end,
+ NetworkStatsAccess.Level.DEVICE, Binder.getCallingUid()).getTotalBytes();
}
@Override
@@ -1530,6 +1575,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
return getGlobalBoolean(NETSTATS_SAMPLE_ENABLED, true);
}
@Override
+ public boolean getAugmentEnabled() {
+ return getGlobalBoolean(NETSTATS_AUGMENT_ENABLED, true);
+ }
+ @Override
public Config getDevConfig() {
return new Config(getGlobalLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS),
getGlobalLong(NETSTATS_DEV_ROTATE_AGE, 15 * DAY_IN_MILLIS),
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 9a76294cdd9e..0c9f65aeff98 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1476,6 +1476,19 @@ public class NotificationManagerService extends SystemService {
savePolicyFile();
}
+ private void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
+ boolean fromApp, boolean fromListener) {
+ Preconditions.checkNotNull(group);
+ Preconditions.checkNotNull(pkg);
+ mRankingHelper.createNotificationChannelGroup(pkg, uid, group,
+ fromApp);
+ if (!fromListener) {
+ mListeners.notifyNotificationChannelGroupChanged(pkg,
+ UserHandle.of(UserHandle.getCallingUserId()), group,
+ NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
+ }
+ }
+
private ArrayList<ComponentName> getSuppressors() {
ArrayList<ComponentName> names = new ArrayList<ComponentName>();
for (int i = mListenersDisablingEffects.size() - 1; i >= 0; --i) {
@@ -1763,6 +1776,14 @@ public class NotificationManagerService extends SystemService {
}
@Override
+ public void updateNotificationChannelGroupForPackage(String pkg, int uid,
+ NotificationChannelGroup group) throws RemoteException {
+ enforceSystemOrSystemUI("Caller not system or systemui");
+ createNotificationChannelGroup(pkg, uid, group, false, false);
+ savePolicyFile();
+ }
+
+ @Override
public void createNotificationChannelGroups(String pkg,
ParceledListSlice channelGroupList) throws RemoteException {
checkCallerIsSystemOrSameApp(pkg);
@@ -1770,12 +1791,7 @@ public class NotificationManagerService extends SystemService {
final int groupSize = groups.size();
for (int i = 0; i < groupSize; i++) {
final NotificationChannelGroup group = groups.get(i);
- Preconditions.checkNotNull(group, "group in list is null");
- mRankingHelper.createNotificationChannelGroup(pkg, Binder.getCallingUid(), group,
- true /* fromTargetApp */);
- mListeners.notifyNotificationChannelGroupChanged(pkg,
- UserHandle.of(UserHandle.getCallingUserId()), group,
- NOTIFICATION_CHANNEL_OR_GROUP_ADDED);
+ createNotificationChannelGroup(pkg, Binder.getCallingUid(), group, true, false);
}
savePolicyFile();
}
@@ -1921,6 +1937,14 @@ public class NotificationManagerService extends SystemService {
}
@Override
+ public NotificationChannelGroup getPopulatedNotificationChannelGroupForPackage(
+ String pkg, int uid, String groupId, boolean includeDeleted) {
+ enforceSystemOrSystemUI("getPopulatedNotificationChannelGroupForPackage");
+ return mRankingHelper.getNotificationChannelGroupWithChannels(
+ pkg, uid, groupId, includeDeleted);
+ }
+
+ @Override
public NotificationChannelGroup getNotificationChannelGroupForPackage(
String groupId, String pkg, int uid) {
enforceSystemOrSystemUI("getNotificationChannelGroupForPackage");
@@ -2923,6 +2947,17 @@ public class NotificationManagerService extends SystemService {
}
@Override
+ public void updateNotificationChannelGroupFromPrivilegedListener(
+ INotificationListener token, String pkg, UserHandle user,
+ NotificationChannelGroup group) throws RemoteException {
+ Preconditions.checkNotNull(user);
+ verifyPrivilegedListener(token, user);
+ createNotificationChannelGroup(
+ pkg, getUidForPackageAndUser(pkg, user), group, false, true);
+ savePolicyFile();
+ }
+
+ @Override
public void updateNotificationChannelFromPrivilegedListener(INotificationListener token,
String pkg, UserHandle user, NotificationChannel channel) throws RemoteException {
Preconditions.checkNotNull(channel);
@@ -3618,9 +3653,10 @@ public class NotificationManagerService extends SystemService {
usageStats.registerSuspendedByAdmin(r);
return isPackageSuspended;
}
-
final boolean isBlocked =
- mRankingHelper.getImportance(pkg, callingUid) == NotificationManager.IMPORTANCE_NONE
+ mRankingHelper.isGroupBlocked(pkg, callingUid, r.getChannel().getGroup())
+ || mRankingHelper.getImportance(pkg, callingUid)
+ == NotificationManager.IMPORTANCE_NONE
|| r.getChannel().getImportance() == NotificationManager.IMPORTANCE_NONE;
if (isBlocked) {
Slog.e(TAG, "Suppressing notification from package by user request.");
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 36da04dfc3c6..b5ef1c60f607 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -29,6 +29,7 @@ public interface RankingConfig {
void setShowBadge(String packageName, int uid, boolean showBadge);
boolean canShowBadge(String packageName, int uid);
boolean badgingEnabled(UserHandle userHandle);
+ boolean isGroupBlocked(String packageName, int uid, String groupId);
Collection<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
int uid);
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 3386fe832e0f..1736a74e1270 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -215,6 +215,7 @@ public class RankingHelper implements RankingConfig {
if (!TextUtils.isEmpty(id)) {
NotificationChannelGroup group
= new NotificationChannelGroup(id, groupName);
+ group.populateFromXml(parser);
r.groups.put(id, group);
}
}
@@ -493,6 +494,19 @@ public class RankingHelper implements RankingConfig {
updateConfig();
}
+ @Override
+ public boolean isGroupBlocked(String packageName, int uid, String groupId) {
+ if (groupId == null) {
+ return false;
+ }
+ Record r = getOrCreateRecord(packageName, uid);
+ NotificationChannelGroup group = r.groups.get(groupId);
+ if (group == null) {
+ return false;
+ }
+ return group.isBlocked();
+ }
+
int getPackagePriority(String pkg, int uid) {
return getOrCreateRecord(pkg, uid).priority;
}
@@ -514,9 +528,16 @@ public class RankingHelper implements RankingConfig {
}
final NotificationChannelGroup oldGroup = r.groups.get(group.getId());
if (!group.equals(oldGroup)) {
- // will log for new entries as well as name changes
+ // will log for new entries as well as name/description changes
MetricsLogger.action(getChannelGroupLog(group.getId(), pkg));
}
+ if (oldGroup != null) {
+ group.setChannels(oldGroup.getChannels());
+
+ if (fromTargetApp) {
+ group.setBlocked(oldGroup.isBlocked());
+ }
+ }
r.groups.put(group.getId(), group);
}
@@ -552,6 +573,9 @@ public class RankingHelper implements RankingConfig {
existing.setName(channel.getName().toString());
existing.setDescription(channel.getDescription());
existing.setBlockableSystem(channel.isBlockableSystem());
+ if (existing.getGroup() == null) {
+ existing.setGroup(channel.getGroup());
+ }
// Apps are allowed to downgrade channel importance if the user has not changed any
// fields on this channel yet.
@@ -684,6 +708,27 @@ public class RankingHelper implements RankingConfig {
}
}
+ public NotificationChannelGroup getNotificationChannelGroupWithChannels(String pkg,
+ int uid, String groupId, boolean includeDeleted) {
+ Preconditions.checkNotNull(pkg);
+ Record r = getRecord(pkg, uid);
+ if (r == null || groupId == null || !r.groups.containsKey(groupId)) {
+ return null;
+ }
+ NotificationChannelGroup group = r.groups.get(groupId).clone();
+ group.setChannels(new ArrayList<>());
+ int N = r.channels.size();
+ for (int i = 0; i < N; i++) {
+ final NotificationChannel nc = r.channels.valueAt(i);
+ if (includeDeleted || !nc.isDeleted()) {
+ if (groupId.equals(nc.getGroup())) {
+ group.addChannel(nc);
+ }
+ }
+ }
+ return group;
+ }
+
public NotificationChannelGroup getNotificationChannelGroup(String groupId, String pkg,
int uid) {
Preconditions.checkNotNull(pkg);
@@ -710,6 +755,7 @@ public class RankingHelper implements RankingConfig {
NotificationChannelGroup ncg = groups.get(nc.getGroup());
if (ncg == null) {
ncg = r.groups.get(nc.getGroup()).clone();
+ ncg.setChannels(new ArrayList<>());
groups.put(nc.getGroup(), ncg);
}
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index 04d91f882d04..807c343d0d10 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -92,26 +92,10 @@ class IdmapManager {
return new File(getIdmapPath(overlayPackage.applicationInfo.getBaseCodePath())).isFile();
}
- boolean isDangerous(@NonNull final PackageInfo overlayPackage, final int userId) {
- // unused userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible
- return isDangerous(getIdmapPath(overlayPackage.applicationInfo.getBaseCodePath()));
- }
-
private String getIdmapPath(@NonNull final String baseCodePath) {
final StringBuilder sb = new StringBuilder("/data/resource-cache/");
sb.append(baseCodePath.substring(1).replace('/', '@'));
sb.append("@idmap");
return sb.toString();
}
-
- private boolean isDangerous(@NonNull final String idmapPath) {
- try (DataInputStream dis = new DataInputStream(new FileInputStream(idmapPath))) {
- final int magic = dis.readInt();
- final int version = dis.readInt();
- final int dangerous = dis.readInt();
- return dangerous != 0;
- } catch (IOException e) {
- return true;
- }
- }
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index db6e9749535b..c3957f432f4c 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -169,8 +169,9 @@ final class OverlayManagerServiceImpl {
}
final PackageInfo targetPackage = mPackageManager.getPackageInfo(packageName, userId);
- updateAllOverlaysForTarget(packageName, userId, targetPackage);
- mListener.onOverlaysChanged(packageName, userId);
+ if (updateAllOverlaysForTarget(packageName, userId, targetPackage)) {
+ mListener.onOverlaysChanged(packageName, userId);
+ }
}
void onTargetPackageChanged(@NonNull final String packageName, final int userId) {
@@ -210,7 +211,9 @@ final class OverlayManagerServiceImpl {
Slog.d(TAG, "onTargetPackageRemoved packageName=" + packageName + " userId=" + userId);
}
- updateAllOverlaysForTarget(packageName, userId, null);
+ if (updateAllOverlaysForTarget(packageName, userId, null)) {
+ mListener.onOverlaysChanged(packageName, userId);
+ }
}
/**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7032d6456007..1db99a54c6a4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -9433,6 +9433,15 @@ public class PackageManagerService extends IPackageManager.Stub
// throw an exception if we have an update to a system application, but, it's not more
// recent than the package we've already scanned
if (isUpdatedSystemPkg && !isUpdatedPkgBetter) {
+ // Set CPU Abis to application info.
+ if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0) {
+ final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, updatedPkg);
+ derivePackageAbi(pkg, scanFile, cpuAbiOverride, false, mAppLib32InstallDir);
+ } else {
+ pkg.applicationInfo.primaryCpuAbi = updatedPkg.primaryCpuAbiString;
+ pkg.applicationInfo.secondaryCpuAbi = updatedPkg.secondaryCpuAbiString;
+ }
+
throw new PackageManagerException(Log.WARN, "Package " + ps.name + " at "
+ scanFile + " ignored: updated version " + ps.versionCode
+ " better than this " + pkg.mVersionCode);
diff --git a/services/core/java/com/android/server/policy/AccessibilityShortcutController.java b/services/core/java/com/android/server/policy/AccessibilityShortcutController.java
index 0a8635d7210f..55c582ed47b4 100644
--- a/services/core/java/com/android/server/policy/AccessibilityShortcutController.java
+++ b/services/core/java/com/android/server/policy/AccessibilityShortcutController.java
@@ -24,6 +24,7 @@ import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.media.AudioAttributes;
import android.media.Ringtone;
@@ -138,13 +139,18 @@ public class AccessibilityShortcutController {
final int userId = ActivityManager.getCurrentUser();
final int dialogAlreadyShown = Settings.Secure.getIntForUser(
cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, userId);
+ // Use USAGE_ASSISTANCE_ACCESSIBILITY for TVs to ensure that TVs play the ringtone as they
+ // have less ways of providing feedback like vibration.
+ final int audioAttributesUsage = hasFeatureLeanback()
+ ? AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY
+ : AudioAttributes.USAGE_NOTIFICATION_EVENT;
// Play a notification tone
final Ringtone tone =
RingtoneManager.getRingtone(mContext, Settings.System.DEFAULT_NOTIFICATION_URI);
if (tone != null) {
tone.setAudioAttributes(new AudioAttributes.Builder()
- .setUsage(AudioAttributes.USAGE_NOTIFICATION_EVENT)
+ .setUsage(audioAttributesUsage)
.build());
tone.play();
}
@@ -254,6 +260,10 @@ public class AccessibilityShortcutController {
AccessibilityServiceInfo.FEEDBACK_ALL_MASK).contains(serviceInfo);
}
+ private boolean hasFeatureLeanback() {
+ return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+ }
+
// Class to allow mocking of static framework calls
public static class FrameworkObjectProvider {
public AccessibilityManager getAccessibilityManagerInstance(Context context) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 380a4f08385a..68913c3a887a 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3401,11 +3401,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (!down) {
cancelPreloadRecentApps();
- if (mHasFeatureLeanback) {
- // Clear flags
- mAccessibilityTvKey2Pressed = down;
- }
-
mHomePressed = false;
if (mHomeConsumed) {
mHomeConsumed = false;
@@ -3460,13 +3455,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
preloadRecentApps();
}
} else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
- if (mHasFeatureLeanback) {
- mAccessibilityTvKey2Pressed = down;
- if (interceptAccessibilityGestureTv()) {
- return -1;
- }
- }
-
if (!keyguardOn) {
handleLongPressOnHome(event.getDeviceId());
}
@@ -3633,11 +3621,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return 0;
} else if (mHasFeatureLeanback && interceptBugreportGestureTv(keyCode, down)) {
return -1;
- } else if (mHasFeatureLeanback && keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
- mAccessibilityTvKey1Pressed = down;
- if (interceptAccessibilityGestureTv()) {
- return -1;
- }
+ } else if (mHasFeatureLeanback && interceptAccessibilityGestureTv(keyCode, down)) {
+ return -1;
}
// Toggle Caps Lock on META-ALT.
@@ -3858,20 +3843,28 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/**
* TV only: recognizes a remote control gesture as Accessibility shortcut.
- * Shortcut: Long press (HOME + DPAD_CENTER)
+ * Shortcut: Long press (BACK + DPAD_DOWN)
*/
- private boolean interceptAccessibilityGestureTv() {
+ private boolean interceptAccessibilityGestureTv(int keyCode, boolean down) {
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ mAccessibilityTvKey1Pressed = down;
+ } else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
+ mAccessibilityTvKey2Pressed = down;
+ }
+
if (mAccessibilityTvKey1Pressed && mAccessibilityTvKey2Pressed) {
if (!mAccessibilityTvScheduled) {
mAccessibilityTvScheduled = true;
Message msg = Message.obtain(mHandler, MSG_ACCESSIBILITY_TV);
msg.setAsynchronous(true);
- mHandler.sendMessage(msg);
+ mHandler.sendMessageDelayed(msg,
+ ViewConfiguration.get(mContext).getAccessibilityShortcutKeyTimeout());
}
} else if (mAccessibilityTvScheduled) {
mHandler.removeMessages(MSG_ACCESSIBILITY_TV);
mAccessibilityTvScheduled = false;
}
+
return mAccessibilityTvScheduled;
}
@@ -7827,13 +7820,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case HapticFeedbackConstants.VIRTUAL_KEY:
return VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
case HapticFeedbackConstants.VIRTUAL_KEY_RELEASE:
- return VibrationEffect.get(VibrationEffect.EFFECT_TICK);
+ return VibrationEffect.get(VibrationEffect.EFFECT_TICK, false);
case HapticFeedbackConstants.KEYBOARD_PRESS: // == HapticFeedbackConstants.KEYBOARD_TAP
return VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
case HapticFeedbackConstants.KEYBOARD_RELEASE:
- return VibrationEffect.get(VibrationEffect.EFFECT_TICK);
+ return VibrationEffect.get(VibrationEffect.EFFECT_TICK, false);
case HapticFeedbackConstants.TEXT_HANDLE_MOVE:
- return VibrationEffect.get(VibrationEffect.EFFECT_TICK);
+ return VibrationEffect.get(VibrationEffect.EFFECT_TICK, false);
default:
return null;
}
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 0867a6c66b70..853e1b269c92 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -110,9 +110,6 @@ public final class ShutdownThread extends Thread {
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.build();
- private static final TimingsTraceLog SHUTDOWN_TIMINGS_LOG = new TimingsTraceLog(
- "ShutdownTiming", Trace.TRACE_TAG_SYSTEM_SERVER);
-
// Metrics that will be reported to tron after reboot
private static final ArrayMap<String, Long> TRON_METRICS = new ArrayMap<>();
@@ -368,8 +365,6 @@ public final class ShutdownThread extends Thread {
}
private static void beginShutdownSequence(Context context) {
- SHUTDOWN_TIMINGS_LOG.traceBegin("SystemServerShutdown");
- metricStarted(METRIC_SYSTEM_SERVER);
synchronized (sIsStartedGuard) {
if (sIsStarted) {
Log.d(TAG, "Shutdown sequence already running, returning.");
@@ -426,6 +421,10 @@ public final class ShutdownThread extends Thread {
* Shuts off power regardless of radio and bluetooth state if the alloted time has passed.
*/
public void run() {
+ TimingsTraceLog shutdownTimingLog = newTimingsLog();
+ shutdownTimingLog.traceBegin("SystemServerShutdown");
+ metricStarted(METRIC_SYSTEM_SERVER);
+
BroadcastReceiver br = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
// We don't allow apps to cancel this, so ignore the result.
@@ -452,7 +451,7 @@ public final class ShutdownThread extends Thread {
}
metricStarted(METRIC_SEND_BROADCAST);
- SHUTDOWN_TIMINGS_LOG.traceBegin("SendShutdownBroadcast");
+ shutdownTimingLog.traceBegin("SendShutdownBroadcast");
Log.i(TAG, "Sending shutdown broadcast...");
// First send the high-level shut down broadcast.
@@ -484,11 +483,11 @@ public final class ShutdownThread extends Thread {
if (mRebootHasProgressBar) {
sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null);
}
- SHUTDOWN_TIMINGS_LOG.traceEnd(); // SendShutdownBroadcast
+ shutdownTimingLog.traceEnd(); // SendShutdownBroadcast
metricEnded(METRIC_SEND_BROADCAST);
Log.i(TAG, "Shutting down activity manager...");
- SHUTDOWN_TIMINGS_LOG.traceBegin("ShutdownActivityManager");
+ shutdownTimingLog.traceBegin("ShutdownActivityManager");
metricStarted(METRIC_AM);
final IActivityManager am =
@@ -502,11 +501,11 @@ public final class ShutdownThread extends Thread {
if (mRebootHasProgressBar) {
sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null);
}
- SHUTDOWN_TIMINGS_LOG.traceEnd();// ShutdownActivityManager
+ shutdownTimingLog.traceEnd();// ShutdownActivityManager
metricEnded(METRIC_AM);
Log.i(TAG, "Shutting down package manager...");
- SHUTDOWN_TIMINGS_LOG.traceBegin("ShutdownPackageManager");
+ shutdownTimingLog.traceBegin("ShutdownPackageManager");
metricStarted(METRIC_PM);
final PackageManagerService pm = (PackageManagerService)
@@ -517,17 +516,17 @@ public final class ShutdownThread extends Thread {
if (mRebootHasProgressBar) {
sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
}
- SHUTDOWN_TIMINGS_LOG.traceEnd(); // ShutdownPackageManager
+ shutdownTimingLog.traceEnd(); // ShutdownPackageManager
metricEnded(METRIC_PM);
// Shutdown radios.
- SHUTDOWN_TIMINGS_LOG.traceBegin("ShutdownRadios");
+ shutdownTimingLog.traceBegin("ShutdownRadios");
metricStarted(METRIC_RADIOS);
shutdownRadios(MAX_RADIO_WAIT_TIME);
if (mRebootHasProgressBar) {
sInstance.setRebootProgress(RADIO_STOP_PERCENT, null);
}
- SHUTDOWN_TIMINGS_LOG.traceEnd(); // ShutdownRadios
+ shutdownTimingLog.traceEnd(); // ShutdownRadios
metricEnded(METRIC_RADIOS);
// Shutdown StorageManagerService to ensure media is in a safe state
@@ -539,7 +538,7 @@ public final class ShutdownThread extends Thread {
};
Log.i(TAG, "Shutting down StorageManagerService");
- SHUTDOWN_TIMINGS_LOG.traceBegin("ShutdownStorageManager");
+ shutdownTimingLog.traceBegin("ShutdownStorageManager");
metricStarted(METRIC_SM);
// Set initial variables and time out time.
@@ -575,7 +574,7 @@ public final class ShutdownThread extends Thread {
}
}
}
- SHUTDOWN_TIMINGS_LOG.traceEnd(); // ShutdownStorageManager
+ shutdownTimingLog.traceEnd(); // ShutdownStorageManager
metricEnded(METRIC_SM);
if (mRebootHasProgressBar) {
@@ -586,15 +585,27 @@ public final class ShutdownThread extends Thread {
uncrypt();
}
+ shutdownTimingLog.traceEnd(); // SystemServerShutdown
+ metricEnded(METRIC_SYSTEM_SERVER);
+ saveMetrics(mReboot);
rebootOrShutdown(mContext, mReboot, mReason);
}
+ private static TimingsTraceLog newTimingsLog() {
+ return new TimingsTraceLog("ShutdownTiming", Trace.TRACE_TAG_SYSTEM_SERVER);
+ }
+
private static void metricStarted(String metricKey) {
- TRON_METRICS.put(metricKey, -1 * SystemClock.elapsedRealtime());
+ synchronized (TRON_METRICS) {
+ TRON_METRICS.put(metricKey, -1 * SystemClock.elapsedRealtime());
+ }
}
private static void metricEnded(String metricKey) {
- TRON_METRICS.put(metricKey, SystemClock.elapsedRealtime() + TRON_METRICS.get(metricKey));
+ synchronized (TRON_METRICS) {
+ TRON_METRICS
+ .put(metricKey, SystemClock.elapsedRealtime() + TRON_METRICS.get(metricKey));
+ }
}
private void setRebootProgress(final int progress, final CharSequence message) {
@@ -618,6 +629,7 @@ public final class ShutdownThread extends Thread {
final boolean[] done = new boolean[1];
Thread t = new Thread() {
public void run() {
+ TimingsTraceLog shutdownTimingsTraceLog = newTimingsLog();
boolean nfcOff;
boolean bluetoothReadyForShutdown;
boolean radioOff;
@@ -693,7 +705,7 @@ public final class ShutdownThread extends Thread {
if (bluetoothReadyForShutdown) {
Log.i(TAG, "Bluetooth turned off.");
metricEnded(METRIC_BT);
- SHUTDOWN_TIMINGS_LOG
+ shutdownTimingsTraceLog
.logDuration("ShutdownBt", TRON_METRICS.get(METRIC_BT));
}
}
@@ -707,7 +719,7 @@ public final class ShutdownThread extends Thread {
if (radioOff) {
Log.i(TAG, "Radio turned off.");
metricEnded(METRIC_RADIO);
- SHUTDOWN_TIMINGS_LOG
+ shutdownTimingsTraceLog
.logDuration("ShutdownRadio", TRON_METRICS.get(METRIC_RADIO));
}
}
@@ -721,7 +733,7 @@ public final class ShutdownThread extends Thread {
if (nfcOff) {
Log.i(TAG, "NFC turned off.");
metricEnded(METRIC_NFC);
- SHUTDOWN_TIMINGS_LOG
+ shutdownTimingsTraceLog
.logDuration("ShutdownNfc", TRON_METRICS.get(METRIC_NFC));
}
}
@@ -757,9 +769,6 @@ public final class ShutdownThread extends Thread {
* @param reason reason for reboot/shutdown
*/
public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
- SHUTDOWN_TIMINGS_LOG.traceEnd(); // SystemServerShutdown
- metricEnded(METRIC_SYSTEM_SERVER);
- saveMetrics(reboot);
if (reboot) {
Log.i(TAG, "Rebooting, reason: " + reason);
PowerManagerService.lowLevelReboot(reason);
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index f6f5341ff0a9..b963561dfd3c 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -280,14 +280,6 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
Slog.v(TAG, "Crop done; invoking completion callback");
}
wallpaper.imageWallpaperPending = false;
- if (wallpaper.setComplete != null) {
- try {
- wallpaper.setComplete.onWallpaperChanged();
- } catch (RemoteException e) {
- // if this fails we don't really care; the setting app may just
- // have crashed and that sort of thing is a fact of life.
- }
- }
if (sysWallpaperChanged) {
// If this was the system wallpaper, rebind...
bindWallpaperComponentLocked(mImageWallpaper, true,
@@ -311,6 +303,16 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
}
saveSettingsLocked(wallpaper.userId);
+
+ // Publish completion *after* we've persisted the changes
+ if (wallpaper.setComplete != null) {
+ try {
+ wallpaper.setComplete.onWallpaperChanged();
+ } catch (RemoteException e) {
+ // if this fails we don't really care; the setting app may just
+ // have crashed and that sort of thing is a fact of life.
+ }
+ }
}
}
}
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index c2edc04db2e1..c76b90593ab3 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -450,7 +450,7 @@ public class AppWindowAnimator {
return isAnimating;
}
- void dump(PrintWriter pw, String prefix, boolean dumpAll) {
+ void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken);
pw.print(prefix); pw.print("mAnimator="); pw.println(mAnimator);
pw.print(prefix); pw.print("freezingScreen="); pw.print(freezingScreen);
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index ebd82e3d7704..66e0a152e09b 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -321,8 +321,7 @@ public class AppWindowContainerController
}
}
- public void setVisibility(boolean visible, boolean visibleIgnoringKeyguard,
- boolean deferHidingClient) {
+ public void setVisibility(boolean visible, boolean deferHidingClient) {
synchronized(mWindowMap) {
if (mContainer == null) {
Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
@@ -361,16 +360,11 @@ public class AppWindowContainerController
wtoken.hiddenRequested = !visible;
wtoken.mDeferHidingClient = deferHidingClient;
- if (!visibleIgnoringKeyguard) {
- mService.mUnknownAppVisibilityController.appRemovedOrHidden(wtoken);
- }
-
if (!visible) {
// If the app is dead while it was visible, we kept its dead window on screen.
// Now that the app is going invisible, we can remove it. It will be restarted
// if made visible again.
wtoken.removeDeadWindows();
- wtoken.setVisibleBeforeClientHidden();
} else {
if (!mService.mAppTransition.isTransitionSet()
&& mService.mAppTransition.isReady()) {
@@ -733,35 +727,6 @@ public class AppWindowContainerController
}
}
- /**
- * Takes a snapshot of the screen. In landscape mode this grabs the whole screen.
- * In portrait mode, it grabs the full screenshot.
- *
- * @param displayId the Display to take a screenshot of.
- * @param width the width of the target bitmap
- * @param height the height of the target bitmap
- * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
- */
- public Bitmap screenshotApplications(int displayId, int width, int height, float frameScale) {
- try {
- Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications");
- final DisplayContent dc;
- synchronized(mWindowMap) {
- dc = mRoot.getDisplayContentOrCreate(displayId);
- if (dc == null) {
- if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot of " + mToken
- + ": returning null. No Display for displayId=" + displayId);
- return null;
- }
- }
- return dc.screenshotApplications(mToken.asBinder(), width, height,
- false /* includeFullDisplay */, frameScale, Bitmap.Config.RGB_565,
- false /* wallpaperOnly */, false /* includeDecor */);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
- }
- }
-
void reportStartingWindowDrawn() {
mHandler.sendMessage(mHandler.obtainMessage(H.NOTIFY_STARTING_WINDOW_DRAWN));
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 7545a10602a6..f70035ca9c92 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -78,8 +78,6 @@ import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.ArrayList;
-import static android.os.Build.VERSION_CODES.O;
-
class AppTokenList extends ArrayList<AppWindowToken> {
}
@@ -126,14 +124,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
// case do not clear allDrawn until the animation completes.
boolean deferClearAllDrawn;
- /**
- * These are to track the app's real drawing status if there were no saved surfaces.
- * @see #updateDrawnWindowStates
- */
- boolean allDrawnExcludingSaved;
- private int mNumInterestingWindowsExcludingSaved;
- private int mNumDrawnWindowsExcludingSaved;
-
// Is this window's surface needed? This is almost like hidden, except
// it will sometimes be true a little earlier: when the token has
// been shown, but is still waiting for its app transition to execute
@@ -372,10 +362,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
boolean runningAppAnimation = false;
+ if (mAppAnimator.animation == AppWindowAnimator.sDummyAnimation) {
+ mAppAnimator.setNullAnimation();
+ }
if (transit != AppTransition.TRANSIT_UNSET) {
- if (mAppAnimator.animation == AppWindowAnimator.sDummyAnimation) {
- mAppAnimator.setNullAnimation();
- }
if (mService.applyAnimationLocked(this, lp, transit, visible, isVoiceInteraction)) {
delayed = runningAppAnimation = true;
}
@@ -690,107 +680,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
}
}
- /**
- * Checks whether we should save surfaces for this app.
- *
- * @return true if the surfaces should be saved, false otherwise.
- */
- boolean shouldSaveSurface() {
- // We want to save surface if the app's windows are "allDrawn".
- // (If we started entering animation early with saved surfaces, allDrawn
- // should have been restored to true. So we'll save again in that case
- // even if app didn't actually finish drawing.)
- return allDrawn;
- }
-
- private boolean canRestoreSurfaces() {
- for (int i = mChildren.size() -1; i >= 0; i--) {
- final WindowState w = mChildren.get(i);
- if (w.canRestoreSurface()) {
- return true;
- }
- }
- return false;
- }
-
- private void clearWasVisibleBeforeClientHidden() {
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState w = mChildren.get(i);
- w.clearWasVisibleBeforeClientHidden();
- }
- }
-
- /**
- * Whether the app has some window that is invisible in layout, but
- * animating with saved surface.
- */
- boolean isAnimatingInvisibleWithSavedSurface() {
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState w = mChildren.get(i);
- if (w.isAnimatingInvisibleWithSavedSurface()) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Hide all window surfaces that's still invisible in layout but animating
- * with a saved surface, and mark them destroying.
- */
- void stopUsingSavedSurfaceLocked() {
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState w = mChildren.get(i);
- w.stopUsingSavedSurface();
- }
- destroySurfaces();
- }
-
- void markSavedSurfaceExiting() {
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState w = mChildren.get(i);
- w.markSavedSurfaceExiting();
- }
- }
-
- void restoreSavedSurfaceForInterestingWindows() {
- if (!canRestoreSurfaces()) {
- clearWasVisibleBeforeClientHidden();
- return;
- }
-
- // Check if all interesting windows are drawn and we can mark allDrawn=true.
- int interestingNotDrawn = -1;
-
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState w = mChildren.get(i);
- interestingNotDrawn = w.restoreSavedSurfaceForInterestingWindow();
- }
-
- if (!allDrawn) {
- allDrawn = (interestingNotDrawn == 0);
- if (allDrawn) {
- mService.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN, token).sendToTarget();
- }
- }
- clearWasVisibleBeforeClientHidden();
-
- if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG,
- "restoreSavedSurfaceForInterestingWindows: " + this + " allDrawn=" + allDrawn
- + " interestingNotDrawn=" + interestingNotDrawn);
- }
-
- void destroySavedSurfaces() {
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- final WindowState win = mChildren.get(i);
- win.destroySavedSurface();
- }
- }
-
void clearAllDrawn() {
allDrawn = false;
deferClearAllDrawn = false;
- allDrawnExcludingSaved = false;
}
Task getTask() {
@@ -1388,8 +1280,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
private boolean allDrawnStatesConsidered() {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState child = mChildren.get(i);
- if (child.mightAffectAllDrawn(false /*visibleOnly*/ )
- && !child.getDrawnStateEvaluated()) {
+ if (child.mightAffectAllDrawn() && !child.getDrawnStateEvaluated()) {
return false;
}
}
@@ -1429,23 +1320,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
}
}
}
-
- if (!allDrawnExcludingSaved) {
- int numInteresting = mNumInterestingWindowsExcludingSaved;
- if (numInteresting > 0 && mNumDrawnWindowsExcludingSaved >= numInteresting) {
- if (DEBUG_VISIBILITY) Slog.v(TAG, "allDrawnExcludingSaved: " + this
- + " interesting=" + numInteresting
- + " drawn=" + mNumDrawnWindowsExcludingSaved);
- allDrawnExcludingSaved = true;
- if (mDisplayContent != null) {
- mDisplayContent.setLayoutNeeded();
- }
- if (isAnimatingInvisibleWithSavedSurface()
- && !mService.mFinishedEarlyAnim.contains(this)) {
- mService.mFinishedEarlyAnim.add(this);
- }
- }
- }
}
/**
@@ -1462,15 +1336,13 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
+ " allDrawn=" + allDrawn + " freezingScreen=" + mAppAnimator.freezingScreen);
}
- if (allDrawn && allDrawnExcludingSaved && !mAppAnimator.freezingScreen) {
+ if (allDrawn && !mAppAnimator.freezingScreen) {
return false;
}
if (mLastTransactionSequence != mService.mTransactionSequence) {
mLastTransactionSequence = mService.mTransactionSequence;
mNumInterestingWindows = mNumDrawnWindows = 0;
- mNumInterestingWindowsExcludingSaved = 0;
- mNumDrawnWindowsExcludingSaved = 0;
startingDisplayed = false;
}
@@ -1478,7 +1350,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
boolean isInterestingAndDrawn = false;
- if (!allDrawn && w.mightAffectAllDrawn(false /* visibleOnly */)) {
+ if (!allDrawn && w.mightAffectAllDrawn()) {
if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
+ ", isAnimationSet=" + winAnimator.isAnimationSet());
@@ -1513,23 +1385,6 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
}
}
- if (!allDrawnExcludingSaved && w.mightAffectAllDrawn(true /* visibleOnly */)) {
- if (w != startingWindow && w.isInteresting()) {
- mNumInterestingWindowsExcludingSaved++;
- if (w.isDrawnLw() && !w.isAnimatingWithSavedSurface()) {
- mNumDrawnWindowsExcludingSaved++;
-
- if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
- "tokenMayBeDrawnExcludingSaved: " + this + " w=" + w
- + " numInteresting=" + mNumInterestingWindowsExcludingSaved
- + " freezingScreen=" + mAppAnimator.freezingScreen
- + " mAppFreezing=" + w.mAppFreezing);
-
- isInterestingAndDrawn = true;
- }
- }
- }
-
return isInterestingAndDrawn;
}
@@ -1763,6 +1618,9 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
if (mRemovingFromDisplay) {
pw.println(prefix + "mRemovingFromDisplay=" + mRemovingFromDisplay);
}
+ if (mAppAnimator.isAnimating()) {
+ mAppAnimator.dump(pw, prefix + " ");
+ }
}
@Override
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index cff2fadd7649..7953ee430934 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -21,7 +21,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import android.animation.AnimationHandler;
-import android.animation.AnimationHandler.AnimationFrameCallbackProvider;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
@@ -32,13 +31,11 @@ import android.os.IBinder;
import android.os.Debug;
import android.util.ArrayMap;
import android.util.Slog;
-import android.view.Choreographer;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.view.WindowManagerInternal;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -142,9 +139,6 @@ public class BoundsAnimationController {
// True if this this animation was canceled and will be replaced the another animation from
// the same {@link #BoundsAnimationTarget} target.
private boolean mSkipFinalResize;
- // True if this animation replaced a previous animation of the same
- // {@link #BoundsAnimationTarget} target.
- private final boolean mSkipAnimationStart;
// True if this animation was canceled by the user, not as a part of a replacing animation
private boolean mSkipAnimationEnd;
@@ -159,6 +153,7 @@ public class BoundsAnimationController {
// Whether to schedule PiP mode changes on animation start/end
private @SchedulePipModeChangedState int mSchedulePipModeChangedState;
+ private @SchedulePipModeChangedState int mPrevSchedulePipModeChangedState;
// Depending on whether we are animating from
// a smaller to a larger size
@@ -171,14 +166,14 @@ public class BoundsAnimationController {
BoundsAnimator(BoundsAnimationTarget target, Rect from, Rect to,
@SchedulePipModeChangedState int schedulePipModeChangedState,
- boolean moveFromFullscreen, boolean moveToFullscreen,
- boolean replacingExistingAnimation) {
+ @SchedulePipModeChangedState int prevShedulePipModeChangedState,
+ boolean moveFromFullscreen, boolean moveToFullscreen) {
super();
mTarget = target;
mFrom.set(from);
mTo.set(to);
- mSkipAnimationStart = replacingExistingAnimation;
mSchedulePipModeChangedState = schedulePipModeChangedState;
+ mPrevSchedulePipModeChangedState = prevShedulePipModeChangedState;
mMoveFromFullscreen = moveFromFullscreen;
mMoveToFullscreen = moveToFullscreen;
addUpdateListener(this);
@@ -200,7 +195,7 @@ public class BoundsAnimationController {
@Override
public void onAnimationStart(Animator animation) {
if (DEBUG) Slog.d(TAG, "onAnimationStart: mTarget=" + mTarget
- + " mSkipAnimationStart=" + mSkipAnimationStart
+ + " mPrevSchedulePipModeChangedState=" + mPrevSchedulePipModeChangedState
+ " mSchedulePipModeChangedState=" + mSchedulePipModeChangedState);
mFinishAnimationAfterTransition = false;
mTmpRect.set(mFrom.left, mFrom.top, mFrom.left + mFrozenTaskWidth,
@@ -210,18 +205,26 @@ public class BoundsAnimationController {
// running
updateBooster();
- // Ensure that we have prepared the target for animation before
- // we trigger any size changes, so it can swap surfaces
- // in to appropriate modes, or do as it wishes otherwise.
- if (!mSkipAnimationStart) {
+ // Ensure that we have prepared the target for animation before we trigger any size
+ // changes, so it can swap surfaces in to appropriate modes, or do as it wishes
+ // otherwise.
+ if (mPrevSchedulePipModeChangedState == NO_PIP_MODE_CHANGED_CALLBACKS) {
mTarget.onAnimationStart(mSchedulePipModeChangedState ==
- SCHEDULE_PIP_MODE_CHANGED_ON_START);
+ SCHEDULE_PIP_MODE_CHANGED_ON_START, false /* forceUpdate */);
// When starting an animation from fullscreen, pause here and wait for the
// windows-drawn signal before we start the rest of the transition down into PiP.
if (mMoveFromFullscreen) {
pause();
}
+ } else if (mPrevSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_END &&
+ mSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START) {
+ // We are replacing a running animation into PiP, but since it hasn't completed, the
+ // client will not currently receive any picture-in-picture mode change callbacks.
+ // However, we still need to report to them that they are leaving PiP, so this will
+ // force an update via a mode changed callback.
+ mTarget.onAnimationStart(true /* schedulePipModeChangedCallback */,
+ true /* forceUpdate */);
}
// Immediately update the task bounds if they have to become larger, but preserve
@@ -388,6 +391,8 @@ public class BoundsAnimationController {
boolean moveFromFullscreen, boolean moveToFullscreen) {
final BoundsAnimator existing = mRunningAnimations.get(target);
final boolean replacing = existing != null;
+ @SchedulePipModeChangedState int prevSchedulePipModeChangedState =
+ NO_PIP_MODE_CHANGED_CALLBACKS;
if (DEBUG) Slog.d(TAG, "animateBounds: target=" + target + " from=" + from + " to=" + to
+ " schedulePipModeChangedState=" + schedulePipModeChangedState
@@ -403,6 +408,9 @@ public class BoundsAnimationController {
return existing;
}
+ // Save the previous state
+ prevSchedulePipModeChangedState = existing.mSchedulePipModeChangedState;
+
// Update the PiP callback states if we are replacing the animation
if (existing.mSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START) {
if (schedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START) {
@@ -428,7 +436,8 @@ public class BoundsAnimationController {
existing.cancel();
}
final BoundsAnimator animator = new BoundsAnimator(target, from, to,
- schedulePipModeChangedState, moveFromFullscreen, moveToFullscreen, replacing);
+ schedulePipModeChangedState, prevSchedulePipModeChangedState,
+ moveFromFullscreen, moveToFullscreen);
mRunningAnimations.put(target, animator);
animator.setFloatValues(0f, 1f);
animator.setDuration((animationDuration != -1 ? animationDuration
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationTarget.java b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java
index 8b1bf7bf77dc..647a2d6deac6 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationTarget.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java
@@ -31,7 +31,7 @@ interface BoundsAnimationTarget {
* @param schedulePipModeChangedCallback whether or not to schedule the PiP mode changed
* callbacks
*/
- void onAnimationStart(boolean schedulePipModeChangedCallback);
+ void onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate);
/**
* Sets the size of the target (without any intermediate steps, like scheduling animation)
diff --git a/services/core/java/com/android/server/wm/ConfigurationContainer.java b/services/core/java/com/android/server/wm/ConfigurationContainer.java
index ace40c1f1e73..21b67f1f9821 100644
--- a/services/core/java/com/android/server/wm/ConfigurationContainer.java
+++ b/services/core/java/com/android/server/wm/ConfigurationContainer.java
@@ -16,6 +16,13 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.activityTypeToString;
+
import android.app.WindowConfiguration;
import android.content.res.Configuration;
@@ -41,6 +48,9 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
*/
private Configuration mMergedOverrideConfiguration = new Configuration();
+ // TODO: Can't have ag/2592611 soon enough!
+ private final Configuration mTmpConfig = new Configuration();
+
/**
* Returns full configuration applied to this configuration container.
* This method should be used for getting settings applied in each particular level of the
@@ -120,10 +130,56 @@ public abstract class ConfigurationContainer<E extends ConfigurationContainer> {
}
/** Sets the windowing mode for the configuration container. */
- public void setWindowingMode(/* @WindowConfiguration.WindowingMode...triggers Jack compiler bug...*/
- int windowingMode) {
- mOverrideConfiguration.windowConfiguration.setWindowingMode(windowingMode);
- onOverrideConfigurationChanged(mOverrideConfiguration);
+ public void setWindowingMode(/*@WindowConfiguration.WindowingMode*/ int windowingMode) {
+ mTmpConfig.setTo(getOverrideConfiguration());
+ mTmpConfig.windowConfiguration.setWindowingMode(windowingMode);
+ onOverrideConfigurationChanged(mTmpConfig);
+ }
+
+ /** Returns the activity type associated with the the configuration container. */
+ /*@WindowConfiguration.ActivityType*/
+ public int getActivityType() {
+ return mFullConfiguration.windowConfiguration.getActivityType();
+ }
+
+ /** Sets the activity type to associate with the configuration container. */
+ public void setActivityType(/*@WindowConfiguration.ActivityType*/ int activityType) {
+ int currentActivityType = getActivityType();
+ if (currentActivityType == activityType) {
+ return;
+ }
+ if (currentActivityType != ACTIVITY_TYPE_UNDEFINED) {
+ throw new IllegalStateException("Can't change activity type once set: " + this
+ + " activityType=" + activityTypeToString(activityType));
+ }
+ mTmpConfig.setTo(getOverrideConfiguration());
+ mTmpConfig.windowConfiguration.setActivityType(activityType);
+ onOverrideConfigurationChanged(mTmpConfig);
+ }
+
+ public boolean isActivityTypeHome() {
+ return getActivityType() == ACTIVITY_TYPE_HOME;
+ }
+
+ public boolean isActivityTypeRecents() {
+ return getActivityType() == ACTIVITY_TYPE_RECENTS;
+ }
+
+ public boolean isActivityTypeAssistant() {
+ return getActivityType() == ACTIVITY_TYPE_ASSISTANT;
+ }
+
+ public boolean isActivityTypeStandard() {
+ return getActivityType() == ACTIVITY_TYPE_STANDARD;
+ }
+
+ public boolean hasCompatibleActivityType(ConfigurationContainer other) {
+ /*@WindowConfiguration.ActivityType*/ int thisType = getActivityType();
+ /*@WindowConfiguration.ActivityType*/ int otherType = other.getActivityType();
+
+ return thisType == otherType
+ || thisType == ACTIVITY_TYPE_UNDEFINED
+ || otherType == ACTIVITY_TYPE_UNDEFINED;
}
/**
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index af8620269370..d74e48253132 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1084,10 +1084,6 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
}
forAllWindows(w -> {
- // Discard surface after orientation change, these can't be reused.
- if (w.mAppToken != null) {
- w.mAppToken.destroySavedSurfaces();
- }
if (w.mHasSurface && !rotateSeamlessly) {
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Set mOrientationChanging of " + w);
w.setOrientationChanging(true);
@@ -2177,8 +2173,9 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
- pw.println(subPrefix + "deferred=" + mDeferredRemoval
+ pw.print(subPrefix + "deferred=" + mDeferredRemoval
+ " mLayoutNeeded=" + mLayoutNeeded);
+ pw.println(" mTouchExcludeRegion=" + mTouchExcludeRegion);
pw.println();
pw.println(prefix + "Application tokens in top down Z order:");
@@ -2354,8 +2351,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
} else if (w.mAppToken != null && w.mAppToken.isClientHidden()) {
Slog.w(TAG_WM, "LEAKED SURFACE (app token hidden): "
+ w + " surface=" + wsa.mSurfaceController
- + " token=" + w.mAppToken
- + " saved=" + w.hasSavedSurface());
+ + " token=" + w.mAppToken);
if (SHOW_TRANSACTIONS) logSurface(w, "LEAK DESTROY", false);
wsa.destroySurface();
mTmpWindow = w;
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index ce21991e1b3e..030b986ef0e9 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -608,8 +608,7 @@ public class DockedStackDividerController implements DimLayerUser {
final TaskStack fullscreenStack =
mDisplayContent.getStackById(FULLSCREEN_WORKSPACE_STACK_ID);
final boolean homeVisible = homeTask.getTopVisibleAppToken() != null;
- final boolean homeBehind = (fullscreenStack != null && fullscreenStack.isVisible())
- || (homeStack.hasMultipleTaskWithHomeTaskNotTop());
+ final boolean homeBehind = fullscreenStack != null && fullscreenStack.isVisible();
setMinimizedDockedStack(homeVisible && !homeBehind, animate);
}
diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowController.java b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
index 135f4000dd81..b5c9b99b35d6 100644
--- a/services/core/java/com/android/server/wm/PinnedStackWindowController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
@@ -204,10 +204,12 @@ public class PinnedStackWindowController extends StackWindowController {
*/
/** Calls directly into activity manager so window manager lock shouldn't held. */
- public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds) {
+ public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
+ boolean forceUpdate) {
if (mListener != null) {
PinnedStackWindowListener listener = (PinnedStackWindowListener) mListener;
- listener.updatePictureInPictureModeForPinnedStackAnimation(targetStackBounds);
+ listener.updatePictureInPictureModeForPinnedStackAnimation(targetStackBounds,
+ forceUpdate);
}
}
}
diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowListener.java b/services/core/java/com/android/server/wm/PinnedStackWindowListener.java
index 12b9c1f0c552..33e8a60329bf 100644
--- a/services/core/java/com/android/server/wm/PinnedStackWindowListener.java
+++ b/services/core/java/com/android/server/wm/PinnedStackWindowListener.java
@@ -28,5 +28,6 @@ public interface PinnedStackWindowListener extends StackWindowListener {
* Called when the stack container pinned stack animation will change the picture-in-picture
* mode. This is a direct call into ActivityManager.
*/
- default void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds) {}
+ default void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
+ boolean forceUpdate) {}
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 05ef1a5fe106..54dd19961999 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -18,7 +18,6 @@ package com.android.server.wm;
import android.content.res.Configuration;
import android.graphics.Rect;
-import android.hardware.display.DisplayManager;
import android.hardware.power.V1_0.PowerHint;
import android.os.Binder;
import android.os.Debug;
@@ -32,6 +31,7 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
+import android.util.ArraySet;
import android.util.EventLog;
import android.util.Slog;
import android.util.SparseIntArray;
@@ -665,19 +665,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
defaultDisplay.pendingLayoutChanges);
}
- for (i = mService.mResizingWindows.size() - 1; i >= 0; i--) {
- WindowState win = mService.mResizingWindows.get(i);
- if (win.mAppFreezing) {
- // Don't remove this window until rotation has completed.
- continue;
- }
- // Discard the saved surface if window size is changed, it can't be reused.
- if (win.mAppToken != null) {
- win.mAppToken.destroySavedSurfaces();
- }
- win.reportResized();
- mService.mResizingWindows.remove(i);
- }
+ final ArraySet<DisplayContent> touchExcludeRegionUpdateDisplays = handleResizingWindows();
if (DEBUG_ORIENTATION && mService.mDisplayFrozen) Slog.v(TAG,
"With display frozen, orientationChangeComplete=" + mOrientationChangeComplete);
@@ -704,7 +692,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
if (win.getDisplayContent().mWallpaperController.isWallpaperTarget(win)) {
wallpaperDestroyed = true;
}
- win.destroyOrSaveSurfaceUnchecked();
+ win.destroySurfaceUnchecked();
} while (i > 0);
mService.mDestroySurface.clear();
}
@@ -819,6 +807,16 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
mService.mInputMonitor.updateInputWindowsLw(false /*force*/);
}
mService.setFocusTaskRegionLocked(null);
+ if (touchExcludeRegionUpdateDisplays != null) {
+ final DisplayContent focusedDc = mService.mFocusedApp != null
+ ? mService.mFocusedApp.getDisplayContent() : null;
+ for (DisplayContent dc : touchExcludeRegionUpdateDisplays) {
+ // The focused DisplayContent was recalcuated in setFocusTaskRegionLocked
+ if (focusedDc != dc) {
+ dc.setTouchExcludeRegion(null /* focusedTask */);
+ }
+ }
+ }
// Check to see if we are now in a state where the screen should
// be enabled, because the window obscured flags have changed.
@@ -870,6 +868,33 @@ class RootWindowContainer extends WindowContainer<DisplayContent> {
}
/**
+ * Handles resizing windows during surface placement.
+ *
+ * @return A set of any DisplayContent whose touch exclude region needs to be recalculated due
+ * to a tap-exclude window resizing, or null if no such DisplayContents were found.
+ */
+ private ArraySet<DisplayContent> handleResizingWindows() {
+ ArraySet<DisplayContent> touchExcludeRegionUpdateSet = null;
+ for (int i = mService.mResizingWindows.size() - 1; i >= 0; i--) {
+ WindowState win = mService.mResizingWindows.get(i);
+ if (win.mAppFreezing) {
+ // Don't remove this window until rotation has completed.
+ continue;
+ }
+ win.reportResized();
+ mService.mResizingWindows.remove(i);
+ if (WindowManagerService.excludeWindowTypeFromTapOutTask(win.mAttrs.type)) {
+ final DisplayContent dc = win.getDisplayContent();
+ if (touchExcludeRegionUpdateSet == null) {
+ touchExcludeRegionUpdateSet = new ArraySet<>();
+ }
+ touchExcludeRegionUpdateSet.add(dc);
+ }
+ }
+ return touchExcludeRegionUpdateSet;
+ }
+
+ /**
* @param w WindowState this method is applied to.
* @param obscured True if there is a window on top of this obscuring the display.
* @param syswin System window?
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 60384f27d594..f57238e34694 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -97,27 +97,23 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
private boolean mDragResizing;
private int mDragResizeMode;
- private boolean mHomeTask;
-
private TaskDescription mTaskDescription;
// If set to true, the task will report that it is not in the floating
- // state regardless of it's stack affilation. As the floating state drives
+ // state regardless of it's stack affiliation. As the floating state drives
// production of content insets this can be used to preserve them across
// stack moves and we in fact do so when moving from full screen to pinned.
private boolean mPreserveNonFloatingState = false;
Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
- boolean homeTask, TaskDescription taskDescription,
- TaskWindowContainerController controller) {
+ TaskDescription taskDescription, TaskWindowContainerController controller) {
mTaskId = taskId;
mStack = stack;
mUserId = userId;
mService = service;
mResizeMode = resizeMode;
mSupportsPictureInPicture = supportsPictureInPicture;
- mHomeTask = homeTask;
setController(controller);
setBounds(bounds, overrideConfig);
mTaskDescription = taskDescription;
@@ -370,10 +366,6 @@ class Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerU
return isResizeable();
}
- boolean isHomeTask() {
- return mHomeTask;
- }
-
boolean resizeLocked(Rect bounds, Configuration overrideConfig, boolean forced) {
int boundsChanged = setBounds(bounds, overrideConfig);
if (forced) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index ecf9067b55c9..463240228fb6 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -16,8 +16,6 @@
package com.android.server.wm;
-import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS;
-
import static com.android.server.wm.TaskSnapshotPersister.DISABLE_FULL_SIZED_BITMAPS;
import static com.android.server.wm.TaskSnapshotPersister.REDUCED_SCALE;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -225,7 +223,7 @@ class TaskSnapshotController {
}
private boolean shouldDisableSnapshots() {
- return !ENABLE_TASK_SNAPSHOTS || mIsRunningOnWear || mIsRunningOnTv || mIsRunningOnIoT;
+ return mIsRunningOnWear || mIsRunningOnTv || mIsRunningOnIoT;
}
private Rect minRect(Rect rect1, Rect rect2) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index 1252aee14964..a2c9283a9b1e 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -333,7 +333,6 @@ class TaskSnapshotPersister {
}
boolean writeBuffer() {
- final File file = getBitmapFile(mTaskId, mUserId);
final Bitmap bitmap = Bitmap.createHardwareBitmap(mSnapshot.getSnapshot());
if (bitmap == null) {
Slog.e(TAG, "Invalid task snapshot hw bitmap");
@@ -361,6 +360,7 @@ class TaskSnapshotPersister {
return true;
}
+ final File file = getBitmapFile(mTaskId, mUserId);
try {
FileOutputStream fos = new FileOutputStream(file);
swBitmap.compress(JPEG, QUALITY, fos);
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 1a6e2c87e695..6ec7565ab156 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -18,18 +18,9 @@ package com.android.server.wm;
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
-import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.HOME_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
-import static android.app.WindowConfiguration.WINDOWING_MODE_DOCKED;
-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.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
@@ -52,7 +43,6 @@ import static com.android.server.wm.proto.StackProto.ID;
import static com.android.server.wm.proto.StackProto.TASKS;
import android.app.ActivityManager.StackId;
-import android.app.WindowConfiguration;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Region;
@@ -170,20 +160,10 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
}
Task findHomeTask() {
- if (mStackId != HOME_STACK_ID) {
+ if (!isActivityTypeHome() || mChildren.isEmpty()) {
return null;
}
-
- for (int i = mChildren.size() - 1; i >= 0; i--) {
- if (mChildren.get(i).isHomeTask()) {
- return mChildren.get(i);
- }
- }
- return null;
- }
-
- boolean hasMultipleTaskWithHomeTaskNotTop() {
- return mChildren.size() > 1 && !mChildren.get(mChildren.size() - 1).isHomeTask();
+ return mChildren.get(mChildren.size() - 1);
}
/**
@@ -1470,7 +1450,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
* small portion which the home stack currently is resized to.
*/
- if (task.isHomeTask() && isMinimizedDockAndHomeStackResizable()) {
+ if (task.isActivityTypeHome() && isMinimizedDockAndHomeStackResizable()) {
mDisplayContent.getLogicalDisplayRect(mTmpRect);
} else {
task.getDimBounds(mTmpRect);
@@ -1525,7 +1505,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
}
@Override // AnimatesBounds
- public void onAnimationStart(boolean schedulePipModeChangedCallback) {
+ public void onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate) {
// Hold the lock since this is called from the BoundsAnimator running on the UiThread
synchronized (mService.mWindowMap) {
mBoundsAnimatingRequested = false;
@@ -1550,9 +1530,11 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
final PinnedStackWindowController controller =
(PinnedStackWindowController) getController();
if (schedulePipModeChangedCallback && controller != null) {
- // We need to schedule the PiP mode change after the animation down, so use the
- // final bounds
- controller.updatePictureInPictureModeForPinnedStackAnimation(null);
+ // We need to schedule the PiP mode change before the animation up. It is possible
+ // in this case for the animation down to not have been completed, so always
+ // force-schedule and update to the client to ensure that it is notified that it
+ // is no longer in picture-in-picture mode
+ controller.updatePictureInPictureModeForPinnedStackAnimation(null, forceUpdate);
}
}
}
@@ -1580,7 +1562,7 @@ public class TaskStack extends WindowContainer<Task> implements DimLayer.DimLaye
// We need to schedule the PiP mode change after the animation down, so use the
// final bounds
controller.updatePictureInPictureModeForPinnedStackAnimation(
- mBoundsAnimationTarget);
+ mBoundsAnimationTarget, false /* forceUpdate */);
}
if (finalStackSize != null) {
diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerController.java b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
index 54a6cc01c831..d8929c9d80c2 100644
--- a/services/core/java/com/android/server/wm/TaskWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
@@ -51,18 +51,17 @@ public class TaskWindowContainerController
public TaskWindowContainerController(int taskId, TaskWindowContainerListener listener,
StackWindowController stackController, int userId, Rect bounds,
Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
- boolean homeTask, boolean toTop, boolean showForAllUsers,
- TaskDescription taskDescription) {
+ boolean toTop, boolean showForAllUsers, TaskDescription taskDescription) {
this(taskId, listener, stackController, userId, bounds, overrideConfig, resizeMode,
- supportsPictureInPicture, homeTask, toTop, showForAllUsers, taskDescription,
+ supportsPictureInPicture, toTop, showForAllUsers, taskDescription,
WindowManagerService.getInstance());
}
public TaskWindowContainerController(int taskId, TaskWindowContainerListener listener,
StackWindowController stackController, int userId, Rect bounds,
Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
- boolean homeTask, boolean toTop, boolean showForAllUsers,
- TaskDescription taskDescription, WindowManagerService service) {
+ boolean toTop, boolean showForAllUsers, TaskDescription taskDescription,
+ WindowManagerService service) {
super(listener, service);
mTaskId = taskId;
mHandler = new H(new WeakReference<>(this), service.mH.getLooper());
@@ -78,7 +77,7 @@ public class TaskWindowContainerController
}
EventLog.writeEvent(WM_TASK_CREATED, taskId, stack.mStackId);
final Task task = createTask(taskId, stack, userId, bounds, overrideConfig, resizeMode,
- supportsPictureInPicture, homeTask, taskDescription);
+ supportsPictureInPicture, taskDescription);
final int position = toTop ? POSITION_TOP : POSITION_BOTTOM;
// We only want to move the parents to the parents if we are creating this task at the
// top of its stack.
@@ -89,9 +88,9 @@ public class TaskWindowContainerController
@VisibleForTesting
Task createTask(int taskId, TaskStack stack, int userId, Rect bounds,
Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
- boolean homeTask, TaskDescription taskDescription) {
+ TaskDescription taskDescription) {
return new Task(taskId, stack, userId, mService, bounds, overrideConfig, resizeMode,
- supportsPictureInPicture, homeTask, taskDescription, this);
+ supportsPictureInPicture, taskDescription, this);
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 079ae40bcb48..c01ee31e8c1c 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -272,7 +272,6 @@ public class WindowAnimator {
mRemoveReplacedWindows = false;
}
- mService.stopUsingSavedSurfaceLocked();
mService.destroyPreservedSurfaceLocked();
mService.mWindowPlacerLocked.destroyPendingSurfaces();
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index bf79dfa15ea5..926719ddf318 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -363,13 +363,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
}
}
- void setVisibleBeforeClientHidden() {
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowContainer wc = mChildren.get(i);
- wc.setVisibleBeforeClientHidden();
- }
- }
-
/**
* Returns true if the container or one of its children as some content it can display or wants
* to display (e.g. app views or saved surface).
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 8e741c50c540..32ee51c8f751 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -445,13 +445,6 @@ public class WindowManagerService extends IWindowManager.Stub
final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<>();
/**
- * List of window tokens that have finished drawing their own windows and
- * no longer need to show any saved surfaces. Windows that's still showing
- * saved surfaces will be cleaned up after next animation pass.
- */
- final ArrayList<AppWindowToken> mFinishedEarlyAnim = new ArrayList<>();
-
- /**
* List of app window tokens that are waiting for replacing windows. If the
* replacement doesn't come in time the stale windows needs to be disposed of.
*/
@@ -2078,17 +2071,8 @@ public class WindowManagerService extends IWindowManager.Stub
winAnimator.mEnterAnimationPending = false;
winAnimator.mEnteringAnimation = false;
- final boolean usingSavedSurfaceBeforeVisible =
- oldVisibility != View.VISIBLE && win.isAnimatingWithSavedSurface();
- if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
- if (winAnimator.hasSurface() && !win.mAnimatingExit
- && usingSavedSurfaceBeforeVisible) {
- Slog.d(TAG, "Ignoring layout to invisible when using saved surface " + win);
- }
- }
- if (winAnimator.hasSurface() && !win.mAnimatingExit
- && !usingSavedSurfaceBeforeVisible) {
+ if (winAnimator.hasSurface() && !win.mAnimatingExit) {
if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Relayout invis " + win
+ ": mAnimatingExit=" + win.mAnimatingExit);
// If we are not currently running the exit animation, we
@@ -5374,14 +5358,6 @@ public class WindowManagerService extends IWindowManager.Stub
mDestroyPreservedSurface.clear();
}
- void stopUsingSavedSurfaceLocked() {
- for (int i = mFinishedEarlyAnim.size() - 1; i >= 0 ; i--) {
- final AppWindowToken wtoken = mFinishedEarlyAnim.get(i);
- wtoken.stopUsingSavedSurfaceLocked();
- }
- mFinishedEarlyAnim.clear();
- }
-
// -------------------------------------------------------------
// IWindowManager API
// -------------------------------------------------------------
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index f7ab534aa27a..e8e40a78554c 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -16,12 +16,10 @@
package com.android.server.wm;
-import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS;
import static android.app.ActivityManager.StackId;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.app.ActivityManager.isLowRamDeviceStatic;
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
@@ -38,7 +36,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
-import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
@@ -138,8 +135,8 @@ import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
import android.os.WorkSource;
-import android.util.MergedConfiguration;
import android.util.DisplayMetrics;
+import android.util.MergedConfiguration;
import android.util.Slog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -182,9 +179,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// to capture touch events in that area.
static final int RESIZE_HANDLE_WIDTH_IN_DP = 30;
- private static final boolean DEBUG_DISABLE_SAVING_SURFACES = false ||
- ENABLE_TASK_SNAPSHOTS;
-
final WindowManagerService mService;
final WindowManagerPolicy mPolicy;
final Context mContext;
@@ -521,15 +515,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
/** When true this window can be displayed on screens owther than mOwnerUid's */
private boolean mShowToOwnerOnly;
- // Whether the window has a saved surface from last pause, which can be
- // used to start an entering animation earlier.
- private boolean mSurfaceSaved = false;
-
- // Whether we're performing an entering animation with a saved surface. This flag is
- // true during the time we're showing a window with a previously saved surface. It's
- // cleared when surface is destroyed, saved, or re-drawn by the app.
- private boolean mAnimatingWithSavedSurface;
-
// Whether the window was visible when we set the app to invisible last time. WM uses
// this as a hint to restore the surface (if available) for early animation next time
// the app is brought visible.
@@ -585,8 +570,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
*/
boolean mSeamlesslyRotated = false;
- private static final Region sEmptyRegion = new Region();
-
/**
* Surface insets from the previous call to relayout(), used to track
* if we are changing the Surface insets.
@@ -1370,10 +1353,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
@Override
boolean hasContentToDisplay() {
- // If we're animating with a saved surface, we're already visible.
- // Return true so that the alpha doesn't get cleared.
- if (!mAppFreezing && isDrawnLw()
- && (mViewVisibility == View.VISIBLE || isAnimatingWithSavedSurface()
+ if (!mAppFreezing && isDrawnLw() && (mViewVisibility == View.VISIBLE
|| (mWinAnimator.isAnimationSet() && !mService.mAppTransition.isTransitionSet()))) {
return true;
}
@@ -1461,19 +1441,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
/**
* Whether this window's drawn state might affect the drawn states of the app token.
*
- * @param visibleOnly Whether we should consider only the windows that's currently
- * visible in layout. If true, windows that has not relayout to VISIBLE
- * would always return false.
- *
* @return true if the window should be considered while evaluating allDrawn flags.
*/
- boolean mightAffectAllDrawn(boolean visibleOnly) {
- final boolean isViewVisible = (mAppToken == null || !mAppToken.isClientHidden())
- && (mViewVisibility == View.VISIBLE) && !mWindowRemovalAllowed;
- return (isOnScreen() && (!visibleOnly || isViewVisible)
- || mWinAnimator.mAttrType == TYPE_BASE_APPLICATION
- || mWinAnimator.mAttrType == TYPE_DRAWN_APPLICATION)
- && !mAnimatingExit && !mDestroying;
+ boolean mightAffectAllDrawn() {
+ final boolean isAppType = mWinAnimator.mAttrType == TYPE_BASE_APPLICATION
+ || mWinAnimator.mAttrType == TYPE_DRAWN_APPLICATION;
+ return (isOnScreen() || isAppType) && !mAnimatingExit && !mDestroying;
}
/**
@@ -1667,10 +1640,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
@Override
void onResize() {
- // Some windows won't go through the resizing process, if they don't have a surface, so
- // destroy all saved surfaces here.
- destroySavedSurface();
-
final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
if (mHasSurface && !resizingWindows.contains(this)) {
if (DEBUG_RESIZE) Slog.d(TAG, "onResize: Resizing " + this);
@@ -1919,19 +1888,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return;
}
- if (isAnimatingWithSavedSurface() && !mAppToken.allDrawnExcludingSaved) {
- // We started enter animation early with a saved surface, now the app asks to remove
- // this window. If we remove it now and the app is not yet drawn, we'll show a
- // flicker. Delay the removal now until it's really drawn.
- if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM,
- "removeWindowLocked: delay removal of " + this + " due to early animation");
- // Do not set mAnimatingExit to true here, it will cause the surface to be hidden
- // immediately after the enter animation is done. If the app is not yet drawn then
- // it will show up as a flicker.
- setupWindowForRemoveOnExit();
- Binder.restoreCallingIdentity(origId);
- return;
- }
// If we are not currently running the exit animation, we need to see about starting one
wasVisible = isWinVisibleLw();
@@ -2634,10 +2590,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return mAnimatingExit || (mService.mClosingApps.contains(mAppToken));
}
- boolean isAnimatingWithSavedSurface() {
- return mAnimatingWithSavedSurface;
- }
-
@Override
boolean isAnimating() {
if (mWinAnimator.isAnimationSet() || mAnimatingExit) {
@@ -2646,48 +2598,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return super.isAnimating();
}
- boolean isAnimatingInvisibleWithSavedSurface() {
- if (mAnimatingWithSavedSurface
- && (mViewVisibility != View.VISIBLE || mWindowRemovalAllowed)) {
- return true;
- }
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowState c = mChildren.get(i);
- if (c.isAnimatingInvisibleWithSavedSurface()) {
- return true;
- }
- }
- return false;
- }
-
- void stopUsingSavedSurface() {
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowState c = mChildren.get(i);
- c.stopUsingSavedSurface();
- }
-
- if (!isAnimatingInvisibleWithSavedSurface()) {
- return;
- }
-
- if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.d(TAG, "stopUsingSavedSurface: " + this);
- clearAnimatingWithSavedSurface();
- mDestroying = true;
- mWinAnimator.hide("stopUsingSavedSurface");
- getDisplayContent().mWallpaperController.hideWallpapers(this);
- }
-
- void markSavedSurfaceExiting() {
- if (isAnimatingInvisibleWithSavedSurface()) {
- mAnimatingExit = true;
- mWinAnimator.mAnimating = true;
- }
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowState c = mChildren.get(i);
- c.markSavedSurfaceExiting();
- }
- }
-
void addWinAnimatorToList(ArrayList<WindowStateAnimator> animators) {
animators.add(mWinAnimator);
@@ -2726,25 +2636,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
}
}
- public void setVisibleBeforeClientHidden() {
- mWasVisibleBeforeClientHidden |=
- (mViewVisibility == View.VISIBLE || mAnimatingWithSavedSurface);
-
- super.setVisibleBeforeClientHidden();
- }
-
- public void clearWasVisibleBeforeClientHidden() {
- mWasVisibleBeforeClientHidden = false;
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowState c = mChildren.get(i);
- c.clearWasVisibleBeforeClientHidden();
- }
- }
-
- public boolean wasVisibleBeforeClientHidden() {
- return mWasVisibleBeforeClientHidden;
- }
-
void onStartFreezingScreen() {
mAppFreezing = true;
for (int i = mChildren.size() - 1; i >= 0; --i) {
@@ -2777,48 +2668,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
return true;
}
- private boolean shouldSaveSurface() {
- if (mWinAnimator.mSurfaceController == null) {
- // Don't bother if the surface controller is gone for any reason.
- return false;
- }
-
- if (!mWasVisibleBeforeClientHidden) {
- return false;
- }
-
- if ((mAttrs.flags & FLAG_SECURE) != 0) {
- // We don't save secure surfaces since their content shouldn't be shown while the app
- // isn't on screen and content might leak through during the transition animation with
- // saved surface.
- return false;
- }
-
- if (isLowRamDeviceStatic()) {
- // Don't save surfaces on Svelte devices.
- return false;
- }
-
- final Task task = getTask();
- final AppWindowToken taskTop = task.getTopVisibleAppToken();
- if (taskTop != null && taskTop != mAppToken) {
- // Don't save if the window is not the topmost window.
- return false;
- }
-
- if (mResizedWhileGone) {
- // Somebody resized our window while we were gone for layout, which means that the
- // client got an old size, so we have an outdated surface here.
- return false;
- }
-
- if (DEBUG_DISABLE_SAVING_SURFACES) {
- return false;
- }
-
- return mAppToken.shouldSaveSurface();
- }
-
boolean destroySurface(boolean cleanupOnResume, boolean appStopped) {
boolean destroyedSomething = false;
for (int i = mChildren.size() - 1; i >= 0; --i) {
@@ -2840,7 +2689,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
+ " win.mWindowRemovalAllowed=" + mWindowRemovalAllowed
+ " win.mRemoveOnExit=" + mRemoveOnExit);
if (!cleanupOnResume || mRemoveOnExit) {
- destroyOrSaveSurfaceUnchecked();
+ destroySurfaceUnchecked();
}
if (mRemoveOnExit) {
removeImmediately();
@@ -2858,156 +2707,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
// Destroy or save the application surface without checking
// various indicators of whether the client has released the surface.
// This is in general unsafe, and most callers should use {@link #destroySurface}
- void destroyOrSaveSurfaceUnchecked() {
- mSurfaceSaved = shouldSaveSurface();
- if (mSurfaceSaved) {
- if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
- Slog.v(TAG, "Saving surface: " + this);
- }
- // Previous user of the surface may have set a transparent region signaling a portion
- // doesn't need to be composited, so reset to default empty state.
- mSession.setTransparentRegion(mClient, sEmptyRegion);
-
- mWinAnimator.hide("saved surface");
- mWinAnimator.mDrawState = WindowStateAnimator.NO_SURFACE;
- setHasSurface(false);
- // The client should have disconnected at this point, but if it doesn't,
- // we need to make sure it's disconnected. Otherwise when we reuse the surface
- // the client can't reconnect to the buffer queue, and rendering will fail.
- if (mWinAnimator.mSurfaceController != null) {
- mWinAnimator.mSurfaceController.disconnectInTransaction();
- }
- mAnimatingWithSavedSurface = false;
- } else {
- mWinAnimator.destroySurfaceLocked();
- }
+ void destroySurfaceUnchecked() {
+ mWinAnimator.destroySurfaceLocked();
+
// Clear animating flags now, since the surface is now gone. (Note this is true even
// if the surface is saved, to outside world the surface is still NO_SURFACE.)
mAnimatingExit = false;
}
- void destroySavedSurface() {
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowState c = mChildren.get(i);
- c.destroySavedSurface();
- }
-
- if (mSurfaceSaved) {
- if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, "Destroying saved surface: " + this);
- mWinAnimator.destroySurfaceLocked();
- mSurfaceSaved = false;
- }
- mWasVisibleBeforeClientHidden = false;
- }
-
- /** Returns -1 if there are no interesting windows or number of interesting windows not drawn.*/
- int restoreSavedSurfaceForInterestingWindow() {
- int interestingNotDrawn = -1;
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowState c = mChildren.get(i);
- final int childInterestingNotDrawn = c.restoreSavedSurfaceForInterestingWindow();
- if (childInterestingNotDrawn != -1) {
- if (interestingNotDrawn == -1) {
- interestingNotDrawn = childInterestingNotDrawn;
- } else {
- interestingNotDrawn += childInterestingNotDrawn;
- }
- }
- }
-
- if (mAttrs.type == TYPE_APPLICATION_STARTING
- || mAppDied || !wasVisibleBeforeClientHidden()
- || (mAppToken.mAppAnimator.freezingScreen && mAppFreezing)) {
- // Window isn't interesting...
- return interestingNotDrawn;
- }
-
- restoreSavedSurface();
-
- if (!isDrawnLw()) {
- if (interestingNotDrawn == -1) {
- interestingNotDrawn = 1;
- } else {
- interestingNotDrawn++;
- }
- }
- return interestingNotDrawn;
- }
-
- /** Returns true if the saved surface was restored. */
- boolean restoreSavedSurface() {
- if (!mSurfaceSaved) {
- return false;
- }
-
- // Sometimes we save surfaces due to layout invisible directly after rotation occurs.
- // However this means the surface was never laid out in the new orientation.
- // We can only restore to the last rotation we were laid out as visible in.
- if (mLastVisibleLayoutRotation != getDisplayContent().getRotation()) {
- destroySavedSurface();
- return false;
- }
- mSurfaceSaved = false;
-
- if (mWinAnimator.mSurfaceController != null) {
- setHasSurface(true);
- mWinAnimator.mDrawState = READY_TO_SHOW;
- mAnimatingWithSavedSurface = true;
-
- requestUpdateWallpaperIfNeeded();
-
- if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
- Slog.v(TAG, "Restoring saved surface: " + this);
- }
- } else {
- // mSurfaceController shouldn't be null if mSurfaceSaved was still true at
- // this point. Even if we destroyed the saved surface because of rotation
- // or resize, mSurfaceSaved flag should have been cleared. So this is a wtf.
- Slog.wtf(TAG, "Failed to restore saved surface: surface gone! " + this);
- }
-
- return true;
- }
-
- boolean canRestoreSurface() {
- if (mWasVisibleBeforeClientHidden && mSurfaceSaved) {
- return true;
- }
-
- for (int i = mChildren.size() - 1; i >= 0; --i) {
- final WindowState c = mChildren.get(i);
- if (c.canRestoreSurface()) {
- return true;
- }
- }
-
- return false;
- }
-
- boolean hasSavedSurface() {
- return mSurfaceSaved;
- }
-
- void clearHasSavedSurface() {
- mSurfaceSaved = false;
- mAnimatingWithSavedSurface = false;
- if (mWasVisibleBeforeClientHidden) {
- mAppToken.destroySavedSurfaces();
- }
- }
-
- boolean clearAnimatingWithSavedSurface() {
- if (mAnimatingWithSavedSurface) {
- // App has drawn something to its windows, we're no longer animating with
- // the saved surfaces.
- if (DEBUG_ANIM) Slog.d(TAG,
- "clearAnimatingWithSavedSurface(): win=" + this);
- mAnimatingWithSavedSurface = false;
- return true;
- }
- return false;
- }
-
@Override
public boolean isDefaultDisplay() {
final DisplayContent displayContent = getDisplayContent();
@@ -3487,12 +3194,11 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
if (mAppToken != null) {
pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken);
pw.print(prefix); pw.print(" isAnimatingWithSavedSurface()=");
- pw.print(isAnimatingWithSavedSurface());
pw.print(" mAppDied=");pw.print(mAppDied);
pw.print(prefix); pw.print("drawnStateEvaluated=");
pw.print(getDrawnStateEvaluated());
pw.print(prefix); pw.print("mightAffectAllDrawn=");
- pw.println(mightAffectAllDrawn(false /*visibleOnly*/));
+ pw.println(mightAffectAllDrawn());
}
pw.print(prefix); pw.print("mViewVisibility=0x");
pw.print(Integer.toHexString(mViewVisibility));
@@ -3543,7 +3249,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
pw.print(prefix); pw.print("mHasSurface="); pw.print(mHasSurface);
pw.print(" mShownPosition="); mShownPosition.printShortString(pw);
pw.print(" isReadyForDisplay()="); pw.print(isReadyForDisplay());
- pw.print(" hasSavedSurface()="); pw.print(hasSavedSurface());
pw.print(" mWindowRemovalAllowed="); pw.println(mWindowRemovalAllowed);
if (dumpAll) {
pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw);
@@ -4601,11 +4306,6 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
&& getResizeMode() == DRAG_RESIZE_MODE_DOCKED_DIVIDER;
result |= freeformResizing ? RELAYOUT_RES_DRAG_RESIZING_FREEFORM : 0;
result |= dockedResizing ? RELAYOUT_RES_DRAG_RESIZING_DOCKED : 0;
- if (isAnimatingWithSavedSurface()) {
- // If we're animating with a saved surface now, request client to report draw.
- // We still need to know when the real thing is drawn.
- result |= RELAYOUT_RES_FIRST_TIME;
- }
return result;
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 5f1e42ccb2e4..ddb8df24ff92 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import static android.app.ActivityManager.StackId;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
@@ -347,7 +346,7 @@ class WindowStateAnimator {
mAnimation.cancel();
mAnimation = null;
mLocalAnimating = false;
- mWin.destroyOrSaveSurfaceUnchecked();
+ mWin.destroySurfaceUnchecked();
}
}
@@ -507,7 +506,7 @@ class WindowStateAnimator {
+ drawStateToString());
}
- boolean layoutNeeded = mWin.clearAnimatingWithSavedSurface();
+ boolean layoutNeeded = false;
if (mDrawState == DRAW_PENDING) {
if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || SHOW_TRANSACTIONS || DEBUG_ORIENTATION)
@@ -626,11 +625,6 @@ class WindowStateAnimator {
WindowSurfaceController createSurfaceLocked(int windowType, int ownerUid) {
final WindowState w = mWin;
- if (w.restoreSavedSurface()) {
- if (DEBUG_ANIM) Slog.i(TAG,
- "createSurface: " + this + ": called when we had a saved surface");
- return mSurfaceController;
- }
if (mSurfaceController != null) {
return mSurfaceController;
@@ -789,8 +783,7 @@ class WindowStateAnimator {
}
boolean hasSurface() {
- return !mWin.hasSavedSurface()
- && mSurfaceController != null && mSurfaceController.hasSurface();
+ return mSurfaceController != null && mSurfaceController.hasSurface();
}
void destroySurfaceLocked() {
@@ -801,8 +794,6 @@ class WindowStateAnimator {
}
}
- mWin.clearHasSavedSurface();
-
if (mSurfaceController == null) {
return;
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 581b0447dafc..88625d35f9b4 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -2,7 +2,6 @@
package com.android.server.wm;
import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-import static android.app.ActivityManagerInternal.APP_TRANSITION_SAVED_SURFACE;
import static android.app.ActivityManagerInternal.APP_TRANSITION_SNAPSHOT;
import static android.app.ActivityManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
import static android.app.ActivityManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
@@ -445,13 +444,6 @@ class WindowSurfacePlacer {
for (int i = 0; i < appsCount; i++) {
AppWindowToken wtoken = mService.mClosingApps.valueAt(i);
- // If we still have some windows animating with saved surfaces that's
- // either invisible or already removed, mark them exiting so that they
- // are disposed of after the exit animation. These are not supposed to
- // be shown, or are delayed removal until app is actually drawn (in which
- // case the window will be removed after the animation).
- wtoken.markSavedSurfaceExiting();
-
final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
appAnimator.clearThumbnail();
@@ -539,8 +531,6 @@ class WindowSurfacePlacer {
+ wtoken.startingMoved + " isRelaunching()="
+ wtoken.isRelaunching());
- final boolean drawnBeforeRestoring = wtoken.allDrawn;
- wtoken.restoreSavedSurfaceForInterestingWindows();
final boolean allDrawn = wtoken.allDrawn && !wtoken.isRelaunching();
if (!allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
@@ -549,8 +539,7 @@ class WindowSurfacePlacer {
final TaskStack stack = wtoken.getStack();
final int stackId = stack != null ? stack.mStackId : INVALID_STACK_ID;
if (allDrawn) {
- outReasons.put(stackId, drawnBeforeRestoring ? APP_TRANSITION_WINDOWS_DRAWN
- : APP_TRANSITION_SAVED_SURFACE);
+ outReasons.put(stackId, APP_TRANSITION_WINDOWS_DRAWN);
} else {
outReasons.put(stackId, wtoken.startingData instanceof SplashScreenStartingData
? APP_TRANSITION_SPLASH_SCREEN
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index 0370490668ec..d2f374dd9e08 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -153,9 +153,9 @@ static jlong vibratorPerformEffect(JNIEnv*, jobject, jlong effect, jint strength
if (status == Status::OK) {
return lengthMs;
} else if (status != Status::UNSUPPORTED_OPERATION) {
- // Don't warn on UNSUPPORTED_OPERATION, that's a normal even and just means the motor
- // doesn't have a pre-defined waveform to perform for it, so we should just fall back
- // to the framework waveforms.
+ // Don't warn on UNSUPPORTED_OPERATION, that's a normal event and just means the motor
+ // doesn't have a pre-defined waveform to perform for it, so we should just give the
+ // opportunity to fall back to the framework waveforms.
ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32
", error=%" PRIu32 ").", static_cast<int64_t>(effect),
static_cast<int32_t>(strength), static_cast<uint32_t>(status));
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index eb9683e1a470..d6b55678040d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -43,11 +43,11 @@ import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS;
import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
+import static android.app.admin.DevicePolicyManager.START_USER_IN_BACKGROUND;
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
-
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PROVISIONING_ENTRY_POINT_ADB;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -80,9 +80,9 @@ import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.IDevicePolicyManager;
import android.app.admin.NetworkEvent;
import android.app.admin.PasswordMetrics;
-import android.app.admin.SystemUpdateInfo;
import android.app.admin.SecurityLog;
import android.app.admin.SecurityLog.SecurityEvent;
+import android.app.admin.SystemUpdateInfo;
import android.app.admin.SystemUpdatePolicy;
import android.app.backup.IBackupManager;
import android.app.trust.TrustManager;
@@ -93,6 +93,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -614,11 +615,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
} else if (Intent.ACTION_USER_STARTED.equals(action)) {
synchronized (DevicePolicyManagerService.this) {
+ maybeSendAdminEnabledBroadcastLocked(userHandle);
// Reset the policy data
mUserData.remove(userHandle);
- sendAdminEnabledBroadcastLocked(userHandle);
}
handlePackagesChanged(null /* check all admins */, userHandle);
+ } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
+ synchronized (DevicePolicyManagerService.this) {
+ maybeSendAdminEnabledBroadcastLocked(userHandle);
+ }
} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
handlePackagesChanged(null /* check all admins */, userHandle);
} else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)
@@ -1854,6 +1859,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_REMOVED);
filter.addAction(Intent.ACTION_USER_STARTED);
+ filter.addAction(Intent.ACTION_USER_UNLOCKED);
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
filter = new IntentFilter();
@@ -2372,11 +2378,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
sendAdminCommandLocked(admin, action, null, result);
}
+ void sendAdminCommandLocked(ActiveAdmin admin, String action, Bundle adminExtras,
+ BroadcastReceiver result) {
+ sendAdminCommandLocked(admin, action, adminExtras, result, false);
+ }
+
/**
* Send an update to one specific admin, get notified when that admin returns a result.
+ *
+ * @return whether the broadcast was successfully sent
*/
- void sendAdminCommandLocked(ActiveAdmin admin, String action, Bundle adminExtras,
- BroadcastReceiver result) {
+ boolean sendAdminCommandLocked(ActiveAdmin admin, String action, Bundle adminExtras,
+ BroadcastReceiver result, boolean inForeground) {
Intent intent = new Intent(action);
intent.setComponent(admin.info.getComponent());
if (UserManager.isDeviceInDemoMode(mContext)) {
@@ -2385,15 +2398,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (action.equals(DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING)) {
intent.putExtra("expiration", admin.passwordExpirationDate);
}
+ if (inForeground) {
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ }
if (adminExtras != null) {
intent.putExtras(adminExtras);
}
+ if (mInjector.getPackageManager().queryBroadcastReceiversAsUser(
+ intent,
+ PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
+ admin.getUserHandle()).isEmpty()) {
+ return false;
+ }
if (result != null) {
mContext.sendOrderedBroadcastAsUser(intent, admin.getUserHandle(),
null, result, mHandler, Activity.RESULT_OK, null, null);
} else {
mContext.sendBroadcastAsUser(intent, admin.getUserHandle());
}
+ return true;
}
/**
@@ -8099,20 +8122,27 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
-
- private void sendAdminEnabledBroadcastLocked(int userHandle) {
+ private void maybeSendAdminEnabledBroadcastLocked(int userHandle) {
DevicePolicyData policyData = getUserData(userHandle);
if (policyData.mAdminBroadcastPending) {
// Send the initialization data to profile owner and delete the data
ActiveAdmin admin = getProfileOwnerAdminLocked(userHandle);
+ boolean clearInitBundle = true;
if (admin != null) {
PersistableBundle initBundle = policyData.mInitBundle;
- sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
- initBundle == null ? null : new Bundle(initBundle), null);
+ clearInitBundle = sendAdminCommandLocked(admin,
+ DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
+ initBundle == null ? null : new Bundle(initBundle),
+ null /* result receiver */,
+ true /* send in foreground */);
+ }
+ if (clearInitBundle) {
+ // If there's no admin or we've successfully called the admin, clear the init bundle
+ // otherwise, keep it around
+ policyData.mInitBundle = null;
+ policyData.mAdminBroadcastPending = false;
+ saveSettingsLocked(userHandle);
}
- policyData.mInitBundle = null;
- policyData.mAdminBroadcastPending = false;
- saveSettingsLocked(userHandle);
}
}
@@ -8158,7 +8188,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (user == null) {
return null;
}
- // Set admin.
final long id = mInjector.binderClearCallingIdentity();
try {
final String adminPkg = admin.getPackageName();
@@ -8171,30 +8200,38 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
0 /*installFlags*/, PackageManager.INSTALL_REASON_POLICY);
}
} catch (RemoteException e) {
- Slog.e(LOG_TAG, "Failed to make remote calls for createAndManageUser, "
- + "removing created user", e);
- mUserManager.removeUser(user.getIdentifier());
- return null;
+ // Does not happen, same process
}
+ // Set admin.
setActiveAdmin(profileOwner, true, userHandle);
- // User is not started yet, the broadcast by setActiveAdmin will not be received.
- // So we store adminExtras for broadcasting when the user starts for first time.
- synchronized(this) {
+ final String ownerName = getProfileOwnerName(Process.myUserHandle().getIdentifier());
+ setProfileOwner(profileOwner, ownerName, userHandle);
+
+ synchronized (this) {
DevicePolicyData policyData = getUserData(userHandle);
policyData.mInitBundle = adminExtras;
policyData.mAdminBroadcastPending = true;
saveSettingsLocked(userHandle);
}
- final String ownerName = getProfileOwnerName(Process.myUserHandle().getIdentifier());
- setProfileOwner(profileOwner, ownerName, userHandle);
if ((flags & DevicePolicyManager.SKIP_SETUP_WIZARD) != 0) {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.USER_SETUP_COMPLETE, 1, userHandle);
}
+ if ((flags & START_USER_IN_BACKGROUND) != 0) {
+ try {
+ mInjector.getIActivityManager().startUserInBackground(user.getIdentifier());
+ } catch (RemoteException re) {
+ // Does not happen, same process
+ }
+ }
+
return user;
+ } catch (Throwable re) {
+ mUserManager.removeUser(user.getIdentifier());
+ return null;
} finally {
mInjector.binderRestoreCallingIdentity(id);
}
@@ -9077,6 +9114,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return false;
}
mLockPatternUtils.setLockScreenDisabled(disabled, userId);
+ mInjector.getIWindowManager().dismissKeyguard(null);
+ } catch (RemoteException e) {
+ // Same process, does not happen.
} finally {
mInjector.binderRestoreCallingIdentity(ident);
}
@@ -11146,4 +11186,40 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
new ArrayList<>(getUserData(userId).mOwnerInstalledCaCerts));
}
}
+
+ @Override
+ public boolean clearApplicationUserData(ComponentName admin, String packageName,
+ IPackageDataObserver callback) {
+ Preconditions.checkNotNull(admin, "ComponentName is null");
+ synchronized (this) {
+ getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+ }
+ final int userId = UserHandle.getCallingUserId();
+
+ long ident = mInjector.binderClearCallingIdentity();
+ try {
+ return ActivityManager.getService().clearApplicationUserData(packageName, callback,
+ userId);
+ } catch(RemoteException re) {
+ // Same process, should not happen.
+ } catch (SecurityException se) {
+ // This can happen e.g. for device admin packages, do not throw out the exception,
+ // because callers have no means to know beforehand for which packages this might
+ // happen.
+ Slog.w(LOG_TAG, "Not allowed to clear application user data for package " + packageName,
+ se);
+ } finally {
+ mInjector.binderRestoreCallingIdentity(ident);
+ }
+
+ if (callback != null) {
+ try {
+ // If there was a throw above, we send back that removal failed
+ callback.onRemoveCompleted(packageName, false);
+ } catch (RemoteException re) {
+ // Caller is no longer available, ignore
+ }
+ }
+ return false;
+ }
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 1620df11f86f..57271fa10950 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1331,11 +1331,13 @@ public final class SystemServer {
traceEnd();
}
- if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_VOICE_RECOGNIZERS)) {
- traceBeginAndSlog("StartVoiceRecognitionManager");
- mSystemServiceManager.startService(VOICE_RECOGNITION_MANAGER_SERVICE_CLASS);
- traceEnd();
- }
+ // We need to always start this service, regardless of whether the
+ // FEATURE_VOICE_RECOGNIZERS feature is set, because it needs to take care
+ // of initializing various settings. It will internally modify its behavior
+ // based on that feature.
+ traceBeginAndSlog("StartVoiceRecognitionManager");
+ mSystemServiceManager.startService(VOICE_RECOGNITION_MANAGER_SERVICE_CLASS);
+ traceEnd();
if (GestureLauncherService.isGestureLauncherEnabled(context.getResources())) {
traceBeginAndSlog("StartGestureLauncher");
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 2d8fcf80e467..1d83897df750 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -94,7 +94,6 @@ import java.util.stream.Collectors;
*/
public class IpManager extends StateMachine {
private static final boolean DBG = false;
- private static final boolean VDBG = false;
// For message logging.
private static final Class[] sMessageClasses = { IpManager.class, DhcpClient.class };
@@ -526,17 +525,18 @@ public class IpManager extends StateMachine {
public static final String DUMP_ARG = "ipmanager";
public static final String DUMP_ARG_CONFIRM = "confirm";
- private static final int CMD_STOP = 1;
- private static final int CMD_START = 2;
- private static final int CMD_CONFIRM = 3;
- private static final int EVENT_PRE_DHCP_ACTION_COMPLETE = 4;
+ private static final int CMD_TERMINATE_AFTER_STOP = 1;
+ private static final int CMD_STOP = 2;
+ private static final int CMD_START = 3;
+ private static final int CMD_CONFIRM = 4;
+ private static final int EVENT_PRE_DHCP_ACTION_COMPLETE = 5;
// Sent by NetlinkTracker to communicate netlink events.
- private static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 5;
- private static final int CMD_UPDATE_TCP_BUFFER_SIZES = 6;
- private static final int CMD_UPDATE_HTTP_PROXY = 7;
- private static final int CMD_SET_MULTICAST_FILTER = 8;
- private static final int EVENT_PROVISIONING_TIMEOUT = 9;
- private static final int EVENT_DHCPACTION_TIMEOUT = 10;
+ private static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 6;
+ private static final int CMD_UPDATE_TCP_BUFFER_SIZES = 7;
+ private static final int CMD_UPDATE_HTTP_PROXY = 8;
+ private static final int CMD_SET_MULTICAST_FILTER = 9;
+ private static final int EVENT_PROVISIONING_TIMEOUT = 10;
+ private static final int EVENT_DHCPACTION_TIMEOUT = 11;
private static final int MAX_LOG_RECORDS = 500;
private static final int MAX_PACKET_RECORDS = 100;
@@ -704,6 +704,16 @@ public class IpManager extends StateMachine {
mMultinetworkPolicyTracker.start();
}
+ private void stopStateMachineUpdaters() {
+ try {
+ mNwService.unregisterObserver(mNetlinkTracker);
+ } catch (RemoteException e) {
+ logError("Couldn't unregister NetlinkTracker: %s", e);
+ }
+
+ mMultinetworkPolicyTracker.shutdown();
+ }
+
@Override
protected void onQuitting() {
mCallback.onQuit();
@@ -712,8 +722,7 @@ public class IpManager extends StateMachine {
// Shut down this IpManager instance altogether.
public void shutdown() {
stop();
- mMultinetworkPolicyTracker.shutdown();
- quit();
+ sendMessage(CMD_TERMINATE_AFTER_STOP);
}
public static ProvisioningConfiguration.Builder buildProvisioningConfiguration() {
@@ -858,7 +867,7 @@ public class IpManager extends StateMachine {
final String richerLogLine = getWhatToString(msg.what) + " " + logLine;
mLog.log(richerLogLine);
- if (VDBG) {
+ if (DBG) {
Log.d(mTag, richerLogLine);
}
@@ -1013,19 +1022,19 @@ public class IpManager extends StateMachine {
private void dispatchCallback(ProvisioningChange delta, LinkProperties newLp) {
switch (delta) {
case GAINED_PROVISIONING:
- if (VDBG) { Log.d(mTag, "onProvisioningSuccess()"); }
+ if (DBG) { Log.d(mTag, "onProvisioningSuccess()"); }
recordMetric(IpManagerEvent.PROVISIONING_OK);
mCallback.onProvisioningSuccess(newLp);
break;
case LOST_PROVISIONING:
- if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); }
+ if (DBG) { Log.d(mTag, "onProvisioningFailure()"); }
recordMetric(IpManagerEvent.PROVISIONING_FAIL);
mCallback.onProvisioningFailure(newLp);
break;
default:
- if (VDBG) { Log.d(mTag, "onLinkPropertiesChange()"); }
+ if (DBG) { Log.d(mTag, "onLinkPropertiesChange()"); }
mCallback.onLinkPropertiesChange(newLp);
break;
}
@@ -1113,7 +1122,7 @@ public class IpManager extends StateMachine {
addAllReachableDnsServers(newLp, config.dnsServers);
}
final LinkProperties oldLp = mLinkProperties;
- if (VDBG) {
+ if (DBG) {
Log.d(mTag, String.format("Netlink-seen LPs: %s, new LPs: %s; old LPs: %s",
netlinkLinkProperties, newLp, oldLp));
}
@@ -1153,7 +1162,7 @@ public class IpManager extends StateMachine {
ifcg.setLinkAddress(address);
try {
mNwService.setInterfaceConfig(mInterfaceName, ifcg);
- if (VDBG) Log.d(mTag, "IPv4 configuration succeeded");
+ if (DBG) Log.d(mTag, "IPv4 configuration succeeded");
} catch (IllegalStateException | RemoteException e) {
logError("IPv4 configuration failed: %s", e);
return false;
@@ -1176,7 +1185,7 @@ public class IpManager extends StateMachine {
final LinkProperties newLp = assembleLinkProperties();
final ProvisioningChange delta = setLinkProperties(newLp);
- if (VDBG) {
+ if (DBG) {
Log.d(mTag, "onNewDhcpResults(" + Objects.toString(dhcpResults) + ")");
}
mCallback.onNewDhcpResults(dhcpResults);
@@ -1192,7 +1201,7 @@ public class IpManager extends StateMachine {
// any addresses upon entry to StoppedState.
clearIPv4Address();
mDhcpResults = null;
- if (VDBG) { Log.d(mTag, "onNewDhcpResults(null)"); }
+ if (DBG) { Log.d(mTag, "onNewDhcpResults(null)"); }
mCallback.onNewDhcpResults(null);
handleProvisioningFailure();
@@ -1348,6 +1357,11 @@ public class IpManager extends StateMachine {
@Override
public boolean processMessage(Message msg) {
switch (msg.what) {
+ case CMD_TERMINATE_AFTER_STOP:
+ stopStateMachineUpdaters();
+ quit();
+ break;
+
case CMD_STOP:
break;
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index 6a6b542f9bb6..71ba685b99c9 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -63,6 +63,7 @@ import com.android.server.SystemService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -645,7 +646,6 @@ public final class PrintManagerService extends SystemService {
int opti = 0;
boolean dumpAsProto = false;
- int user = UserHandle.USER_ALL;
while (opti < args.length) {
String opt = args[opti];
if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
@@ -659,48 +659,47 @@ public final class PrintManagerService extends SystemService {
}
}
+ ArrayList<UserState> userStatesToDump = new ArrayList<>();
synchronized (mLock) {
- final long identity = Binder.clearCallingIdentity();
- try {
- if (dumpAsProto) {
- dumpLocked(new ProtoOutputStream(fd), UserHandle.of(user));
- } else {
- dumpLocked(fd, pw, UserHandle.of(user));
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
+ int numUserStates = mUserStates.size();
+ for (int i = 0; i < numUserStates; i++) {
+ userStatesToDump.add(mUserStates.valueAt(i));
+ }
+ }
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ if (dumpAsProto) {
+ dump(new ProtoOutputStream(fd), userStatesToDump);
+ } else {
+ dump(fd, pw, userStatesToDump);
}
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
- private void dumpLocked(@NonNull ProtoOutputStream proto, @NonNull UserHandle user) {
- final int userStateCount = mUserStates.size();
+ private void dump(@NonNull ProtoOutputStream proto,
+ @NonNull ArrayList<UserState> userStatesToDump) {
+ final int userStateCount = userStatesToDump.size();
for (int i = 0; i < userStateCount; i++) {
- UserState userState = mUserStates.valueAt(i);
-
- if (user.equals(UserHandle.ALL) || mUserStates.keyAt(i) == user.getIdentifier()) {
- long token = proto.start(PrintServiceDumpProto.USER_STATES);
- userState.dump(proto);
- proto.end(token);
- }
+ long token = proto.start(PrintServiceDumpProto.USER_STATES);
+ userStatesToDump.get(i).dump(proto);
+ proto.end(token);
}
proto.flush();
}
- private void dumpLocked(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
- @NonNull UserHandle user) {
+ private void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw,
+ @NonNull ArrayList<UserState> userStatesToDump) {
pw = Preconditions.checkNotNull(pw);
pw.println("PRINT MANAGER STATE (dumpsys print)");
- final int userStateCount = mUserStates.size();
+ final int userStateCount = userStatesToDump.size();
for (int i = 0; i < userStateCount; i++) {
- UserState userState = mUserStates.valueAt(i);
-
- if (user.equals(UserHandle.ALL) || mUserStates.keyAt(i) == user.getIdentifier()) {
- userState.dump(fd, pw, "");
- pw.println();
- }
+ userStatesToDump.get(i).dump(fd, pw, "");
+ pw.println();
}
}
diff --git a/services/robotests/Android.mk b/services/robotests/Android.mk
new file mode 100644
index 000000000000..717176247d36
--- /dev/null
+++ b/services/robotests/Android.mk
@@ -0,0 +1,78 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+############################################################
+# FrameworksServicesLib app just for Robolectric test target. #
+############################################################
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := FrameworksServicesLib
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_PRIVILEGED_MODULE := true
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ frameworks-base-testutils \
+ services.backup \
+ services.core \
+ android-support-test \
+ mockito-target-minus-junit4 \
+ platform-test-annotations \
+ truth-prebuilt
+
+include $(BUILD_PACKAGE)
+
+#############################################
+# FrameworksServices Robolectric test target. #
+#############################################
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+# Include the testing libraries (JUnit4 + Robolectric libs).
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ platform-system-robolectric \
+ truth-prebuilt
+
+LOCAL_JAVA_LIBRARIES := \
+ junit \
+ platform-robolectric-prebuilt
+
+LOCAL_INSTRUMENTATION_FOR := FrameworksServicesLib
+LOCAL_MODULE := FrameworksServicesRoboTests
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+#############################################################
+# FrameworksServices runner target to run the previous target. #
+#############################################################
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := RunFrameworksServicesRoboTests
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ FrameworksServicesRoboTests
+
+LOCAL_TEST_PACKAGE := FrameworksServicesLib
+
+LOCAL_INSTRUMENT_SOURCE_DIRS := $(dir $(LOCAL_PATH))backup/java
+
+include prebuilts/misc/common/robolectric/run_robotests.mk
diff --git a/services/robotests/src/com/android/server/backup/TransportManagerTest.java b/services/robotests/src/com/android/server/backup/TransportManagerTest.java
new file mode 100644
index 000000000000..f345da2b548c
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/TransportManagerTest.java
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+
+import com.android.server.backup.testing.BackupTransportStub;
+import com.android.server.backup.testing.DefaultPackageManagerWithQueryIntentServicesAsUser;
+import com.android.server.backup.testing.ShadowBackupTransportStub;
+import com.android.server.backup.testing.ShadowContextImplForBackup;
+import com.android.server.backup.testing.TransportBoundListenerStub;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.res.builder.RobolectricPackageManager;
+import org.robolectric.shadows.ShadowLog;
+import org.robolectric.shadows.ShadowLooper;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(
+ manifest = Config.NONE,
+ sdk = 23,
+ shadows = {
+ ShadowContextImplForBackup.class,
+ ShadowBackupTransportStub.class
+ }
+)
+@Presubmit
+public class TransportManagerTest {
+ private static final String PACKAGE_NAME = "some.package.name";
+ private static final String ANOTHER_PACKAGE_NAME = "another.package.name";
+
+ private TransportInfo mTransport1;
+ private TransportInfo mTransport2;
+
+ private RobolectricPackageManager mPackageManager;
+
+ private final TransportBoundListenerStub mTransportBoundListenerStub =
+ new TransportBoundListenerStub(true);
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ ShadowLog.stream = System.out;
+ mPackageManager = new DefaultPackageManagerWithQueryIntentServicesAsUser(
+ RuntimeEnvironment.getAppResourceLoader());
+ RuntimeEnvironment.setRobolectricPackageManager(mPackageManager);
+
+ mTransport1 = new TransportInfo(PACKAGE_NAME, "transport1.name");
+ mTransport2 = new TransportInfo(PACKAGE_NAME, "transport2.name");
+
+ ShadowContextImplForBackup.sComponentBinderMap.put(mTransport1.componentName,
+ mTransport1.binder);
+ ShadowContextImplForBackup.sComponentBinderMap.put(mTransport2.componentName,
+ mTransport2.binder);
+ ShadowBackupTransportStub.sBinderTransportMap.put(mTransport1.binder, mTransport1.stub);
+ ShadowBackupTransportStub.sBinderTransportMap.put(mTransport2.binder, mTransport2.stub);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ ShadowContextImplForBackup.resetBackupShadowState();
+ }
+
+ @Test
+ public void onPackageAdded_bindsToAllTransports() throws Exception {
+ setUpPackageWithTransports(PACKAGE_NAME, Arrays.asList(mTransport1, mTransport2),
+ ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+
+ TransportManager transportManager = new TransportManager(
+ RuntimeEnvironment.application.getApplicationContext(),
+ new HashSet<>(Arrays.asList(
+ mTransport1.componentName, mTransport2.componentName)),
+ null /* defaultTransport */,
+ mTransportBoundListenerStub,
+ ShadowLooper.getMainLooper());
+ transportManager.onPackageAdded(PACKAGE_NAME);
+
+ assertThat(transportManager.getAllTransportComponents()).asList().containsExactlyElementsIn(
+ Arrays.asList(mTransport1.componentName, mTransport2.componentName));
+ assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
+ Arrays.asList(mTransport1.name, mTransport2.name));
+ assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.stub)).isTrue();
+ assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.stub)).isTrue();
+ }
+
+ @Test
+ public void onPackageAdded_oneTransportUnavailable_bindsToOnlyOneTransport() throws Exception {
+ setUpPackageWithTransports(PACKAGE_NAME, Arrays.asList(mTransport1, mTransport2),
+ ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+
+ ShadowContextImplForBackup.sUnbindableComponents.add(mTransport1.componentName);
+
+ TransportManager transportManager = new TransportManager(
+ RuntimeEnvironment.application.getApplicationContext(),
+ new HashSet<>(Arrays.asList(
+ mTransport1.componentName, mTransport2.componentName)),
+ null /* defaultTransport */,
+ mTransportBoundListenerStub,
+ ShadowLooper.getMainLooper());
+ transportManager.onPackageAdded(PACKAGE_NAME);
+
+ assertThat(transportManager.getAllTransportComponents()).asList().containsExactlyElementsIn(
+ Collections.singleton(mTransport2.componentName));
+ assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
+ Collections.singleton(mTransport2.name));
+ assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.stub)).isFalse();
+ assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.stub)).isTrue();
+ }
+
+ @Test
+ public void onPackageAdded_whitelistIsNull_doesNotBindToTransports() throws Exception {
+ setUpPackageWithTransports(PACKAGE_NAME, Arrays.asList(mTransport1, mTransport2),
+ ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+
+ TransportManager transportManager = new TransportManager(
+ RuntimeEnvironment.application.getApplicationContext(),
+ null /* whitelist */,
+ null /* defaultTransport */,
+ mTransportBoundListenerStub,
+ ShadowLooper.getMainLooper());
+ transportManager.onPackageAdded(PACKAGE_NAME);
+
+ assertThat(transportManager.getAllTransportComponents()).isEmpty();
+ assertThat(transportManager.getBoundTransportNames()).isEmpty();
+ assertThat(mTransportBoundListenerStub.isCalled()).isFalse();
+ }
+
+ @Test
+ public void onPackageAdded_onlyOneTransportWhitelisted_onlyConnectsToWhitelistedTransport()
+ throws Exception {
+ setUpPackageWithTransports(PACKAGE_NAME, Arrays.asList(mTransport1, mTransport2),
+ ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+
+ TransportManager transportManager = new TransportManager(
+ RuntimeEnvironment.application.getApplicationContext(),
+ new HashSet<>(Collections.singleton(mTransport2.componentName)),
+ null /* defaultTransport */,
+ mTransportBoundListenerStub,
+ ShadowLooper.getMainLooper());
+ transportManager.onPackageAdded(PACKAGE_NAME);
+
+ assertThat(transportManager.getAllTransportComponents()).asList().containsExactlyElementsIn(
+ Collections.singleton(mTransport2.componentName));
+ assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
+ Collections.singleton(mTransport2.name));
+ assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.stub)).isFalse();
+ assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.stub)).isTrue();
+ }
+
+ @Test
+ public void onPackageAdded_appIsNotPrivileged_doesNotBindToTransports() throws Exception {
+ setUpPackageWithTransports(PACKAGE_NAME, Arrays.asList(mTransport1, mTransport2), 0);
+
+ TransportManager transportManager = new TransportManager(
+ RuntimeEnvironment.application.getApplicationContext(),
+ new HashSet<>(Arrays.asList(
+ mTransport1.componentName, mTransport2.componentName)),
+ null /* defaultTransport */,
+ mTransportBoundListenerStub,
+ ShadowLooper.getMainLooper());
+ transportManager.onPackageAdded(PACKAGE_NAME);
+
+ assertThat(transportManager.getAllTransportComponents()).isEmpty();
+ assertThat(transportManager.getBoundTransportNames()).isEmpty();
+ assertThat(mTransportBoundListenerStub.isCalled()).isFalse();
+ }
+
+ @Test
+ public void onPackageRemoved_transportsUnbound() throws Exception {
+ TransportManager transportManager = createTransportManagerAndSetUpTransports(
+ Arrays.asList(mTransport1, mTransport2), mTransport1.name);
+
+ transportManager.onPackageRemoved(PACKAGE_NAME);
+
+ assertThat(transportManager.getAllTransportComponents()).isEmpty();
+ assertThat(transportManager.getBoundTransportNames()).isEmpty();
+ }
+
+ @Test
+ public void onPackageRemoved_incorrectPackageName_nothingHappens() throws Exception {
+ TransportManager transportManager = createTransportManagerAndSetUpTransports(
+ Arrays.asList(mTransport1, mTransport2), mTransport1.name);
+
+ transportManager.onPackageRemoved(ANOTHER_PACKAGE_NAME);
+
+ assertThat(transportManager.getAllTransportComponents()).asList().containsExactlyElementsIn(
+ Arrays.asList(mTransport1.componentName, mTransport2.componentName));
+ assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
+ Arrays.asList(mTransport1.name, mTransport2.name));
+ }
+
+ @Test
+ public void onPackageChanged_oneComponentChanged_onlyOneTransportRebound() throws Exception {
+ TransportManager transportManager = createTransportManagerAndSetUpTransports(
+ Arrays.asList(mTransport1, mTransport2), mTransport1.name);
+
+ transportManager.onPackageChanged(PACKAGE_NAME, new String[]{mTransport2.name});
+
+ assertThat(transportManager.getAllTransportComponents()).asList().containsExactlyElementsIn(
+ Arrays.asList(mTransport1.componentName, mTransport2.componentName));
+ assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
+ Arrays.asList(mTransport1.name, mTransport2.name));
+ assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.stub)).isFalse();
+ assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.stub)).isTrue();
+ }
+
+ @Test
+ public void onPackageChanged_nothingChanged_noTransportsRebound() throws Exception {
+ TransportManager transportManager = createTransportManagerAndSetUpTransports(
+ Arrays.asList(mTransport1, mTransport2), mTransport1.name);
+
+ transportManager.onPackageChanged(PACKAGE_NAME, new String[0]);
+
+ assertThat(transportManager.getAllTransportComponents()).asList().containsExactlyElementsIn(
+ Arrays.asList(mTransport1.componentName, mTransport2.componentName));
+ assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
+ Arrays.asList(mTransport1.name, mTransport2.name));
+ assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.stub)).isFalse();
+ assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.stub)).isFalse();
+ }
+
+ @Test
+ public void onPackageChanged_unexpectedComponentChanged_noTransportsRebound() throws Exception {
+ TransportManager transportManager = createTransportManagerAndSetUpTransports(
+ Arrays.asList(mTransport1, mTransport2), mTransport1.name);
+
+ transportManager.onPackageChanged(PACKAGE_NAME, new String[]{"unexpected.component"});
+
+ assertThat(transportManager.getAllTransportComponents()).asList().containsExactlyElementsIn(
+ Arrays.asList(mTransport1.componentName, mTransport2.componentName));
+ assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
+ Arrays.asList(mTransport1.name, mTransport2.name));
+ assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.stub)).isFalse();
+ assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.stub)).isFalse();
+ }
+
+ @Test
+ public void onPackageChanged_transportsRebound() throws Exception {
+ TransportManager transportManager = createTransportManagerAndSetUpTransports(
+ Arrays.asList(mTransport1, mTransport2), mTransport1.name);
+
+ transportManager.onPackageChanged(PACKAGE_NAME, new String[]{mTransport2.name});
+
+ assertThat(transportManager.getAllTransportComponents()).asList().containsExactlyElementsIn(
+ Arrays.asList(mTransport1.componentName, mTransport2.componentName));
+ assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
+ Arrays.asList(mTransport1.name, mTransport2.name));
+ assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport1.stub)).isFalse();
+ assertThat(mTransportBoundListenerStub.isCalledForTransport(mTransport2.stub)).isTrue();
+ }
+
+ @Test
+ public void getTransportBinder_returnsCorrectBinder() throws Exception {
+ TransportManager transportManager = createTransportManagerAndSetUpTransports(
+ Arrays.asList(mTransport1, mTransport2), mTransport1.name);
+
+ assertThat(transportManager.getTransportBinder(mTransport1.name)).isEqualTo(
+ mTransport1.stub);
+ assertThat(transportManager.getTransportBinder(mTransport2.name)).isEqualTo(
+ mTransport2.stub);
+ }
+
+ @Test
+ public void getTransportBinder_incorrectTransportName_returnsNull() throws Exception {
+ TransportManager transportManager = createTransportManagerAndSetUpTransports(
+ Arrays.asList(mTransport1, mTransport2), mTransport1.name);
+
+ assertThat(transportManager.getTransportBinder("incorrect.transport")).isNull();
+ }
+
+ @Test
+ public void getTransportBinder_oneTransportUnavailable_returnsCorrectBinder() throws Exception {
+ TransportManager transportManager =
+ createTransportManagerAndSetUpTransports(Collections.singletonList(mTransport2),
+ Collections.singletonList(mTransport1), mTransport1.name);
+
+ assertThat(transportManager.getTransportBinder(mTransport1.name)).isNull();
+ assertThat(transportManager.getTransportBinder(mTransport2.name)).isEqualTo(
+ mTransport2.stub);
+ }
+
+ @Test
+ public void getCurrentTransport_selectTransportNotCalled_returnsDefaultTransport()
+ throws Exception {
+ TransportManager transportManager = createTransportManagerAndSetUpTransports(
+ Arrays.asList(mTransport1, mTransport2), mTransport1.name);
+
+ assertThat(transportManager.getCurrentTransportName()).isEqualTo(mTransport1.name);
+ }
+
+ @Test
+ public void getCurrentTransport_selectTransportCalled_returnsCorrectTransport()
+ throws Exception {
+ TransportManager transportManager = createTransportManagerAndSetUpTransports(
+ Arrays.asList(mTransport1, mTransport2), mTransport1.name);
+
+ assertThat(transportManager.getCurrentTransportName()).isEqualTo(mTransport1.name);
+
+ transportManager.selectTransport(mTransport2.name);
+
+ assertThat(transportManager.getCurrentTransportName()).isEqualTo(mTransport2.name);
+ }
+
+ @Test
+ public void getCurrentTransportBinder_returnsCorrectBinder() throws Exception {
+ TransportManager transportManager = createTransportManagerAndSetUpTransports(
+ Arrays.asList(mTransport1, mTransport2), mTransport1.name);
+
+ assertThat(transportManager.getCurrentTransportBinder()).isEqualTo(mTransport1.stub);
+ }
+
+ @Test
+ public void getCurrentTransportBinder_transportNotBound_returnsNull() throws Exception {
+ TransportManager transportManager =
+ createTransportManagerAndSetUpTransports(Collections.singletonList(mTransport2),
+ Collections.singletonList(mTransport1), mTransport2.name);
+
+ transportManager.selectTransport(mTransport1.name);
+
+ assertThat(transportManager.getCurrentTransportBinder()).isNull();
+ }
+
+ @Test
+ public void getTransportName_returnsCorrectTransportName() throws Exception {
+ TransportManager transportManager = createTransportManagerAndSetUpTransports(
+ Arrays.asList(mTransport1, mTransport2), mTransport1.name);
+
+ assertThat(transportManager.getTransportName(mTransport1.stub)).isEqualTo(mTransport1.name);
+ assertThat(transportManager.getTransportName(mTransport2.stub)).isEqualTo(mTransport2.name);
+ }
+
+ @Test
+ public void getTransportName_transportNotBound_returnsNull() throws Exception {
+ TransportManager transportManager =
+ createTransportManagerAndSetUpTransports(Collections.singletonList(mTransport2),
+ Collections.singletonList(mTransport1), mTransport1.name);
+
+ assertThat(transportManager.getTransportName(mTransport1.stub)).isNull();
+ assertThat(transportManager.getTransportName(mTransport2.stub)).isEqualTo(mTransport2.name);
+ }
+
+ @Test
+ public void getTransportWhitelist_returnsCorrectWhiteList() throws Exception {
+ TransportManager transportManager = new TransportManager(
+ RuntimeEnvironment.application.getApplicationContext(),
+ new HashSet<>(Arrays.asList(mTransport1.componentName, mTransport2.componentName)),
+ mTransport1.name,
+ mTransportBoundListenerStub,
+ ShadowLooper.getMainLooper());
+
+ assertThat(transportManager.getTransportWhitelist()).containsExactlyElementsIn(
+ Arrays.asList(mTransport1.componentName, mTransport2.componentName));
+ }
+
+ @Test
+ public void getTransportWhitelist_whiteListIsNull_returnsEmptyArray() throws Exception {
+ TransportManager transportManager = new TransportManager(
+ RuntimeEnvironment.application.getApplicationContext(),
+ null /* whitelist */,
+ mTransport1.name,
+ mTransportBoundListenerStub,
+ ShadowLooper.getMainLooper());
+
+ assertThat(transportManager.getTransportWhitelist()).isEmpty();
+ }
+
+ @Test
+ public void selectTransport_setsTransportCorrectlyAndReturnsPreviousTransport()
+ throws Exception {
+ TransportManager transportManager = new TransportManager(
+ RuntimeEnvironment.application.getApplicationContext(),
+ null /* whitelist */,
+ mTransport1.name,
+ mTransportBoundListenerStub,
+ ShadowLooper.getMainLooper());
+
+ assertThat(transportManager.selectTransport(mTransport2.name)).isEqualTo(mTransport1.name);
+ assertThat(transportManager.selectTransport(mTransport1.name)).isEqualTo(mTransport2.name);
+ }
+
+ private void setUpPackageWithTransports(String packageName, List<TransportInfo> transports,
+ int flags) throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = packageName;
+ packageInfo.applicationInfo = new ApplicationInfo();
+ packageInfo.applicationInfo.privateFlags = flags;
+
+ mPackageManager.addPackage(packageInfo);
+
+ List<ResolveInfo> transportsInfo = new ArrayList<>();
+ for (TransportInfo transport : transports) {
+ ResolveInfo info = new ResolveInfo();
+ info.serviceInfo = new ServiceInfo();
+ info.serviceInfo.packageName = packageName;
+ info.serviceInfo.name = transport.name;
+ transportsInfo.add(info);
+ }
+
+ Intent intent = new Intent(TransportManager.SERVICE_ACTION_TRANSPORT_HOST);
+ intent.setPackage(packageName);
+
+ mPackageManager.addResolveInfoForIntent(intent, transportsInfo);
+ }
+
+ private TransportManager createTransportManagerAndSetUpTransports(
+ List<TransportInfo> availableTransports, String defaultTransportName) throws Exception {
+ return createTransportManagerAndSetUpTransports(availableTransports,
+ Collections.<TransportInfo>emptyList(), defaultTransportName);
+ }
+
+ private TransportManager createTransportManagerAndSetUpTransports(
+ List<TransportInfo> availableTransports, List<TransportInfo> unavailableTransports,
+ String defaultTransportName)
+ throws Exception {
+ List<String> availableTransportsNames = new ArrayList<>();
+ List<ComponentName> availableTransportsComponentNames = new ArrayList<>();
+ for (TransportInfo transport : availableTransports) {
+ availableTransportsNames.add(transport.name);
+ availableTransportsComponentNames.add(transport.componentName);
+ }
+
+ List<ComponentName> allTransportsComponentNames = new ArrayList<>();
+ allTransportsComponentNames.addAll(availableTransportsComponentNames);
+ for (TransportInfo transport : unavailableTransports) {
+ allTransportsComponentNames.add(transport.componentName);
+ }
+
+ for (TransportInfo transport : unavailableTransports) {
+ ShadowContextImplForBackup.sUnbindableComponents.add(transport.componentName);
+ }
+
+ setUpPackageWithTransports(PACKAGE_NAME, Arrays.asList(mTransport1, mTransport2),
+ ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
+
+ TransportManager transportManager = new TransportManager(
+ RuntimeEnvironment.application.getApplicationContext(),
+ new HashSet<>(allTransportsComponentNames),
+ defaultTransportName,
+ mTransportBoundListenerStub,
+ ShadowLooper.getMainLooper());
+ transportManager.onPackageAdded(PACKAGE_NAME);
+
+ assertThat(transportManager.getAllTransportComponents()).asList().containsExactlyElementsIn(
+ availableTransportsComponentNames);
+ assertThat(transportManager.getBoundTransportNames()).asList().containsExactlyElementsIn(
+ availableTransportsNames);
+ for (TransportInfo transport : availableTransports) {
+ assertThat(mTransportBoundListenerStub.isCalledForTransport(transport.stub)).isTrue();
+ }
+ for (TransportInfo transport : unavailableTransports) {
+ assertThat(mTransportBoundListenerStub.isCalledForTransport(transport.stub)).isFalse();
+ }
+
+ mTransportBoundListenerStub.resetState();
+
+ return transportManager;
+ }
+
+ private static class TransportInfo {
+ public final String packageName;
+ public final String name;
+ public final ComponentName componentName;
+ public final BackupTransportStub stub;
+ public final IBinder binder;
+
+ TransportInfo(String packageName, String name) {
+ this.packageName = packageName;
+ this.name = name;
+ this.componentName = new ComponentName(packageName, name);
+ this.stub = new BackupTransportStub(name);
+ this.binder = mock(IBinder.class);
+ }
+ }
+}
diff --git a/services/robotests/src/com/android/server/backup/testing/BackupTransportStub.java b/services/robotests/src/com/android/server/backup/testing/BackupTransportStub.java
new file mode 100644
index 000000000000..ec09f908c90d
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/testing/BackupTransportStub.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.testing;
+
+import android.app.backup.RestoreDescription;
+import android.app.backup.RestoreSet;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+
+import com.android.internal.backup.IBackupTransport;
+
+/**
+ * Stub backup transport, doing nothing and returning default values.
+ */
+public class BackupTransportStub implements IBackupTransport {
+
+ private final String mName;
+
+ public BackupTransportStub(String name) {
+ mName = name;
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return null;
+ }
+
+ @Override
+ public String name() throws RemoteException {
+ return mName;
+ }
+
+ @Override
+ public Intent configurationIntent() throws RemoteException {
+ return null;
+ }
+
+ @Override
+ public String currentDestinationString() throws RemoteException {
+ return null;
+ }
+
+ @Override
+ public Intent dataManagementIntent() throws RemoteException {
+ return null;
+ }
+
+ @Override
+ public String dataManagementLabel() throws RemoteException {
+ return null;
+ }
+
+ @Override
+ public String transportDirName() throws RemoteException {
+ return null;
+ }
+
+ @Override
+ public long requestBackupTime() throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public int initializeDevice() throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor inFd, int flags)
+ throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public int clearBackupData(PackageInfo packageInfo) throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public int finishBackup() throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public RestoreSet[] getAvailableRestoreSets() throws RemoteException {
+ return new RestoreSet[0];
+ }
+
+ @Override
+ public long getCurrentRestoreSet() throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public int startRestore(long token, PackageInfo[] packages) throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public RestoreDescription nextRestorePackage() throws RemoteException {
+ return null;
+ }
+
+ @Override
+ public int getRestoreData(ParcelFileDescriptor outFd) throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public void finishRestore() throws RemoteException {
+
+ }
+
+ @Override
+ public long requestFullBackupTime() throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public int performFullBackup(PackageInfo targetPackage, ParcelFileDescriptor socket,
+ int flags)
+ throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public int checkFullBackupSize(long size) throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public int sendBackupData(int numBytes) throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public void cancelFullBackup() throws RemoteException {
+
+ }
+
+ @Override
+ public boolean isAppEligibleForBackup(PackageInfo targetPackage, boolean isFullBackup)
+ throws RemoteException {
+ return false;
+ }
+
+ @Override
+ public long getBackupQuota(String packageName, boolean isFullBackup)
+ throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public int abortFullRestore() throws RemoteException {
+ return 0;
+ }
+}
diff --git a/services/robotests/src/com/android/server/backup/testing/DefaultPackageManagerWithQueryIntentServicesAsUser.java b/services/robotests/src/com/android/server/backup/testing/DefaultPackageManagerWithQueryIntentServicesAsUser.java
new file mode 100644
index 000000000000..5a0967ba2420
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/testing/DefaultPackageManagerWithQueryIntentServicesAsUser.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.testing;
+
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+
+import org.robolectric.res.ResourceLoader;
+import org.robolectric.res.builder.DefaultPackageManager;
+
+import java.util.List;
+
+/**
+ * Implementation of PackageManager for Robolectric which handles queryIntentServicesAsUser().
+ */
+public class DefaultPackageManagerWithQueryIntentServicesAsUser extends
+ DefaultPackageManager {
+
+ /* package */
+ public DefaultPackageManagerWithQueryIntentServicesAsUser(
+ ResourceLoader appResourceLoader) {
+ super(appResourceLoader);
+ }
+
+ @Override
+ public List<ResolveInfo> queryIntentServicesAsUser(Intent intent, int flags, int userId) {
+ return super.queryIntentServices(intent, flags);
+ }
+}
diff --git a/services/robotests/src/com/android/server/backup/testing/ShadowBackupTransportStub.java b/services/robotests/src/com/android/server/backup/testing/ShadowBackupTransportStub.java
new file mode 100644
index 000000000000..48a12f0f5435
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/testing/ShadowBackupTransportStub.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.testing;
+
+import android.os.IBinder;
+
+import com.android.internal.backup.IBackupTransport;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Shadow IBackupTransport.Stub, returns a transport corresponding to the binder.
+ */
+@Implements(IBackupTransport.Stub.class)
+public class ShadowBackupTransportStub {
+ public static Map<IBinder, IBackupTransport> sBinderTransportMap = new HashMap<>();
+
+ @Implementation
+ public static IBackupTransport asInterface(IBinder obj) {
+ return sBinderTransportMap.get(obj);
+ }
+}
diff --git a/services/robotests/src/com/android/server/backup/testing/ShadowContextImplForBackup.java b/services/robotests/src/com/android/server/backup/testing/ShadowContextImplForBackup.java
new file mode 100644
index 000000000000..c3975db3057f
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/testing/ShadowContextImplForBackup.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.testing;
+
+import android.annotation.RequiresPermission;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.UserHandle;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.ShadowApplication;
+import org.robolectric.shadows.ShadowContextImpl;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Implementation of ContextImpl shadow, handling bindServiceAsUser().
+ */
+@Implements(className = ShadowContextImpl.CLASS_NAME)
+public class ShadowContextImplForBackup extends ShadowContextImpl {
+ public static Map<ComponentName, IBinder> sComponentBinderMap = new HashMap<>();
+ public static Set<ComponentName> sUnbindableComponents = new HashSet<>();
+
+ @Implementation
+ public boolean bindServiceAsUser(@RequiresPermission Intent service, ServiceConnection conn,
+ int flags, UserHandle user) {
+ if (sUnbindableComponents.contains(service.getComponent())) {
+ return false;
+ }
+
+ ShadowApplication.getInstance().setComponentNameAndServiceForBindService(
+ service.getComponent(), sComponentBinderMap.get(service.getComponent()));
+ return bindService(service, conn, flags);
+ }
+
+
+ /**
+ * Resets backup-related shadow state.
+ */
+ public static void resetBackupShadowState() {
+ sComponentBinderMap.clear();
+ sUnbindableComponents.clear();
+ }
+}
diff --git a/services/robotests/src/com/android/server/backup/testing/TransportBoundListenerStub.java b/services/robotests/src/com/android/server/backup/testing/TransportBoundListenerStub.java
new file mode 100644
index 000000000000..84ac2c212854
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/testing/TransportBoundListenerStub.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.backup.testing;
+
+import com.android.internal.backup.IBackupTransport;
+import com.android.server.backup.TransportManager;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Stub implementation of TransportBoundListener, which returns given result and can tell whether
+ * it was called for given transport.
+ */
+public class TransportBoundListenerStub implements
+ TransportManager.TransportBoundListener {
+ private boolean mAlwaysReturnSuccess;
+ private Set<IBackupTransport> mTransportsCalledFor = new HashSet<>();
+
+ public TransportBoundListenerStub(boolean alwaysReturnSuccess) {
+ this.mAlwaysReturnSuccess = alwaysReturnSuccess;
+ }
+
+ @Override
+ public boolean onTransportBound(IBackupTransport binder) {
+ mTransportsCalledFor.add(binder);
+ return mAlwaysReturnSuccess;
+ }
+
+ /**
+ * Returns whether the listener was called for the specified transport at least once.
+ */
+ public boolean isCalledForTransport(IBackupTransport binder) {
+ return mTransportsCalledFor.contains(binder);
+ }
+
+ /**
+ * Returns whether the listener was called at least once.
+ */
+ public boolean isCalled() {
+ return !mTransportsCalledFor.isEmpty();
+ }
+
+ /**
+ * Resets listener calls.
+ */
+ public void resetState() {
+ mTransportsCalledFor.clear();
+ }
+}
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index 04b42f1ee312..ddd21df78e85 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -429,6 +429,20 @@ public class NotificationManagerServiceTest extends NotificationTestCase {
}
@Test
+ public void testBlockedNotifications_blockedChannelGroup() throws Exception {
+ when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
+ mNotificationManagerService.setRankingHelper(mRankingHelper);
+ when(mRankingHelper.isGroupBlocked(anyString(), anyInt(), anyString())).thenReturn(true);
+
+ NotificationChannel channel = new NotificationChannel("id", "name",
+ NotificationManager.IMPORTANCE_HIGH);
+ channel.setGroup("something");
+ NotificationRecord r = generateNotificationRecord(channel);
+ assertTrue(mNotificationManagerService.isBlocked(r, mUsageStats));
+ verify(mUsageStats, times(1)).registerBlocked(eq(r));
+ }
+
+ @Test
public void testEnqueuedBlockedNotifications_blockedApp() throws Exception {
when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 65bf33084bb4..306dd98acaad 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -240,12 +240,23 @@ public class RankingHelperTest extends NotificationTestCase {
private void compareGroups(NotificationChannelGroup expected, NotificationChannelGroup actual) {
assertEquals(expected.getId(), actual.getId());
assertEquals(expected.getName(), actual.getName());
+ assertEquals(expected.getDescription(), actual.getDescription());
+ assertEquals(expected.isBlocked(), actual.isBlocked());
}
private NotificationChannel getChannel() {
return new NotificationChannel("id", "name", IMPORTANCE_LOW);
}
+ private NotificationChannel findChannel(List<NotificationChannel> channels, String id) {
+ for (NotificationChannel channel : channels) {
+ if (channel.getId().equals(id)) {
+ return channel;
+ }
+ }
+ return null;
+ }
+
@Test
public void testFindAfterRankingWithASplitGroup() throws Exception {
ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(3);
@@ -299,6 +310,8 @@ public class RankingHelperTest extends NotificationTestCase {
@Test
public void testChannelXml() throws Exception {
NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
+ ncg.setBlocked(true);
+ ncg.setDescription("group desc");
NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
NotificationChannel channel1 =
new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
@@ -1294,6 +1307,26 @@ public class RankingHelperTest extends NotificationTestCase {
}
@Test
+ public void testCreateChannel_addToGroup() throws Exception {
+ NotificationChannelGroup group = new NotificationChannelGroup("group", "");
+ mHelper.createNotificationChannelGroup(PKG, UID, group, true);
+ NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT);
+ mHelper.createNotificationChannel(PKG, UID, nc, true);
+ NotificationChannel actual = mHelper.getNotificationChannel(PKG, UID, "id", false);
+ assertNull(actual.getGroup());
+
+ nc = new NotificationChannel("id", "hello", IMPORTANCE_HIGH);
+ nc.setGroup(group.getId());
+ mHelper.createNotificationChannel(PKG, UID, nc, true);
+
+ actual = mHelper.getNotificationChannel(PKG, UID, "id", false);
+ assertNotNull(actual.getGroup());
+ assertEquals(IMPORTANCE_DEFAULT, actual.getImportance());
+
+ verify(mHandler, times(1)).requestSort();
+ }
+
+ @Test
public void testDumpChannelsJson() throws Exception {
final ApplicationInfo upgrade = new ApplicationInfo();
upgrade.targetSdkVersion = Build.VERSION_CODES.O;
@@ -1388,4 +1421,77 @@ public class RankingHelperTest extends NotificationTestCase {
assertEquals(newLabel, mHelper.getNotificationChannel(PKG, UID,
NotificationChannel.DEFAULT_CHANNEL_ID, false).getName());
}
+
+ @Test
+ public void testIsGroupBlocked_noGroup() throws Exception {
+ assertFalse(mHelper.isGroupBlocked(PKG, UID, null));
+
+ assertFalse(mHelper.isGroupBlocked(PKG, UID, "non existent group"));
+ }
+
+ @Test
+ public void testIsGroupBlocked_notBlocked() throws Exception {
+ NotificationChannelGroup group = new NotificationChannelGroup("id", "name");
+ mHelper.createNotificationChannelGroup(PKG, UID, group, true);
+
+ assertFalse(mHelper.isGroupBlocked(PKG, UID, group.getId()));
+ }
+
+ @Test
+ public void testIsGroupBlocked_blocked() throws Exception {
+ NotificationChannelGroup group = new NotificationChannelGroup("id", "name");
+ mHelper.createNotificationChannelGroup(PKG, UID, group, true);
+ group.setBlocked(true);
+ mHelper.createNotificationChannelGroup(PKG, UID, group, false);
+
+ assertTrue(mHelper.isGroupBlocked(PKG, UID, group.getId()));
+ }
+
+ @Test
+ public void testIsGroup_appCannotResetBlock() throws Exception {
+ NotificationChannelGroup group = new NotificationChannelGroup("id", "name");
+ mHelper.createNotificationChannelGroup(PKG, UID, group, true);
+ NotificationChannelGroup group2 = group.clone();
+ group2.setBlocked(true);
+ mHelper.createNotificationChannelGroup(PKG, UID, group2, false);
+ assertTrue(mHelper.isGroupBlocked(PKG, UID, group.getId()));
+
+ NotificationChannelGroup group3 = group.clone();
+ group3.setBlocked(false);
+ mHelper.createNotificationChannelGroup(PKG, UID, group3, true);
+ assertTrue(mHelper.isGroupBlocked(PKG, UID, group.getId()));
+ }
+
+ @Test
+ public void testGetNotificationChannelGroupWithChannels() throws Exception {
+ NotificationChannelGroup group = new NotificationChannelGroup("group", "");
+ NotificationChannelGroup other = new NotificationChannelGroup("something else", "");
+ mHelper.createNotificationChannelGroup(PKG, UID, group, true);
+ mHelper.createNotificationChannelGroup(PKG, UID, other, true);
+
+ NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
+ a.setGroup(group.getId());
+ NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_DEFAULT);
+ b.setGroup(other.getId());
+ NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT);
+ c.setGroup(group.getId());
+ NotificationChannel d = new NotificationChannel("d", "d", IMPORTANCE_DEFAULT);
+
+ mHelper.createNotificationChannel(PKG, UID, a, true);
+ mHelper.createNotificationChannel(PKG, UID, b, true);
+ mHelper.createNotificationChannel(PKG, UID, c, true);
+ mHelper.createNotificationChannel(PKG, UID, d, true);
+ mHelper.deleteNotificationChannel(PKG, UID, c.getId());
+
+ NotificationChannelGroup retrieved = mHelper.getNotificationChannelGroupWithChannels(
+ PKG, UID, group.getId(), true);
+ assertEquals(2, retrieved.getChannels().size());
+ compareChannels(a, findChannel(retrieved.getChannels(), a.getId()));
+ compareChannels(c, findChannel(retrieved.getChannels(), c.getId()));
+
+ retrieved = mHelper.getNotificationChannelGroupWithChannels(
+ PKG, UID, group.getId(), false);
+ assertEquals(1, retrieved.getChannels().size());
+ compareChannels(a, findChannel(retrieved.getChannels(), a.getId()));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
new file mode 100644
index 000000000000..50824e32e50d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/MagnificationGestureHandlerTest.java
@@ -0,0 +1,535 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.accessibility;
+
+import static android.util.ExceptionUtils.propagate;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_POINTER_DOWN;
+import static android.view.MotionEvent.ACTION_POINTER_UP;
+
+import static com.android.server.testutils.TestUtils.strictMock;
+
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.DebugUtils;
+import android.view.InputDevice;
+import android.view.MotionEvent;
+
+import com.android.server.testutils.OffsettableClock;
+import com.android.server.testutils.TestHandler;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.function.IntConsumer;
+
+
+@RunWith(AndroidJUnit4.class)
+public class MagnificationGestureHandlerTest {
+
+ public static final int STATE_IDLE = 1;
+ public static final int STATE_ZOOMED = 2;
+ public static final int STATE_2TAPS = 3;
+ public static final int STATE_ZOOMED_2TAPS = 4;
+ public static final int STATE_SHORTCUT_TRIGGERED = 5;
+ public static final int STATE_DRAGGING_TMP = 6;
+ public static final int STATE_DRAGGING = 7;
+ public static final int STATE_PANNING = 8;
+ public static final int STATE_SCALING_AND_PANNING = 9;
+
+
+ public static final int FIRST_STATE = STATE_IDLE;
+ public static final int LAST_STATE = STATE_SCALING_AND_PANNING;
+
+ // Co-prime x and y, to potentially catch x-y-swapped errors
+ public static final float DEFAULT_X = 301;
+ public static final float DEFAULT_Y = 299;
+
+ private Context mContext;
+ private AccessibilityManagerService mAms;
+ private MagnificationController mMagnificationController;
+ private OffsettableClock mClock;
+ private MagnificationGestureHandler mMgh;
+ private TestHandler mHandler;
+
+ @Before
+ public void setUp() {
+ mContext = InstrumentationRegistry.getContext();
+ mAms = new AccessibilityManagerService(mContext);
+ mMagnificationController = new MagnificationController(
+ mContext, mAms, /* lock */ new Object()) {
+ @Override
+ public boolean magnificationRegionContains(float x, float y) {
+ return true;
+ }
+
+ @Override
+ void setForceShowMagnifiableBounds(boolean show) {}
+ };
+ mMagnificationController.mRegistered = true;
+ mClock = new OffsettableClock.Stopped();
+
+ boolean detectTripleTap = true;
+ boolean detectShortcutTrigger = true;
+ mMgh = newInstance(detectTripleTap, detectShortcutTrigger);
+ }
+
+ @NonNull
+ public MagnificationGestureHandler newInstance(boolean detectTripleTap,
+ boolean detectShortcutTrigger) {
+ MagnificationGestureHandler h = new MagnificationGestureHandler(
+ mContext, mMagnificationController,
+ detectTripleTap, detectShortcutTrigger);
+ mHandler = new TestHandler(h.mDetectingStateHandler, mClock);
+ h.mDetectingStateHandler.mHandler = mHandler;
+ h.setNext(strictMock(EventStreamTransformation.class));
+ return h;
+ }
+
+ @Test
+ public void testInitialState_isIdle() {
+ assertIn(STATE_IDLE);
+ }
+
+ /**
+ * Covers paths to get to and back between each state and {@link #STATE_IDLE}
+ * This navigates between states using "canonical" paths, specified in
+ * {@link #goFromStateIdleTo} (for traversing away from {@link #STATE_IDLE}) and
+ * {@link #returnToNormalFrom} (for navigating back to {@link #STATE_IDLE})
+ */
+ @Test
+ public void testEachState_isReachableAndRecoverable() {
+ forEachState(state -> {
+ goFromStateIdleTo(state);
+ assertIn(state);
+
+ returnToNormalFrom(state);
+ try {
+ assertIn(STATE_IDLE);
+ } catch (AssertionError e) {
+ throw new AssertionError("Failed while testing state " + stateToString(state), e);
+ }
+ });
+ }
+
+ @Test
+ public void testStates_areMutuallyExclusive() {
+ forEachState(state1 -> {
+ forEachState(state2 -> {
+ if (state1 < state2) {
+ goFromStateIdleTo(state1);
+ try {
+ assertIn(state2);
+ fail("State " + stateToString(state1) + " also implies state "
+ + stateToString(state2) + stateDump());
+ } catch (AssertionError e) {
+ // expected
+ returnToNormalFrom(state1);
+ }
+ }
+ });
+ });
+ }
+
+ /**
+ * Covers edges of the graph not covered by "canonical" transitions specified in
+ * {@link #goFromStateIdleTo} and {@link #returnToNormalFrom}
+ */
+ @SuppressWarnings("Convert2MethodRef")
+ @Test
+ public void testAlternativeTransitions_areWorking() {
+ // A11y button followed by a tap&hold turns temporary "viewport dragging" zoom on
+ assertTransition(STATE_SHORTCUT_TRIGGERED, () -> {
+ send(downEvent());
+ fastForward1sec();
+ }, STATE_DRAGGING_TMP);
+
+ // A11y button followed by a tap turns zoom on
+ assertTransition(STATE_SHORTCUT_TRIGGERED, () -> tap(), STATE_ZOOMED);
+
+ // A11y button pressed second time negates the 1st press
+ assertTransition(STATE_SHORTCUT_TRIGGERED, () -> triggerShortcut(), STATE_IDLE);
+
+ // A11y button turns zoom off
+ assertTransition(STATE_ZOOMED, () -> triggerShortcut(), STATE_IDLE);
+
+
+ // Double tap times out while zoomed
+ assertTransition(STATE_ZOOMED_2TAPS, () -> {
+ allowEventDelegation();
+ fastForward1sec();
+ }, STATE_ZOOMED);
+
+ // tap+tap+swipe gets delegated
+ assertTransition(STATE_2TAPS, () -> {
+ allowEventDelegation();
+ swipe();
+ }, STATE_IDLE);
+ }
+
+ @Test
+ public void testNonTransitions_dontChangeState() {
+ // ACTION_POINTER_DOWN triggers event delegation if not magnifying
+ assertStaysIn(STATE_IDLE, () -> {
+ allowEventDelegation();
+ send(downEvent());
+ send(pointerEvent(ACTION_POINTER_DOWN, DEFAULT_X * 2, DEFAULT_Y));
+ });
+
+ // Long tap breaks the triple-tap detection sequence
+ Runnable tapAndLongTap = () -> {
+ allowEventDelegation();
+ tap();
+ longTap();
+ };
+ assertStaysIn(STATE_IDLE, tapAndLongTap);
+ assertStaysIn(STATE_ZOOMED, tapAndLongTap);
+
+ // Triple tap with delays in between doesn't count
+ Runnable slow3tap = () -> {
+ tap();
+ fastForward1sec();
+ tap();
+ fastForward1sec();
+ tap();
+ };
+ assertStaysIn(STATE_IDLE, slow3tap);
+ assertStaysIn(STATE_ZOOMED, slow3tap);
+ }
+
+ @Test
+ public void testDisablingTripleTap_removesInputLag() {
+ mMgh = newInstance(/* detect3tap */ false, /* detectShortcut */ true);
+ goFromStateIdleTo(STATE_IDLE);
+ allowEventDelegation();
+ tap();
+ // no fast forward
+ verify(mMgh.mNext, times(2)).onMotionEvent(any(), any(), anyInt());
+ }
+
+ private void assertTransition(int fromState, Runnable transitionAction, int toState) {
+ goFromStateIdleTo(fromState);
+ transitionAction.run();
+ assertIn(toState);
+ returnToNormalFrom(toState);
+ }
+
+ private void assertStaysIn(int state, Runnable action) {
+ assertTransition(state, action, state);
+ }
+
+ private void forEachState(IntConsumer action) {
+ for (int state = FIRST_STATE; state <= LAST_STATE; state++) {
+ action.accept(state);
+ }
+ }
+
+ private void allowEventDelegation() {
+ doNothing().when(mMgh.mNext).onMotionEvent(any(), any(), anyInt());
+ }
+
+ private void fastForward1sec() {
+ fastForward(1000);
+ }
+
+ private void fastForward(int ms) {
+ mClock.fastForward(ms);
+ mHandler.timeAdvance();
+ }
+
+ /**
+ * Asserts that {@link #mMgh the handler} is in the given {@code state}
+ */
+ private void assertIn(int state) {
+ switch (state) {
+
+ // Asserts on separate lines for accurate stack traces
+
+ case STATE_IDLE: {
+ check(tapCount() < 2, state);
+ check(!mMgh.mShortcutTriggered, state);
+ check(!isZoomed(), state);
+ } break;
+ case STATE_ZOOMED: {
+ check(isZoomed(), state);
+ check(tapCount() < 2, state);
+ } break;
+ case STATE_2TAPS: {
+ check(!isZoomed(), state);
+ check(tapCount() == 2, state);
+ } break;
+ case STATE_ZOOMED_2TAPS: {
+ check(isZoomed(), state);
+ check(tapCount() == 2, state);
+ } break;
+ case STATE_DRAGGING: {
+ check(mMgh.mCurrentState == MagnificationGestureHandler.STATE_VIEWPORT_DRAGGING,
+ state);
+ check(mMgh.mViewportDraggingStateHandler.mZoomedInBeforeDrag, state);
+ } break;
+ case STATE_DRAGGING_TMP: {
+ check(mMgh.mCurrentState == MagnificationGestureHandler.STATE_VIEWPORT_DRAGGING,
+ state);
+ check(!mMgh.mViewportDraggingStateHandler.mZoomedInBeforeDrag, state);
+ } break;
+ case STATE_SHORTCUT_TRIGGERED: {
+ check(mMgh.mShortcutTriggered, state);
+ check(!isZoomed(), state);
+ } break;
+ case STATE_PANNING: {
+ check(mMgh.mCurrentState == MagnificationGestureHandler.STATE_PANNING_SCALING,
+ state);
+ check(!mMgh.mPanningScalingStateHandler.mScaling, state);
+ } break;
+ case STATE_SCALING_AND_PANNING: {
+ check(mMgh.mCurrentState == MagnificationGestureHandler.STATE_PANNING_SCALING,
+ state);
+ check(mMgh.mPanningScalingStateHandler.mScaling, state);
+ } break;
+ default: throw new IllegalArgumentException("Illegal state: " + state);
+ }
+ }
+
+ /**
+ * Defines a "canonical" path from {@link #STATE_IDLE} to {@code state}
+ */
+ private void goFromStateIdleTo(int state) {
+ try {
+ switch (state) {
+ case STATE_IDLE: {
+ mMgh.clearAndTransitionToStateDetecting();
+ } break;
+ case STATE_2TAPS: {
+ goFromStateIdleTo(STATE_IDLE);
+ tap();
+ tap();
+ } break;
+ case STATE_ZOOMED: {
+ if (mMgh.mDetectTripleTap) {
+ goFromStateIdleTo(STATE_2TAPS);
+ tap();
+ } else {
+ goFromStateIdleTo(STATE_SHORTCUT_TRIGGERED);
+ tap();
+ }
+ } break;
+ case STATE_ZOOMED_2TAPS: {
+ goFromStateIdleTo(STATE_ZOOMED);
+ tap();
+ tap();
+ } break;
+ case STATE_DRAGGING: {
+ goFromStateIdleTo(STATE_ZOOMED_2TAPS);
+ send(downEvent());
+ fastForward1sec();
+ } break;
+ case STATE_DRAGGING_TMP: {
+ goFromStateIdleTo(STATE_2TAPS);
+ send(downEvent());
+ fastForward1sec();
+ } break;
+ case STATE_SHORTCUT_TRIGGERED: {
+ goFromStateIdleTo(STATE_IDLE);
+ triggerShortcut();
+ } break;
+ case STATE_PANNING: {
+ goFromStateIdleTo(STATE_ZOOMED);
+ send(downEvent());
+ send(pointerEvent(ACTION_POINTER_DOWN, DEFAULT_X * 2, DEFAULT_Y));
+ } break;
+ case STATE_SCALING_AND_PANNING: {
+ goFromStateIdleTo(STATE_PANNING);
+ send(pointerEvent(ACTION_MOVE, DEFAULT_X * 2, DEFAULT_Y * 3));
+ send(pointerEvent(ACTION_MOVE, DEFAULT_X * 2, DEFAULT_Y * 4));
+ } break;
+ default:
+ throw new IllegalArgumentException("Illegal state: " + state);
+ }
+ } catch (Throwable t) {
+ throw new RuntimeException("Failed to go to state " + stateToString(state), t);
+ }
+ }
+
+ /**
+ * Defines a "canonical" path from {@code state} to {@link #STATE_IDLE}
+ */
+ private void returnToNormalFrom(int state) {
+ switch (state) {
+ case STATE_IDLE: {
+ // no op
+ } break;
+ case STATE_2TAPS: {
+ allowEventDelegation();
+ fastForward1sec();
+ } break;
+ case STATE_ZOOMED: {
+ if (mMgh.mDetectTripleTap) {
+ tap();
+ tap();
+ returnToNormalFrom(STATE_ZOOMED_2TAPS);
+ } else {
+ triggerShortcut();
+ }
+ } break;
+ case STATE_ZOOMED_2TAPS: {
+ tap();
+ } break;
+ case STATE_DRAGGING: {
+ send(upEvent());
+ returnToNormalFrom(STATE_ZOOMED);
+ } break;
+ case STATE_DRAGGING_TMP: {
+ send(upEvent());
+ } break;
+ case STATE_SHORTCUT_TRIGGERED: {
+ triggerShortcut();
+ } break;
+ case STATE_PANNING: {
+ send(pointerEvent(ACTION_POINTER_UP, DEFAULT_X * 2, DEFAULT_Y));
+ send(upEvent());
+ returnToNormalFrom(STATE_ZOOMED);
+ } break;
+ case STATE_SCALING_AND_PANNING: {
+ returnToNormalFrom(STATE_PANNING);
+ } break;
+ default: throw new IllegalArgumentException("Illegal state: " + state);
+ }
+ }
+
+ private void check(boolean condition, int expectedState) {
+ if (!condition) {
+ fail("Expected to be in state " + stateToString(expectedState) + stateDump());
+ }
+ }
+
+ private boolean isZoomed() {
+ return mMgh.mMagnificationController.isMagnifying();
+ }
+
+ private int tapCount() {
+ return mMgh.mDetectingStateHandler.tapCount();
+ }
+
+ private static String stateToString(int state) {
+ return DebugUtils.valueToString(MagnificationGestureHandlerTest.class, "STATE_", state);
+ }
+
+ private void tap() {
+ MotionEvent downEvent = downEvent();
+ send(downEvent);
+ send(upEvent(downEvent.getDownTime()));
+ }
+
+ private void swipe() {
+ MotionEvent downEvent = downEvent();
+ send(downEvent);
+ send(moveEvent(DEFAULT_X * 2, DEFAULT_Y * 2));
+ send(upEvent(downEvent.getDownTime()));
+ }
+
+ private void longTap() {
+ MotionEvent downEvent = downEvent();
+ send(downEvent);
+ fastForward(2000);
+ send(upEvent(downEvent.getDownTime()));
+ }
+
+ private void triggerShortcut() {
+ mMgh.notifyShortcutTriggered();
+ }
+
+ private void send(MotionEvent event) {
+ event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+ try {
+ mMgh.onMotionEvent(event, event, /* policyFlags */ 0);
+ } catch (Throwable t) {
+ throw new RuntimeException("Exception while handling " + event, t);
+ }
+ fastForward(1);
+ }
+
+ private MotionEvent moveEvent(float x, float y) {
+ return MotionEvent.obtain(defaultDownTime(), mClock.now(), ACTION_MOVE, x, y, 0);
+ }
+
+ private MotionEvent downEvent() {
+ return MotionEvent.obtain(mClock.now(), mClock.now(),
+ ACTION_DOWN, DEFAULT_X, DEFAULT_Y, 0);
+ }
+
+ private MotionEvent upEvent() {
+ return upEvent(defaultDownTime());
+ }
+
+ private MotionEvent upEvent(long downTime) {
+ return MotionEvent.obtain(downTime, mClock.now(),
+ MotionEvent.ACTION_UP, DEFAULT_X, DEFAULT_Y, 0);
+ }
+
+ private long defaultDownTime() {
+ MotionEvent lastDown = mMgh.mDetectingStateHandler.mLastDown;
+ return lastDown == null ? mClock.now() - 1 : lastDown.getDownTime();
+ }
+
+ private MotionEvent pointerEvent(int action, float x, float y) {
+ MotionEvent.PointerProperties defPointerProperties = new MotionEvent.PointerProperties();
+ defPointerProperties.id = 0;
+ defPointerProperties.toolType = MotionEvent.TOOL_TYPE_FINGER;
+ MotionEvent.PointerProperties pointerProperties = new MotionEvent.PointerProperties();
+ pointerProperties.id = 1;
+ pointerProperties.toolType = MotionEvent.TOOL_TYPE_FINGER;
+
+ MotionEvent.PointerCoords defPointerCoords = new MotionEvent.PointerCoords();
+ defPointerCoords.x = DEFAULT_X;
+ defPointerCoords.y = DEFAULT_Y;
+ MotionEvent.PointerCoords pointerCoords = new MotionEvent.PointerCoords();
+ pointerCoords.x = x;
+ pointerCoords.y = y;
+
+ return MotionEvent.obtain(
+ /* downTime */ mClock.now(),
+ /* eventTime */ mClock.now(),
+ /* action */ action,
+ /* pointerCount */ 2,
+ /* pointerProperties */ new MotionEvent.PointerProperties[] {
+ defPointerProperties, pointerProperties },
+ /* pointerCoords */ new MotionEvent.PointerCoords[] { defPointerCoords, pointerCoords },
+ /* metaState */ 0,
+ /* buttonState */ 0,
+ /* xPrecision */ 1.0f,
+ /* yPrecision */ 1.0f,
+ /* deviceId */ 0,
+ /* edgeFlags */ 0,
+ /* source */ InputDevice.SOURCE_TOUCHSCREEN,
+ /* flags */ 0);
+ }
+
+ private String stateDump() {
+ return "\nCurrent state dump:\n" + mMgh + "\n" + mHandler.getPendingMessages();
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 55ecd7ade878..f3c00b197763 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -117,7 +117,7 @@ public class ActivityTestsBase {
intent.setComponent(component);
final TaskRecord task = new TaskRecord(service, 0, aInfo, intent /*intent*/,
- null /*_taskDescription*/, new ActivityManager.TaskThumbnailInfo());
+ null /*_taskDescription*/);
final ActivityStack stack = service.mStackSupervisor.getStack(stackId,
true /*createStaticStackIfNeeded*/, true /*onTop*/);
service.mStackSupervisor.setFocusStackUnchecked("test", stack);
diff --git a/services/tests/servicestests/src/com/android/server/backup/BackupPasswordManagerTest.java b/services/tests/servicestests/src/com/android/server/backup/BackupPasswordManagerTest.java
index 04c02510cb3d..bc162977de2b 100644
--- a/services/tests/servicestests/src/com/android/server/backup/BackupPasswordManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/BackupPasswordManagerTest.java
@@ -16,7 +16,7 @@
package com.android.server.backup;
-import static com.android.server.testutis.TestUtils.assertExpectException;
+import static com.android.server.testutils.TestUtils.assertExpectException;
import static com.google.common.truth.Truth.assertThat;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index e3faa5280859..e8a1811e1a63 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -22,7 +22,7 @@ import static android.os.UserManagerInternal.CAMERA_DISABLED_GLOBALLY;
import static android.os.UserManagerInternal.CAMERA_DISABLED_LOCALLY;
import static android.os.UserManagerInternal.CAMERA_NOT_DISABLED;
-import static com.android.server.testutis.TestUtils.assertExpectException;
+import static com.android.server.testutils.TestUtils.assertExpectException;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
@@ -54,11 +54,11 @@ import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.PasswordMetrics;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
-import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.pm.StringParceledListSlice;
import android.content.pm.UserInfo;
import android.graphics.Color;
@@ -167,6 +167,11 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mServiceContext.binder.callingUid = DpmMockContext.CALLER_UID;
when(getServices().packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN)))
.thenReturn(true);
+ doReturn(Collections.singletonList(new ResolveInfo()))
+ .when(getServices().packageManager).queryBroadcastReceiversAsUser(
+ any(Intent.class),
+ anyInt(),
+ any(UserHandle.class));
// By default, pretend all users are running and unlocked.
when(getServices().userManager.isUserUnlocked(anyInt())).thenReturn(true);
diff --git a/services/tests/servicestests/src/com/android/server/testutils/OffsettableClock.java b/services/tests/servicestests/src/com/android/server/testutils/OffsettableClock.java
new file mode 100644
index 000000000000..8dabbc4d4356
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/testutils/OffsettableClock.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.testutils;
+
+import android.os.SystemClock;
+
+import java.util.function.LongSupplier;
+
+/**
+ * A time supplier (in the format of a {@code long} as the amount of milliseconds) similar
+ * to {@link SystemClock#uptimeMillis()}, but with the ability to {@link #fastForward}
+ * and {@link #rewind}
+ *
+ * Implements {@link LongSupplier} to be interchangeable with {@code SystemClock::uptimeMillis}
+ *
+ * Can be provided to {@link TestHandler} to "mock time" for the delayed execution testing
+ *
+ * @see OffsettableClock.Stopped for a version of this clock that does not advance on its own
+ */
+public class OffsettableClock implements LongSupplier {
+ private long mOffset = 0L;
+
+ /**
+ * @return Current time in milliseconds, according to this clock
+ */
+ public long now() {
+ return realNow() + mOffset;
+ }
+
+ /**
+ * Can be overriden with a constant for a clock that stands still, and is only ever moved
+ * manually
+ */
+ public long realNow() {
+ return SystemClock.uptimeMillis();
+ }
+
+ public void fastForward(long timeMs) {
+ mOffset += timeMs;
+ }
+ public void rewind(long timeMs) {
+ fastForward(-timeMs);
+ }
+ public void reset() {
+ mOffset = 0;
+ }
+
+ /** @deprecated Only present for {@link LongSupplier} contract */
+ @Override
+ @Deprecated
+ public long getAsLong() {
+ return now();
+ }
+
+ /**
+ * An {@link OffsettableClock} that does not advance with real time, and can only be
+ * advanced manually via {@link #fastForward}
+ */
+ public static class Stopped extends OffsettableClock {
+ @Override
+ public long realNow() {
+ return 0L;
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java b/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java
new file mode 100644
index 000000000000..2d4bc0f8b7d0
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/testutils/TestHandler.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.testutils;
+
+
+import static android.util.ExceptionUtils.getRootCause;
+import static android.util.ExceptionUtils.propagate;
+
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.util.ArrayMap;
+
+import java.util.Map;
+import java.util.PriorityQueue;
+import java.util.function.LongSupplier;
+
+/**
+ * A test {@link Handler} that stores incoming {@link Message}s and {@link Runnable callbacks}
+ * in a {@link PriorityQueue} based on time, to be manually processed later in a correct order
+ * either all together with {@link #flush}, or only those due at the current time with
+ * {@link #timeAdvance}.
+ *
+ * For the latter use case this also supports providing a custom clock (in a format of a
+ * milliseconds-returning {@link LongSupplier}), that will be used for storing the messages'
+ * timestamps to be posted at, and checked against during {@link #timeAdvance}.
+ *
+ * This allows to test code that uses {@link Handler}'s delayed invocation capabilities, such as
+ * {@link Handler#sendMessageDelayed} or {@link Handler#postDelayed} without resorting to
+ * synchronously {@link Thread#sleep}ing in your test.
+ *
+ * @see OffsettableClock for a useful custom clock implementation to use with this handler
+ */
+public class TestHandler extends Handler {
+ private static final LongSupplier DEFAULT_CLOCK = SystemClock::uptimeMillis;
+
+ private final PriorityQueue<MsgInfo> mMessages = new PriorityQueue<>();
+ /**
+ * Map of: {@code message id -> count of such messages currently pending }
+ */
+ // Boxing is ok here - both msg ids and their pending counts tend to be well below 128
+ private final Map<Integer, Integer> mPendingMsgTypeCounts = new ArrayMap<>();
+ private final LongSupplier mClock;
+
+ public TestHandler(Callback callback) {
+ this(callback, DEFAULT_CLOCK);
+ }
+
+ public TestHandler(Callback callback, LongSupplier clock) {
+ super(callback);
+ mClock = clock;
+ }
+
+ @Override
+ public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
+ mPendingMsgTypeCounts.put(msg.what,
+ mPendingMsgTypeCounts.getOrDefault(msg.what, 0) + 1);
+
+ // uptimeMillis is an absolute time obtained as SystemClock.uptimeMillis() + offsetMillis
+ // if custom clock is given, recalculate the time with regards to it
+ if (mClock != DEFAULT_CLOCK) {
+ uptimeMillis = uptimeMillis - SystemClock.uptimeMillis() + mClock.getAsLong();
+ }
+
+ // post a dummy queue entry to keep track of message removal
+ return super.sendMessageAtTime(msg, Long.MAX_VALUE)
+ && mMessages.add(new MsgInfo(Message.obtain(msg), uptimeMillis));
+ }
+
+ /** @see TestHandler */
+ public void timeAdvance() {
+ long now = mClock.getAsLong();
+ while (!mMessages.isEmpty() && mMessages.peek().sendTime <= now) {
+ dispatch(mMessages.poll());
+ }
+ }
+
+ /**
+ * Dispatch all messages in order
+ *
+ * @see TestHandler
+ */
+ public void flush() {
+ MsgInfo msg;
+ while ((msg = mMessages.poll()) != null) {
+ dispatch(msg);
+ }
+ }
+
+ public PriorityQueue<MsgInfo> getPendingMessages() {
+ return new PriorityQueue<>(mMessages);
+ }
+
+ private void dispatch(MsgInfo msg) {
+ int msgId = msg.message.what;
+
+ if (!hasMessages(msgId)) {
+ // Handler.removeMessages(msgId) must have been called
+ return;
+ }
+
+ try {
+ Integer pendingMsgCount = mPendingMsgTypeCounts.getOrDefault(msgId, 0);
+ if (pendingMsgCount <= 1) {
+ removeMessages(msgId);
+ }
+ mPendingMsgTypeCounts.put(msgId, pendingMsgCount - 1);
+
+ dispatchMessage(msg.message);
+ } catch (Throwable t) {
+ // Append stack trace of this message being posted as a cause for a helpful
+ // test error message
+ throw propagate(getRootCause(t).initCause(msg.postPoint));
+ } finally {
+ msg.message.recycle();
+ }
+ }
+
+ private class MsgInfo implements Comparable<MsgInfo> {
+ public final Message message;
+ public final long sendTime;
+ public final RuntimeException postPoint;
+
+ private MsgInfo(Message message, long sendTime) {
+ this.message = message;
+ this.sendTime = sendTime;
+ this.postPoint = new RuntimeException("Message originated from here:");
+ }
+
+ @Override
+ public int compareTo(MsgInfo o) {
+ return (int) (sendTime - o.sendTime);
+ }
+
+ @Override
+ public String toString() {
+ return "MsgInfo{" +
+ "message=" + message +
+ ", sendTime=" + sendTime +
+ '}';
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/testutis/TestUtils.java b/services/tests/servicestests/src/com/android/server/testutils/TestUtils.java
index 88289888b0dd..b200293ee916 100644
--- a/services/tests/servicestests/src/com/android/server/testutis/TestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/testutils/TestUtils.java
@@ -13,12 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.server.testutis;
+package com.android.server.testutils;
import android.test.MoreAsserts;
import junit.framework.Assert;
+import org.mockito.Mockito;
+import org.mockito.stubbing.Answer;
+
public class TestUtils {
private TestUtils() {
}
@@ -44,4 +47,17 @@ public class TestUtils {
Assert.fail("Expected exception type " + expectedExceptionType.getName()
+ " was not thrown");
}
+
+ /**
+ * EasyMock-style "strict" mock that throws immediately on any interaction that was not
+ * explicitly allowed.
+ *
+ * You can allow certain method calls on a whitelist basis by stubbing them e.g. with
+ * {@link Mockito#doAnswer}, {@link Mockito#doNothing}, etc.
+ */
+ public static <T> T strictMock(Class<T> c) {
+ return Mockito.mock(c, (Answer) invocation -> {
+ throw new AssertionError("Unexpected invocation: " + invocation);
+ });
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
index 9d32496c7817..0081214a24da 100644
--- a/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/BoundsAnimationControllerTests.java
@@ -126,6 +126,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
boolean mMovedToFullscreen;
boolean mAnimationStarted;
boolean mSchedulePipModeChangedOnStart;
+ boolean mForcePipModeChangedCallback;
boolean mAnimationEnded;
Rect mAnimationEndFinalStackBounds;
boolean mSchedulePipModeChangedOnEnd;
@@ -140,6 +141,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
mAnimationStarted = false;
mAnimationEnded = false;
mAnimationEndFinalStackBounds = null;
+ mForcePipModeChangedCallback = false;
mSchedulePipModeChangedOnStart = false;
mSchedulePipModeChangedOnEnd = false;
mStackBounds = from;
@@ -148,10 +150,11 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
}
@Override
- public void onAnimationStart(boolean schedulePipModeChangedCallback) {
+ public void onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate) {
mAwaitingAnimationStart = false;
mAnimationStarted = true;
mSchedulePipModeChangedOnStart = schedulePipModeChangedCallback;
+ mForcePipModeChangedCallback = forceUpdate;
}
@Override
@@ -232,7 +235,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
return this;
}
- BoundsAnimationDriver restart(Rect to) {
+ BoundsAnimationDriver restart(Rect to, boolean expectStartedAndPipModeChangedCallback) {
if (mAnimator == null) {
throw new IllegalArgumentException("Call start() to start a new animation");
}
@@ -251,8 +254,15 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
assertSame(oldAnimator, mAnimator);
}
- // No animation start for replacing animation
- assertTrue(!mTarget.mAnimationStarted);
+ if (expectStartedAndPipModeChangedCallback) {
+ // Replacing animation with pending pip mode changed callback, ensure we update
+ assertTrue(mTarget.mAnimationStarted);
+ assertTrue(mTarget.mSchedulePipModeChangedOnStart);
+ assertTrue(mTarget.mForcePipModeChangedCallback);
+ } else {
+ // No animation start for replacing animation
+ assertTrue(!mTarget.mAnimationStarted);
+ }
mTarget.mAnimationStarted = true;
return this;
}
@@ -467,7 +477,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
- .restart(BOUNDS_FLOATING)
+ .restart(BOUNDS_FLOATING, false /* expectStartedAndPipModeChangedCallback */)
.end()
.expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN);
}
@@ -478,7 +488,8 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
- .restart(BOUNDS_SMALLER_FLOATING)
+ .restart(BOUNDS_SMALLER_FLOATING,
+ false /* expectStartedAndPipModeChangedCallback */)
.end()
.expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN);
}
@@ -486,10 +497,12 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
@UiThreadTest
@Test
public void testFullscreenToFloatingCancelFromAnimationToFullscreenBounds() throws Exception {
+ // When animating from fullscreen and the animation is interruped, we expect the animation
+ // start callback to be made, with a forced pip mode change callback
mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
.expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
- .restart(BOUNDS_FULL)
+ .restart(BOUNDS_FULL, true /* expectStartedAndPipModeChangedCallback */)
.end()
.expectEnded(!SCHEDULE_PIP_MODE_CHANGED, MOVE_TO_FULLSCREEN);
}
@@ -512,7 +525,7 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
.expectStarted(SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
- .restart(BOUNDS_FULL)
+ .restart(BOUNDS_FULL, false /* expectStartedAndPipModeChangedCallback */)
.end()
.expectEnded(!SCHEDULE_PIP_MODE_CHANGED, MOVE_TO_FULLSCREEN);
}
@@ -523,7 +536,8 @@ public class BoundsAnimationControllerTests extends WindowTestsBase {
mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
.expectStarted(SCHEDULE_PIP_MODE_CHANGED)
.update(0.25f)
- .restart(BOUNDS_SMALLER_FLOATING)
+ .restart(BOUNDS_SMALLER_FLOATING,
+ false /* expectStartedAndPipModeChangedCallback */)
.end()
.expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN);
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/ConfigurationContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/ConfigurationContainerTests.java
index 0f9b7217bd24..d441df024599 100644
--- a/services/tests/servicestests/src/com/android/server/wm/ConfigurationContainerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/ConfigurationContainerTests.java
@@ -16,24 +16,30 @@
package com.android.server.wm;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+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_REVERSE_PORTRAIT;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import android.content.res.Configuration;
import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
-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_REVERSE_PORTRAIT;
-import static org.junit.Assert.assertEquals;
-
/**
* Test class for {@link ConfigurationContainer}.
*
@@ -201,6 +207,62 @@ public class ConfigurationContainerTests {
assertEquals(mergedConfig2, child2.getConfiguration());
}
+ @Test
+ public void testSetWindowingMode() throws Exception {
+ final TestConfigurationContainer root = new TestConfigurationContainer();
+ root.setWindowingMode(WINDOWING_MODE_UNDEFINED);
+ final TestConfigurationContainer child = root.addChild();
+ child.setWindowingMode(WINDOWING_MODE_FREEFORM);
+ assertEquals(WINDOWING_MODE_UNDEFINED, root.getWindowingMode());
+ assertEquals(WINDOWING_MODE_FREEFORM, child.getWindowingMode());
+
+ root.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ assertEquals(WINDOWING_MODE_FULLSCREEN, root.getWindowingMode());
+ assertEquals(WINDOWING_MODE_FREEFORM, child.getWindowingMode());
+ }
+
+ @Test
+ public void testSetActivityType() throws Exception {
+ final TestConfigurationContainer root = new TestConfigurationContainer();
+ root.setActivityType(ACTIVITY_TYPE_UNDEFINED);
+ final TestConfigurationContainer child = root.addChild();
+ child.setActivityType(ACTIVITY_TYPE_STANDARD);
+ assertEquals(ACTIVITY_TYPE_UNDEFINED, root.getActivityType());
+ assertEquals(ACTIVITY_TYPE_STANDARD, child.getActivityType());
+
+ boolean gotException = false;
+ try {
+ // Can't change activity type once set.
+ child.setActivityType(ACTIVITY_TYPE_HOME);
+ } catch (IllegalStateException e) {
+ gotException = true;
+ }
+ assertTrue("Can't change activity type once set.", gotException);
+
+ gotException = false;
+ try {
+ // Parent can't change child's activity type once set.
+ root.setActivityType(ACTIVITY_TYPE_HOME);
+ } catch (IllegalStateException e) {
+ gotException = true;
+ }
+ assertTrue("Parent can't change activity type once set.", gotException);
+ assertEquals(ACTIVITY_TYPE_HOME, root.getActivityType());
+
+ final TestConfigurationContainer child2 = new TestConfigurationContainer();
+ child2.setActivityType(ACTIVITY_TYPE_RECENTS);
+
+ gotException = false;
+ try {
+ // Can't re-parent to a different activity type.
+ root.addChild(child2);
+ } catch (IllegalStateException e) {
+ gotException = true;
+ }
+ assertTrue("Can't re-parent to a different activity type.", gotException);
+
+ }
+
/**
* Contains minimal implementation of {@link ConfigurationContainer}'s abstract behavior needed
* for testing.
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
index a1ff2d7f9267..3f75b412d100 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowConfigurationTests.java
@@ -27,8 +27,9 @@ import android.support.test.runner.AndroidJUnit4;
import android.view.DisplayInfo;
import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOW_CONFIG_APP_BOUNDS;
import static android.app.WindowConfiguration.WINDOW_CONFIG_WINDOWING_MODE;
import static android.content.pm.ActivityInfo.CONFIG_WINDOW_CONFIGURATION;
@@ -118,6 +119,22 @@ public class WindowConfigurationTests extends WindowTestsBase {
assertEquals(blankWinConfig.compareTo(winConfig1), 1);
}
+ @Test
+ public void testSetActivityType() throws Exception {
+ final WindowConfiguration config = new WindowConfiguration();
+ config.setActivityType(ACTIVITY_TYPE_HOME);
+ assertEquals(ACTIVITY_TYPE_HOME, config.getActivityType());
+
+ boolean gotException = false;
+ try {
+ // Can't change activity type once set.
+ config.setActivityType(ACTIVITY_TYPE_STANDARD);
+ } catch (IllegalStateException e) {
+ gotException = true;
+ }
+ assertTrue("Can't change activity type once set.", gotException);
+ }
+
/** Ensures the configuration app bounds at the root level match the app dimensions. */
@Test
public void testAppBounds_RootConfigurationBounds() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
index 6e253e743ddb..df3f7553e83c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowFrameTests.java
@@ -75,7 +75,7 @@ public class WindowFrameTests extends WindowTestsBase {
final Rect mInsetBounds = new Rect();
boolean mFullscreenForTest = true;
TaskWithBounds(Rect bounds) {
- super(0, mStubStack, 0, sWm, null, null, 0, false, false, new TaskDescription(), null);
+ super(0, mStubStack, 0, sWm, null, null, 0, false, new TaskDescription(), null);
mBounds = bounds;
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
index 40c79bbb183d..ebe00ce8d51d 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
@@ -67,7 +67,7 @@ public class WindowTestUtils {
public static Task createTaskInStack(WindowManagerService service, TaskStack stack,
int userId) {
final Task newTask = new Task(sNextTaskId++, stack, userId, service, null, EMPTY, 0, false,
- false, new ActivityManager.TaskDescription(), null);
+ new ActivityManager.TaskDescription(), null);
stack.addTask(newTask, POSITION_TOP);
return newTask;
}
@@ -175,10 +175,9 @@ public class WindowTestUtils {
TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
- boolean homeTask, TaskWindowContainerController controller) {
+ TaskWindowContainerController controller) {
super(taskId, stack, userId, service, bounds, overrideConfig, resizeMode,
- supportsPictureInPicture, homeTask, new ActivityManager.TaskDescription(),
- controller);
+ supportsPictureInPicture, new ActivityManager.TaskDescription(), controller);
}
boolean shouldDeferRemoval() {
@@ -229,7 +228,7 @@ public class WindowTestUtils {
}
}, stackController, 0 /* userId */, null /* bounds */,
EMPTY /* overrideConfig*/, RESIZE_MODE_UNRESIZEABLE,
- false /* supportsPictureInPicture */, false /* homeTask*/, true /* toTop*/,
+ false /* supportsPictureInPicture */, true /* toTop*/,
true /* showForAllUsers */, new ActivityManager.TaskDescription(),
stackController.mService);
}
@@ -237,9 +236,9 @@ public class WindowTestUtils {
@Override
TestTask createTask(int taskId, TaskStack stack, int userId, Rect bounds,
Configuration overrideConfig, int resizeMode, boolean supportsPictureInPicture,
- boolean homeTask, ActivityManager.TaskDescription taskDescription) {
+ ActivityManager.TaskDescription taskDescription) {
return new TestTask(taskId, stack, userId, mService, bounds, overrideConfig, resizeMode,
- supportsPictureInPicture, homeTask, this);
+ supportsPictureInPicture, this);
}
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/ByteStream.java b/services/usb/java/com/android/server/usb/descriptors/ByteStream.java
index d678931fd01a..1e823b63d5b2 100644
--- a/services/usb/java/com/android/server/usb/descriptors/ByteStream.java
+++ b/services/usb/java/com/android/server/usb/descriptors/ByteStream.java
@@ -15,7 +15,11 @@
*/
package com.android.server.usb.descriptors;
+// Framework builds and Android Studio builds use different imports for NonNull.
+// This one for Framework builds
import android.annotation.NonNull;
+// this one in the AndroidStudio project
+// import android.support.annotation.NonNull;
/**
* @hide
@@ -23,7 +27,7 @@ import android.annotation.NonNull;
* but with the capability to "back up" in situations where the parser discovers that a
* UsbDescriptor has overrun its length.
*/
-public class ByteStream {
+public final class ByteStream {
private static final String TAG = "ByteStream";
/** The byte array being wrapped */
@@ -104,6 +108,20 @@ public class ByteStream {
}
/**
+ * @return the next byte from the stream and advances the stream and the read count. Note
+ * that this is an unsigned byte encoded in a Java int.
+ * @throws IndexOutOfBoundsException
+ */
+ public int getUnsignedByte() {
+ if (available() > 0) {
+ mReadCount++;
+ return mBytes[mIndex++] & 0x000000FF;
+ } else {
+ throw new IndexOutOfBoundsException();
+ }
+ }
+
+ /**
* Reads 2 bytes in *little endian format* from the stream and composes a 16-bit integer.
* As we are storing the 2-byte value in a 4-byte integer, the upper 2 bytes are always
* 0, essentially making the returned value *unsigned*.
@@ -111,11 +129,11 @@ public class ByteStream {
* next 2 bytes in the stream.
* @throws IndexOutOfBoundsException
*/
- public int unpackUsbWord() {
+ public int unpackUsbShort() {
if (available() >= 2) {
- int b0 = getByte();
- int b1 = getByte();
- return ((b1 << 8) & 0x0000FF00) | (b0 & 0x000000FF);
+ int b0 = getUnsignedByte();
+ int b1 = getUnsignedByte();
+ return (b1 << 8) | b0;
} else {
throw new IndexOutOfBoundsException();
}
@@ -131,16 +149,32 @@ public class ByteStream {
*/
public int unpackUsbTriple() {
if (available() >= 3) {
- int b0 = getByte();
- int b1 = getByte();
- int b2 = getByte();
- return ((b2 << 16) & 0x00FF0000) | ((b1 << 8) & 0x0000FF00) | (b0 & 0x000000FF);
+ int b0 = getUnsignedByte();
+ int b1 = getUnsignedByte();
+ int b2 = getUnsignedByte();
+ return (b2 << 16) | (b1 << 8) | b0;
} else {
throw new IndexOutOfBoundsException();
}
}
/**
+ * Reads 4 bytes in *little endian format* from the stream and composes a 32-bit integer.
+ * @return The 32-bit integer encoded by the next 4 bytes in the stream.
+ * @throws IndexOutOfBoundsException
+ */
+ public int unpackUsbInt() {
+ if (available() >= 4) {
+ int b0 = getUnsignedByte();
+ int b1 = getUnsignedByte();
+ int b2 = getUnsignedByte();
+ int b3 = getUnsignedByte();
+ return (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
+ } else {
+ throw new IndexOutOfBoundsException();
+ }
+ }
+ /**
* Advances the logical position in the stream. Affects the running count also.
* @param numBytes The number of bytes to advance.
* @throws IndexOutOfBoundsException
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACHeader.java b/services/usb/java/com/android/server/usb/descriptors/Usb10ACHeader.java
index e31438c58e06..a35b46318e23 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACHeader.java
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb10ACHeader.java
@@ -15,18 +15,16 @@
*/
package com.android.server.usb.descriptors;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
/**
* @hide
* An audio class-specific Interface Header.
* see audio10.pdf section 4.3.2
*/
-public class UsbACHeader extends UsbACInterface {
- private static final String TAG = "ACHeader";
+public final class Usb10ACHeader extends UsbACHeaderInterface {
+ private static final String TAG = "Usb10ACHeader";
- private int mADCRelease; // 3:2 Audio Device Class Specification Release (BCD).
- private int mTotalLength; // 5:2 Total number of bytes returned for the class-specific
- // AudioControl interface descriptor. Includes the combined length
- // of this descriptor header and all Unit and Terminal descriptors.
private byte mNumInterfaces = 0; // 7:1 The number of AudioStreaming and MIDIStreaming
// interfaces in the Audio Interface Collection to which this
// AudioControl interface belongs: n
@@ -34,16 +32,8 @@ public class UsbACHeader extends UsbACInterface {
// numbers associate with this endpoint
private byte mControls; // Vers 2.0 thing
- public UsbACHeader(int length, byte type, byte subtype, byte subclass) {
- super(length, type, subtype, subclass);
- }
-
- public int getADCRelease() {
- return mADCRelease;
- }
-
- public int getTotalLength() {
- return mTotalLength;
+ public Usb10ACHeader(int length, byte type, byte subtype, byte subclass, int spec) {
+ super(length, type, subtype, subclass, spec);
}
public byte getNumInterfaces() {
@@ -60,9 +50,8 @@ public class UsbACHeader extends UsbACInterface {
@Override
public int parseRawDescriptors(ByteStream stream) {
- mADCRelease = stream.unpackUsbWord();
- mTotalLength = stream.unpackUsbWord();
+ mTotalLength = stream.unpackUsbShort();
if (mADCRelease >= 0x200) {
mControls = stream.getByte();
} else {
@@ -75,4 +64,30 @@ public class UsbACHeader extends UsbACInterface {
return mLength;
}
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.openList();
+ int numInterfaces = getNumInterfaces();
+ StringBuilder sb = new StringBuilder();
+ sb.append("" + numInterfaces + " Interfaces");
+ if (numInterfaces > 0) {
+ sb.append(" [");
+ byte[] interfaceNums = getInterfaceNums();
+ if (interfaceNums != null) {
+ for (int index = 0; index < numInterfaces; index++) {
+ sb.append("" + interfaceNums[index]);
+ if (index < numInterfaces - 1) {
+ sb.append(" ");
+ }
+ }
+ }
+ sb.append("]");
+ }
+ canvas.writeListItem(sb.toString());
+ canvas.writeListItem("Controls: " + ReportCanvas.getHexString(getControls()));
+ canvas.closeList();
+ }
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACInputTerminal.java b/services/usb/java/com/android/server/usb/descriptors/Usb10ACInputTerminal.java
index 653a7de5457e..2363c4dd8009 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACInputTerminal.java
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb10ACInputTerminal.java
@@ -15,13 +15,15 @@
*/
package com.android.server.usb.descriptors;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
/**
* @hide
* An audio class-specific Input Terminal interface.
* see audio10.pdf section 4.3.2.1
*/
-public class UsbACInputTerminal extends UsbACTerminal {
- private static final String TAG = "ACInputTerminal";
+public final class Usb10ACInputTerminal extends UsbACTerminal {
+ private static final String TAG = "Usb10ACInputTerminal";
private byte mNrChannels; // 7:1 1 Channel (0x01)
// Number of logical output channels in the
@@ -30,7 +32,7 @@ public class UsbACInputTerminal extends UsbACTerminal {
private byte mChannelNames; // 10:1 Unused (0x00)
private byte mTerminal; // 11:1 Unused (0x00)
- public UsbACInputTerminal(int length, byte type, byte subtype, byte subclass) {
+ public Usb10ACInputTerminal(int length, byte type, byte subtype, byte subclass) {
super(length, type, subtype, subclass);
}
@@ -55,10 +57,22 @@ public class UsbACInputTerminal extends UsbACTerminal {
super.parseRawDescriptors(stream);
mNrChannels = stream.getByte();
- mChannelConfig = stream.unpackUsbWord();
+ mChannelConfig = stream.unpackUsbShort();
mChannelNames = stream.getByte();
mTerminal = stream.getByte();
return mLength;
}
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.openList();
+ canvas.writeListItem("Associated Terminal: "
+ + ReportCanvas.getHexString(getAssocTerminal()));
+ canvas.writeListItem("" + getNrChannels() + " Chans. Config: "
+ + ReportCanvas.getHexString(getChannelConfig()));
+ canvas.closeList();
+ }
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb10ACMixerUnit.java b/services/usb/java/com/android/server/usb/descriptors/Usb10ACMixerUnit.java
new file mode 100644
index 000000000000..d3486643ede2
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb10ACMixerUnit.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors;
+
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
+/**
+ * @hide
+ * An audio class-specific Mixer Interface.
+ * see audio10.pdf section 4.3.2.3
+ */
+public final class Usb10ACMixerUnit extends UsbACMixerUnit {
+ private static final String TAG = "Usb10ACMixerUnit";
+
+ private int mChannelConfig; // Spatial location of output channels
+ private byte mChanNameID; // First channel name string descriptor ID
+ private byte[] mControls; // bitmasks of which controls are present for each channel
+ private byte mNameID; // string descriptor ID of mixer name
+
+ public Usb10ACMixerUnit(int length, byte type, byte subtype, byte subClass) {
+ super(length, type, subtype, subClass);
+ }
+
+ public int getChannelConfig() {
+ return mChannelConfig;
+ }
+
+ public byte getChanNameID() {
+ return mChanNameID;
+ }
+
+ public byte[] getControls() {
+ return mControls;
+ }
+
+ public byte getNameID() {
+ return mNameID;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ super.parseRawDescriptors(stream);
+
+ mChannelConfig = stream.unpackUsbShort();
+ mChanNameID = stream.getByte();
+
+ int controlArraySize = calcControlArraySize(mNumInputs, mNumOutputs);
+ mControls = new byte[controlArraySize];
+ for (int index = 0; index < controlArraySize; index++) {
+ mControls[index] = stream.getByte();
+ }
+
+ mNameID = stream.getByte();
+
+ return mLength;
+ }
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.writeParagraph("Mixer Unit", false);
+ canvas.openList();
+
+ canvas.writeListItem("Unit ID: " + ReportCanvas.getHexString(getUnitID()));
+ byte numInputs = getNumInputs();
+ byte[] inputIDs = getInputIDs();
+ canvas.openListItem();
+ canvas.write("Num Inputs: " + numInputs + " [");
+ for (int input = 0; input < numInputs; input++) {
+ canvas.write("" + ReportCanvas.getHexString(inputIDs[input]));
+ if (input < numInputs - 1) {
+ canvas.write(" ");
+ }
+ }
+ canvas.write("]");
+ canvas.closeListItem();
+
+ canvas.writeListItem("Num Outputs: " + getNumOutputs());
+ canvas.writeListItem("Channel Config: " + ReportCanvas.getHexString(getChannelConfig()));
+
+ byte[] controls = getControls();
+ canvas.openListItem();
+ canvas.write("Controls: " + controls.length + " [");
+ for (int ctrl = 0; ctrl < controls.length; ctrl++) {
+ canvas.write("" + controls[ctrl]);
+ if (ctrl < controls.length - 1) {
+ canvas.write(" ");
+ }
+ }
+ canvas.write("]");
+ canvas.closeListItem();
+ canvas.closeList();
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACOutputTerminal.java b/services/usb/java/com/android/server/usb/descriptors/Usb10ACOutputTerminal.java
index f957e3dbe217..9f2f09ec146c 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACOutputTerminal.java
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb10ACOutputTerminal.java
@@ -15,18 +15,20 @@
*/
package com.android.server.usb.descriptors;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
/**
* @hide
* An audio class-specific Output Terminal Interface.
* see audio10.pdf section 4.3.2.2
*/
-public class UsbACOutputTerminal extends UsbACTerminal {
- private static final String TAG = "ACOutputTerminal";
+public final class Usb10ACOutputTerminal extends UsbACTerminal {
+ private static final String TAG = "Usb10ACOutputTerminal";
private byte mSourceID; // 7:1 From Input Terminal. (0x01)
private byte mTerminal; // 8:1 Unused.
- public UsbACOutputTerminal(int length, byte type, byte subtype, byte subClass) {
+ public Usb10ACOutputTerminal(int length, byte type, byte subtype, byte subClass) {
super(length, type, subtype, subClass);
}
@@ -46,4 +48,13 @@ public class UsbACOutputTerminal extends UsbACTerminal {
mTerminal = stream.getByte();
return mLength;
}
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.openList();
+ canvas.writeListItem("Source ID: " + ReportCanvas.getHexString(getSourceID()));
+ canvas.closeList();
+ }
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbASFormatI.java b/services/usb/java/com/android/server/usb/descriptors/Usb10ASFormatI.java
index 347a6cffb525..1523bb528a03 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbASFormatI.java
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb10ASFormatI.java
@@ -15,13 +15,15 @@
*/
package com.android.server.usb.descriptors;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
/**
* @hide
* An audio class-specific Format I interface.
* see Frmts10.pdf section 2.2
*/
-public class UsbASFormatI extends UsbASFormat {
- private static final String TAG = "ASFormatI";
+public final class Usb10ASFormatI extends UsbASFormat {
+ private static final String TAG = "Usb10ASFormatI";
private byte mNumChannels; // 4:1
private byte mSubframeSize; // 5:1 frame size in bytes
@@ -31,7 +33,7 @@ public class UsbASFormatI extends UsbASFormat {
// min & max rates otherwise mSamFreqType rates.
// All 3-byte values. All rates in Hz
- public UsbASFormatI(int length, byte type, byte subtype, byte formatType, byte subclass) {
+ public Usb10ASFormatI(int length, byte type, byte subtype, byte formatType, byte subclass) {
super(length, type, subtype, formatType, subclass);
}
@@ -51,11 +53,24 @@ public class UsbASFormatI extends UsbASFormat {
return mSampleFreqType;
}
+ @Override
public int[] getSampleRates() {
return mSampleRates;
}
@Override
+ public int[] getBitDepths() {
+ int[] depths = {mBitResolution};
+ return depths;
+ }
+
+ @Override
+ public int[] getChannelCounts() {
+ int[] counts = {mNumChannels};
+ return counts;
+ }
+
+ @Override
public int parseRawDescriptors(ByteStream stream) {
mNumChannels = stream.getByte();
mSubframeSize = stream.getByte();
@@ -74,4 +89,28 @@ public class UsbASFormatI extends UsbASFormat {
return mLength;
}
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.openList();
+ canvas.writeListItem("" + getNumChannels() + " Channels.");
+ canvas.writeListItem("Subframe Size: " + getSubframeSize());
+ canvas.writeListItem("Bit Resolution: " + getBitResolution());
+ byte sampleFreqType = getSampleFreqType();
+ int[] sampleRates = getSampleRates();
+ canvas.writeListItem("Sample Freq Type: " + sampleFreqType);
+ canvas.openList();
+ if (sampleFreqType == 0) {
+ canvas.writeListItem("min: " + sampleRates[0]);
+ canvas.writeListItem("max: " + sampleRates[1]);
+ } else {
+ for (int index = 0; index < sampleFreqType; index++) {
+ canvas.writeListItem("" + sampleRates[index]);
+ }
+ }
+ canvas.closeList();
+ canvas.closeList();
+ }
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbASFormatII.java b/services/usb/java/com/android/server/usb/descriptors/Usb10ASFormatII.java
index abdc62145aa2..b1e7680ee1b9 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbASFormatII.java
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb10ASFormatII.java
@@ -15,13 +15,15 @@
*/
package com.android.server.usb.descriptors;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
/**
* @hide
* An audio class-specific Format II interface.
* see Frmts10.pdf section 2.3
*/
-public class UsbASFormatII extends UsbASFormat {
- private static final String TAG = "ASFormatII";
+public final class Usb10ASFormatII extends UsbASFormat {
+ private static final String TAG = "Usb10ASFormatII";
private int mMaxBitRate; // 4:2 Indicates the maximum number of bits per second this
// interface can handle. Expressed in kbits/s.
@@ -36,7 +38,7 @@ public class UsbASFormatII extends UsbASFormat {
// the min & max rates. otherwise mSamFreqType rates.
// All 3-byte values. All rates in Hz
- public UsbASFormatII(int length, byte type, byte subtype, byte formatType, byte subclass) {
+ public Usb10ASFormatII(int length, byte type, byte subtype, byte formatType, byte subclass) {
super(length, type, subtype, formatType, subclass);
}
@@ -58,8 +60,8 @@ public class UsbASFormatII extends UsbASFormat {
@Override
public int parseRawDescriptors(ByteStream stream) {
- mMaxBitRate = stream.unpackUsbWord();
- mSamplesPerFrame = stream.unpackUsbWord();
+ mMaxBitRate = stream.unpackUsbShort();
+ mSamplesPerFrame = stream.unpackUsbShort();
mSamFreqType = stream.getByte();
int numFreqs = mSamFreqType == 0 ? 2 : mSamFreqType;
mSampleRates = new int[numFreqs];
@@ -69,4 +71,29 @@ public class UsbASFormatII extends UsbASFormat {
return mLength;
}
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.openList();
+ canvas.writeListItem("Max Bit Rate: " + getMaxBitRate());
+ canvas.writeListItem("Samples Per Frame: " + getMaxBitRate());
+ byte sampleFreqType = getSamFreqType();
+ int[] sampleRates = getSampleRates();
+ canvas.writeListItem("Sample Freq Type: " + sampleFreqType);
+ canvas.openList();
+ if (sampleFreqType == 0) {
+ canvas.writeListItem("min: " + sampleRates[0]);
+ canvas.writeListItem("max: " + sampleRates[1]);
+ } else {
+ for (int index = 0; index < sampleFreqType; index++) {
+ canvas.writeListItem("" + sampleRates[index]);
+ }
+ }
+ canvas.closeList();
+
+ canvas.closeList();
+ }
+
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbASGeneral.java b/services/usb/java/com/android/server/usb/descriptors/Usb10ASGeneral.java
index c4f42d318213..2d4f604ed1a1 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbASGeneral.java
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb10ASGeneral.java
@@ -15,13 +15,16 @@
*/
package com.android.server.usb.descriptors;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+import com.android.server.usb.descriptors.report.UsbStrings;
+
/**
* @hide
* An audio class-specific General interface.
* see audio10.pdf section 4.5.2
*/
-public class UsbASGeneral extends UsbACInterface {
- private static final String TAG = "ACGeneral";
+public final class Usb10ASGeneral extends UsbACInterface {
+ private static final String TAG = "Usb10ASGeneral";
// audio10.pdf - section 4.5.2
private byte mTerminalLink; // 3:1 The Terminal ID of the Terminal to which the endpoint
@@ -31,7 +34,7 @@ public class UsbASGeneral extends UsbACInterface {
private int mFormatTag; // 5:2 The Audio Data Format that has to be used to communicate
// with this interface.
- public UsbASGeneral(int length, byte type, byte subtype, byte subclass) {
+ public Usb10ASGeneral(int length, byte type, byte subtype, byte subclass) {
super(length, type, subtype, subclass);
}
@@ -51,8 +54,20 @@ public class UsbASGeneral extends UsbACInterface {
public int parseRawDescriptors(ByteStream stream) {
mTerminalLink = stream.getByte();
mDelay = stream.getByte();
- mFormatTag = stream.unpackUsbWord();
+ mFormatTag = stream.unpackUsbShort();
return mLength;
}
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.openList();
+ canvas.writeListItem("Delay: " + mDelay);
+ canvas.writeListItem("Terminal Link: " + mTerminalLink);
+ canvas.writeListItem("Format: " + UsbStrings.getAudioFormatName(mFormatTag) + " - "
+ + ReportCanvas.getHexString(mFormatTag));
+ canvas.closeList();
+ }
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ACHeader.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ACHeader.java
new file mode 100644
index 000000000000..eefae3d51b3f
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ACHeader.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors;
+
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
+/**
+ * @hide
+ * An audio class-specific Header descriptor.
+ * see Audio20.pdf section 4.7.2 Class-Specific AC Interface Descriptor
+ */
+public final class Usb20ACHeader extends UsbACHeaderInterface {
+ private static final String TAG = "Usb20ACHeader";
+
+ private byte mCategory; // 5:1 Constant, indicating the primary use of this audio function.
+ // See audio20.pdf Appendix A.7, “Audio Function Category Codes.”
+ private byte mControls; // 8:1 See audio20.pdf Table 4-5.
+
+ public Usb20ACHeader(int length, byte type, byte subtype, byte subclass, int spec) {
+ super(length, type, subtype, subclass, spec);
+ }
+
+ public byte getCategory() {
+ return mCategory;
+ }
+
+ public byte getControls() {
+ return mControls;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ mCategory = stream.getByte();
+ mTotalLength = stream.unpackUsbShort();
+ mControls = stream.getByte();
+
+ return mLength;
+ }
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.openList();
+ canvas.writeListItem("Category: " + ReportCanvas.getHexString(getCategory()));
+ canvas.writeListItem("Controls: " + ReportCanvas.getHexString(getControls()));
+ canvas.closeList();
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ACInputTerminal.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ACInputTerminal.java
new file mode 100644
index 000000000000..3e2ac39c0aca
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ACInputTerminal.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors;
+
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
+/**
+ * @hide
+ * An audio class-specific Input Terminal interface.
+ * see Audio20.pdf section 3.13.2 Input Terminal
+ */
+public final class Usb20ACInputTerminal extends UsbACTerminal {
+ private static final String TAG = "Usb20ACInputTerminal";
+
+ // See Audio20.pdf - Table 4-9
+ // Always 17 bytes
+ private byte mClkSourceID; // 7:1 - ID of the Clock Entity to which this Input
+ // Terminal is connected.
+ private byte mNumChannels; // 8:1 - Number of logical output channels in the
+ // Terminal’s output audio channel cluster.
+ private int mChanConfig; // 9:4 - Describes the spatial location of the
+ // logical channels.
+ private byte mChanNames; // 13:1 - Index of a string descriptor, describing the
+ // name of the first logical channel.
+ private int mControls; // 14:2 - Bitmask (see Audio20.pdf Table 4-9)
+ private byte mTerminalName; // 16:1 - Index of a string descriptor, describing the
+ // Input Terminal.
+
+ public Usb20ACInputTerminal(int length, byte type, byte subtype, byte subclass) {
+ super(length, type, subtype, subclass);
+ }
+
+ public byte getClkSourceID() {
+ return mClkSourceID;
+ }
+
+ public byte getNumChannels() {
+ return mNumChannels;
+ }
+
+ public int getChanConfig() {
+ return mChanConfig;
+ }
+
+ public int getControls() {
+ return mControls;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ super.parseRawDescriptors(stream);
+
+ mClkSourceID = stream.getByte();
+ mNumChannels = stream.getByte();
+ mChanConfig = stream.unpackUsbInt();
+ mChanNames = stream.getByte();
+ mControls = stream.unpackUsbShort();
+ mTerminalName = stream.getByte();
+
+ return mLength;
+ }
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.openList();
+ canvas.writeListItem("Clock Source: " + getClkSourceID());
+ canvas.writeListItem("" + getNumChannels() + " Channels. Config: "
+ + ReportCanvas.getHexString(getChanConfig()));
+ canvas.closeList();
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ACMixerUnit.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ACMixerUnit.java
new file mode 100644
index 000000000000..1b267a67752b
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ACMixerUnit.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors;
+
+/**
+ * @hide
+ * An audio class-specific Mixer Unit interface.
+ * see Audio20.pdf section 4.7.2.6 Mixer Unit Descriptor
+ */
+public final class Usb20ACMixerUnit extends UsbACMixerUnit {
+ private static final String TAG = "Usb20ACMixerUnit";
+
+ private int mChanConfig; // 6+p:4 Describes the spatial location of the
+ // logical channels.
+ private byte mChanNames; // 10+p:1 Index of a string descriptor, describing the
+ // name of the first logical channel.
+ private byte[] mControls; // 11+p:N bitmasks of which controls are present for each channel
+ // for N, see UsbACMixerUnit.calcControlArraySize()
+ private byte mControlsMask; // 11+p+N:1 bitmasks of which controls are present for each channel
+ private byte mNameID; // 12+p+N:1 Index of a string descriptor, describing the
+ // Mixer Unit.
+
+ public Usb20ACMixerUnit(int length, byte type, byte subtype, byte subClass) {
+ super(length, type, subtype, subClass);
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ super.parseRawDescriptors(stream);
+
+ mChanConfig = stream.unpackUsbInt();
+ mChanNames = stream.getByte();
+ int controlArraySize = calcControlArraySize(mNumInputs, mNumOutputs);
+ mControls = new byte[controlArraySize];
+ for (int index = 0; index < controlArraySize; index++) {
+ mControls[index] = stream.getByte();
+ }
+ mControlsMask = stream.getByte();
+ mNameID = stream.getByte();
+
+ return mLength;
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ACOutputTerminal.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ACOutputTerminal.java
new file mode 100644
index 000000000000..67478aad8a59
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ACOutputTerminal.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors;
+
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
+/**
+ * @hide
+ * An audio class-specific Output Terminal interface.
+ * see Audio20.pdf section 3.13.3 Output Terminal
+ */
+public final class Usb20ACOutputTerminal extends UsbACTerminal {
+ private static final String TAG = "Usb20ACOutputTerminal";
+
+ // Audio20.pdf - section 4.7.2.5, Table 4-10
+ // Always 12 bytes
+ private byte mSourceID; // 7:1 - ID of the Unit or Terminal to which this
+ // Terminal is connected.
+ private byte mClkSoureID; // 8:1 - ID of the Clock Entity to which this Output
+ // Terminal is connected.
+ private int mControls; // 9:2 - see Audio20.pdf Table 4-10
+ private byte mTerminalID; // 11:1 - Index of a string descriptor, describing the
+
+ public Usb20ACOutputTerminal(int length, byte type, byte subtype, byte subClass) {
+ super(length, type, subtype, subClass);
+ }
+
+ public byte getSourceID() {
+ return mSourceID;
+ }
+
+ public byte getClkSourceID() {
+ return mClkSoureID;
+ }
+
+ public int getControls() {
+ return mControls;
+ }
+
+ public byte getTerminalID() {
+ return mTerminalID;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ super.parseRawDescriptors(stream);
+
+ mSourceID = stream.getByte();
+ mClkSoureID = stream.getByte();
+ mControls = stream.unpackUsbShort();
+ mTerminalID = stream.getByte();
+
+ return mLength;
+ }
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.openList();
+ canvas.writeListItem("Clock Source ID: " + getClkSourceID());
+ canvas.writeListItem("Controls: " + ReportCanvas.getHexString(getControls()));
+ canvas.writeListItem("Terminal Name ID: " + getTerminalID());
+ canvas.closeList();
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatI.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatI.java
new file mode 100644
index 000000000000..c03199619e74
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatI.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors;
+
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
+/**
+ * @hide
+ * An audio class-specific Format I interface.
+ * see Frmts20.pdf section 2.3.1.6 Type I Format Type Descriptor
+ */
+public final class Usb20ASFormatI extends UsbASFormat {
+ private static final String TAG = "Usb20ASFormatI";
+
+ // Frmts20.pdf Table 2-2: Type I Format Type Descriptor
+ private byte mSubSlotSize; // 4:1 The number of bytes occupied by one
+ // audio subslot. Can be 1, 2, 3 or 4.
+ private byte mBitResolution; // 5:1 The number of effectively used bits from
+ // the available bits in an audio subslot.
+
+ public Usb20ASFormatI(int length, byte type, byte subtype, byte formatType, byte subclass) {
+ super(length, type, subtype, formatType, subclass);
+ }
+
+ /**
+ * TBD
+ */
+ public byte getSubSlotSize() {
+ return mSubSlotSize;
+ }
+
+ /**
+ * TBD
+ */
+ public byte getBitResolution() {
+ return mBitResolution;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ mSubSlotSize = stream.getByte();
+ mBitResolution = stream.getByte();
+
+ return mLength;
+ }
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.openList();
+ canvas.writeListItem("Subslot Size: " + getSubSlotSize());
+ canvas.writeListItem("Bit Resolution: " + getBitResolution());
+ canvas.closeList();
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatII.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatII.java
new file mode 100644
index 000000000000..dc44ff063964
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatII.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors;
+
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
+/**
+ * @hide
+ * An audio class-specific Format II interface.
+ * see Frmts20.pdf section 2.3.2.6 Type II Format Type Descriptor
+ */
+public final class Usb20ASFormatII extends UsbASFormat {
+ private static final String TAG = "Usb20ASFormatII";
+
+ // Frmts20.pdf Table 2-3: Type II Format Type Descriptor
+ private int mMaxBitRate; // 4:2 Indicates the maximum number of bits per
+ // second this interface can handle in kbits/s.
+ private int mSlotsPerFrame; // 6:2 Indicates the number of PCM audio slots
+ // contained in one encoded audio frame.
+
+ /**
+ * TBD
+ */
+ public Usb20ASFormatII(int length, byte type, byte subtype, byte formatType, byte subclass) {
+ super(length, type, subtype, formatType, subclass);
+ }
+
+ /**
+ * TBD
+ */
+ public int getmaxBitRate() {
+ return mMaxBitRate;
+ }
+
+ /**
+ * TBD
+ */
+ public int getSlotsPerFrame() {
+ return mSlotsPerFrame;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ mMaxBitRate = stream.unpackUsbShort();
+ mSlotsPerFrame = stream.unpackUsbShort();
+
+ return mLength;
+ }
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.openList();
+ canvas.writeListItem("Max Bit Rate: " + getmaxBitRate());
+ canvas.writeListItem("slots Per Frame: " + getSlotsPerFrame());
+ canvas.closeList();
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatIIEx.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatIIEx.java
new file mode 100644
index 000000000000..d7dfba396984
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatIIEx.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors;
+
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
+/**
+ * @hide
+ * An audio class-specific Format II interface.
+ * see Frmts20.pdf section 2.4.2.1 Extended Type II Format Type Descriptor
+ */
+public final class Usb20ASFormatIIEx extends UsbASFormat {
+ private static final String TAG = "Usb20ASFormatIIEx";
+
+ // Frmts20.pdf Table 2-7: Extended Type II Format Type Descriptor
+ private int mMaxBitRate; // 4:2 Indicates the maximum number of bits per
+ // second this interface can handle in kbits/s
+ private int mSamplesPerFrame; // 6:2 Indicates the number of PCM audio
+ // samples contained in one encoded audio frame.
+ private byte mHeaderLength; // 8:1 Size of the Packet Header, in bytes.
+ private byte mSidebandProtocol; // 9:1 Constant, identifying the Side Band
+ // Protocol used for the Packet Header content.
+
+ public Usb20ASFormatIIEx(int length, byte type, byte subtype, byte formatType, byte subclass) {
+ super(length, type, subtype, formatType, subclass);
+ }
+
+ public int getMaxBitRate() {
+ return mMaxBitRate;
+ }
+
+ public int getSamplesPerFrame() {
+ return mSamplesPerFrame;
+ }
+
+ public byte getHeaderLength() {
+ return mHeaderLength;
+ }
+
+ public byte getSidebandProtocol() {
+ return mSidebandProtocol;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ mMaxBitRate = stream.unpackUsbShort();
+ mSamplesPerFrame = stream.unpackUsbShort();
+ mHeaderLength = stream.getByte();
+ mSidebandProtocol = stream.getByte();
+
+ return mLength;
+ }
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.openList();
+ canvas.writeListItem("Max Bit Rate: " + getMaxBitRate());
+ canvas.writeListItem("Samples Per Frame: " + getSamplesPerFrame());
+ canvas.writeListItem("Header Length: " + getHeaderLength());
+ canvas.writeListItem("Sideband Protocol: " + getSidebandProtocol());
+ canvas.closeList();
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatIII.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatIII.java
new file mode 100644
index 000000000000..b44a216703f8
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ASFormatIII.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors;
+
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
+/**
+ * @hide
+ * An audio class-specific Format III interface.
+ * see Frmts20.pdf section 2.3.1.6 2.3.3.1 Type III Format Type Descriptor
+ */
+public final class Usb20ASFormatIII extends UsbASFormat {
+ private static final String TAG = "Usb20ASFormatIII";
+
+ // frmts20.pdf Table 2-4: Type III Format Type Descriptor
+ private byte mSubslotSize; // 4:1 The number of bytes occupied by one
+ // audio subslot. Must be set to two.
+ private byte mBitResolution; // 5:1 The number of effectively used bits from
+ // the available bits in an audio subframe.
+
+ public Usb20ASFormatIII(int length, byte type, byte subtype, byte formatType, byte subclass) {
+ super(length, type, subtype, formatType, subclass);
+ }
+
+ public byte getSubslotSize() {
+ return mSubslotSize;
+ }
+
+ public byte getBitResolution() {
+ return mBitResolution;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+ mSubslotSize = stream.getByte();
+ mBitResolution = stream.getByte();
+
+ return mLength;
+ }
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.openList();
+ canvas.writeListItem("Subslot Size: " + getSubslotSize());
+ canvas.writeListItem("Bit Resolution: " + getBitResolution());
+ canvas.closeList();
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/Usb20ASGeneral.java b/services/usb/java/com/android/server/usb/descriptors/Usb20ASGeneral.java
new file mode 100644
index 000000000000..18d48a009098
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/Usb20ASGeneral.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors;
+
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
+/**
+ * Audio20.pdf - 4.9.2 Class-Specific AS Interface Descriptor
+ * 16 bytes
+ */
+public final class Usb20ASGeneral extends UsbACInterface {
+ private static final String TAG = "Usb20ASGeneral";
+
+ // Audio20.pdf - Table 4-27
+ private byte mTerminalLink; // 3:1 The Terminal ID of the Terminal to which
+ // this interface is connected.
+ private byte mControls; // 4:1 see audio20.pdf Table 4-27
+ private byte mFormatType; // 5:1 Constant identifying the Format Type the
+ // AudioStreaming interface is using.
+ private int mFormats; // 6:4 The Audio Data Format(s) that can be
+ // used to communicate with this interface.
+ // See the USB Audio Data Formats
+ // document for further details.
+ private byte mNumChannels; // 10:1 Number of physical channels in the AS
+ // Interface audio channel cluster.
+ private int mChannelConfig; // 11:4 Describes the spatial location of the
+ // physical channels.
+ private byte mChannelNames; // 15:1 Index of a string descriptor, describing the
+ // name of the first physical channel.
+
+ public Usb20ASGeneral(int length, byte type, byte subtype, byte subclass) {
+ super(length, type, subtype, subclass);
+ }
+
+ public byte getTerminalLink() {
+ return mTerminalLink;
+ }
+
+ public byte getControls() {
+ return mControls;
+ }
+
+ public byte getFormatType() {
+ return mFormatType;
+ }
+
+ public int getFormats() {
+ return mFormats;
+ }
+
+ public byte getNumChannels() {
+ return mNumChannels;
+ }
+
+ public int getChannelConfig() {
+ return mChannelConfig;
+ }
+
+ public byte getChannelNames() {
+ return mChannelNames;
+ }
+
+ @Override
+ public int parseRawDescriptors(ByteStream stream) {
+
+ mTerminalLink = stream.getByte();
+ mControls = stream.getByte();
+ mFormatType = stream.getByte();
+ mFormats = stream.unpackUsbInt();
+ mNumChannels = stream.getByte();
+ mChannelConfig = stream.unpackUsbInt();
+ mChannelNames = stream.getByte();
+
+ return mLength;
+ }
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.openList();
+ canvas.writeListItem("Terminal Link: " + getTerminalLink());
+ canvas.writeListItem("Controls: " + ReportCanvas.getHexString(getControls()));
+ canvas.writeListItem("Format Type: " + ReportCanvas.getHexString(getFormatType()));
+ canvas.writeListItem("Formats: " + ReportCanvas.getHexString(getFormats()));
+ canvas.writeListItem("Num Channels: " + getNumChannels());
+ canvas.writeListItem("Channel Config: " + ReportCanvas.getHexString(getChannelConfig()));
+ canvas.writeListItem("Channel Names String ID: " + getChannelNames());
+ canvas.closeList();
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACAudioControlEndpoint.java b/services/usb/java/com/android/server/usb/descriptors/UsbACAudioControlEndpoint.java
index 96fcc6a0b8db..6e1ce07536c5 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACAudioControlEndpoint.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACAudioControlEndpoint.java
@@ -21,7 +21,7 @@ package com.android.server.usb.descriptors;
* audio10.pdf section 4.4.2.1
*/
public class UsbACAudioControlEndpoint extends UsbACEndpoint {
- private static final String TAG = "ACAudioControlEndpoint";
+ private static final String TAG = "UsbACAudioControlEndpoint";
private byte mAddress; // 2:1 The address of the endpoint on the USB device.
// D7: Direction. 1 = IN endpoint
@@ -64,7 +64,7 @@ public class UsbACAudioControlEndpoint extends UsbACEndpoint {
mAddress = stream.getByte();
mAttribs = stream.getByte();
- mMaxPacketSize = stream.unpackUsbWord();
+ mMaxPacketSize = stream.unpackUsbShort();
mInterval = stream.getByte();
return mLength;
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACAudioStreamEndpoint.java b/services/usb/java/com/android/server/usb/descriptors/UsbACAudioStreamEndpoint.java
index d387883d3049..d35190298df6 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACAudioStreamEndpoint.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACAudioStreamEndpoint.java
@@ -21,7 +21,7 @@ package com.android.server.usb.descriptors;
* see audio10.pdf section 3.7.2
*/
public class UsbACAudioStreamEndpoint extends UsbACEndpoint {
- private static final String TAG = "ACAudioStreamEndpoint";
+ private static final String TAG = "UsbACAudioStreamEndpoint";
//TODO data fields...
public UsbACAudioStreamEndpoint(int length, byte type, byte subclass) {
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACEndpoint.java b/services/usb/java/com/android/server/usb/descriptors/UsbACEndpoint.java
index 223496ab016e..4a6839d943ff 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACEndpoint.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACEndpoint.java
@@ -23,7 +23,7 @@ import android.util.Log;
* see audio10.pdf section 4.4.1.2
*/
abstract class UsbACEndpoint extends UsbDescriptor {
- private static final String TAG = "ACEndpoint";
+ private static final String TAG = "UsbACEndpoint";
protected final byte mSubclass; // from the mSubclass member of the "enclosing"
// Interface Descriptor, not the stream.
@@ -50,7 +50,7 @@ abstract class UsbACEndpoint extends UsbDescriptor {
}
public static UsbDescriptor allocDescriptor(UsbDescriptorParser parser,
- int length, byte type) {
+ int length, byte type) {
UsbInterfaceDescriptor interfaceDesc = parser.getCurInterface();
byte subClass = interfaceDesc.getUsbSubclass();
switch (subClass) {
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACFeatureUnit.java b/services/usb/java/com/android/server/usb/descriptors/UsbACFeatureUnit.java
index 739fe5503a1d..ab3903b402d9 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACFeatureUnit.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACFeatureUnit.java
@@ -20,8 +20,8 @@ package com.android.server.usb.descriptors;
* An audio class-specific Feature Unit Interface
* see audio10.pdf section 3.5.5
*/
-public class UsbACFeatureUnit extends UsbACInterface {
- private static final String TAG = "ACFeatureUnit";
+public final class UsbACFeatureUnit extends UsbACInterface {
+ private static final String TAG = "UsbACFeatureUnit";
// audio10.pdf section 4.3.2.5
public static final int CONTROL_MASK_MUTE = 0x0001;
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACHeaderInterface.java b/services/usb/java/com/android/server/usb/descriptors/UsbACHeaderInterface.java
new file mode 100644
index 000000000000..01a355e2c6e4
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACHeaderInterface.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors;
+
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
+/**
+ * @hide
+ * An audio class-specific Interface Header super class.
+ * see audio10.pdf section 4.3.2 & Audio20.pdf section 4.7.2
+ */
+public abstract class UsbACHeaderInterface extends UsbACInterface {
+ private static final String TAG = "UsbACHeaderInterface";
+
+ protected int mADCRelease; // Audio Device Class Specification Release (BCD).
+ protected int mTotalLength; // Total number of bytes returned for the class-specific
+ // AudioControl interface descriptor. Includes the combined length
+ // of this descriptor header and all Unit and Terminal descriptors.
+
+ public UsbACHeaderInterface(
+ int length, byte type, byte subtype, byte subclass, int adcRelease) {
+ super(length, type, subtype, subclass);
+ mADCRelease = adcRelease;
+ }
+
+ public int getADCRelease() {
+ return mADCRelease;
+ }
+
+ public int getTotalLength() {
+ return mTotalLength;
+ }
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.openList();
+ canvas.writeListItem("Release: " + ReportCanvas.getBCDString(getADCRelease()));
+ canvas.writeListItem("Total Length: " + getTotalLength());
+ canvas.closeList();
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACInterface.java b/services/usb/java/com/android/server/usb/descriptors/UsbACInterface.java
index 0ab7fccd2c3b..df6c53fa9f52 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACInterface.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACInterface.java
@@ -17,13 +17,16 @@ package com.android.server.usb.descriptors;
import android.util.Log;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+import com.android.server.usb.descriptors.report.UsbStrings;
+
/**
* @hide
* An audio class-specific Interface.
* see audio10.pdf section 4.3.2
*/
public abstract class UsbACInterface extends UsbDescriptor {
- private static final String TAG = "ACInterface";
+ private static final String TAG = "UsbACInterface";
// Audio Control Subtypes
public static final byte ACI_UNDEFINED = 0;
@@ -35,6 +38,11 @@ public abstract class UsbACInterface extends UsbDescriptor {
public static final byte ACI_FEATURE_UNIT = 6;
public static final byte ACI_PROCESSING_UNIT = 7;
public static final byte ACI_EXTENSION_UNIT = 8;
+ // Not handled yet
+ public static final byte ACI_CLOCK_SOURCE = 0x0A;
+ public static final byte ACI_CLOCK_SELECTOR = 0x0B;
+ public static final byte ACI_CLOCK_MULTIPLIER = 0x0C;
+ public static final byte ACI_SAMPLE_RATE_CONVERTER = 0x0D;
// Audio Streaming Subtypes
public static final byte ASI_UNDEFINED = 0;
@@ -87,17 +95,39 @@ public abstract class UsbACInterface extends UsbDescriptor {
return mSubclass;
}
- private static UsbDescriptor allocAudioControlDescriptor(ByteStream stream,
- int length, byte type, byte subtype, byte subClass) {
+ private static UsbDescriptor allocAudioControlDescriptor(UsbDescriptorParser parser,
+ ByteStream stream, int length, byte type, byte subtype, byte subClass) {
switch (subtype) {
case ACI_HEADER:
- return new UsbACHeader(length, type, subtype, subClass);
+ {
+ int acInterfaceSpec = stream.unpackUsbShort();
+ parser.setACInterfaceSpec(acInterfaceSpec);
+ if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) {
+ return new Usb20ACHeader(length, type, subtype, subClass, acInterfaceSpec);
+ } else {
+ return new Usb10ACHeader(length, type, subtype, subClass, acInterfaceSpec);
+ }
+ }
case ACI_INPUT_TERMINAL:
- return new UsbACInputTerminal(length, type, subtype, subClass);
+ {
+ int acInterfaceSpec = parser.getACInterfaceSpec();
+ if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) {
+ return new Usb20ACInputTerminal(length, type, subtype, subClass);
+ } else {
+ return new Usb10ACInputTerminal(length, type, subtype, subClass);
+ }
+ }
case ACI_OUTPUT_TERMINAL:
- return new UsbACOutputTerminal(length, type, subtype, subClass);
+ {
+ int acInterfaceSpec = parser.getACInterfaceSpec();
+ if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) {
+ return new Usb20ACOutputTerminal(length, type, subtype, subClass);
+ } else {
+ return new Usb10ACOutputTerminal(length, type, subtype, subClass);
+ }
+ }
case ACI_SELECTOR_UNIT:
return new UsbACSelectorUnit(length, type, subtype, subClass);
@@ -106,7 +136,14 @@ public abstract class UsbACInterface extends UsbDescriptor {
return new UsbACFeatureUnit(length, type, subtype, subClass);
case ACI_MIXER_UNIT:
- return new UsbACMixerUnit(length, type, subtype, subClass);
+ {
+ int acInterfaceSpec = parser.getACInterfaceSpec();
+ if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) {
+ return new Usb20ACMixerUnit(length, type, subtype, subClass);
+ } else {
+ return new Usb10ACMixerUnit(length, type, subtype, subClass);
+ }
+ }
case ACI_PROCESSING_UNIT:
case ACI_EXTENSION_UNIT:
@@ -115,18 +152,24 @@ public abstract class UsbACInterface extends UsbDescriptor {
default:
Log.w(TAG, "Unknown Audio Class Interface subtype:0x"
+ Integer.toHexString(subtype));
- return null;
+ return new UsbACInterfaceUnparsed(length, type, subtype, subClass);
}
}
- private static UsbDescriptor allocAudioStreamingDescriptor(ByteStream stream,
- int length, byte type, byte subtype, byte subClass) {
+ private static UsbDescriptor allocAudioStreamingDescriptor(UsbDescriptorParser parser,
+ ByteStream stream, int length, byte type, byte subtype, byte subClass) {
+ //int spec = parser.getUsbSpec();
+ int acInterfaceSpec = parser.getACInterfaceSpec();
switch (subtype) {
case ASI_GENERAL:
- return new UsbASGeneral(length, type, subtype, subClass);
+ if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) {
+ return new Usb20ASGeneral(length, type, subtype, subClass);
+ } else {
+ return new Usb10ASGeneral(length, type, subtype, subClass);
+ }
case ASI_FORMAT_TYPE:
- return UsbASFormat.allocDescriptor(stream, length, type, subtype, subClass);
+ return UsbASFormat.allocDescriptor(parser, stream, length, type, subtype, subClass);
case ASI_FORMAT_SPECIFIC:
case ASI_UNDEFINED:
@@ -155,7 +198,6 @@ public abstract class UsbACInterface extends UsbDescriptor {
// Fall through until we implement that descriptor
case MSI_UNDEFINED:
- // break; Fall through until we implement this descriptor
default:
Log.w(TAG, "Unknown MIDI Streaming Interface subtype:0x"
+ Integer.toHexString(subtype));
@@ -173,10 +215,12 @@ public abstract class UsbACInterface extends UsbDescriptor {
byte subClass = interfaceDesc.getUsbSubclass();
switch (subClass) {
case AUDIO_AUDIOCONTROL:
- return allocAudioControlDescriptor(stream, length, type, subtype, subClass);
+ return allocAudioControlDescriptor(
+ parser, stream, length, type, subtype, subClass);
case AUDIO_AUDIOSTREAMING:
- return allocAudioStreamingDescriptor(stream, length, type, subtype, subClass);
+ return allocAudioStreamingDescriptor(
+ parser, stream, length, type, subtype, subClass);
case AUDIO_MIDISTREAMING:
return allocMidiStreamingDescriptor(length, type, subtype, subClass);
@@ -187,4 +231,21 @@ public abstract class UsbACInterface extends UsbDescriptor {
return null;
}
}
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ byte subClass = getSubclass();
+ String subClassName = UsbStrings.getACInterfaceSubclassName(subClass);
+
+ byte subtype = getSubtype();
+ String subTypeName = UsbStrings.getACControlInterfaceName(subtype);
+
+ canvas.openList();
+ canvas.writeListItem("Subclass: " + ReportCanvas.getHexString(subClass)
+ + " " + subClassName);
+ canvas.writeListItem("Subtype: " + ReportCanvas.getHexString(subtype) + " " + subTypeName);
+ canvas.closeList();
+ }
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACInterfaceUnparsed.java b/services/usb/java/com/android/server/usb/descriptors/UsbACInterfaceUnparsed.java
new file mode 100644
index 000000000000..9e00a7976dfd
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACInterfaceUnparsed.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors;
+
+/**
+ * @hide
+ * A holder class for as yet unparsed audio-class interfaces.
+ */
+public final class UsbACInterfaceUnparsed extends UsbACInterface {
+ private static final String TAG = "UsbACInterfaceUnparsed";
+
+ public UsbACInterfaceUnparsed(int length, byte type, byte subtype, byte subClass) {
+ super(length, type, subtype, subClass);
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACMidiEndpoint.java b/services/usb/java/com/android/server/usb/descriptors/UsbACMidiEndpoint.java
index 9c072426cc49..9c314575ccc4 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACMidiEndpoint.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACMidiEndpoint.java
@@ -15,13 +15,15 @@
*/
package com.android.server.usb.descriptors;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
/**
* @hide
* An audio class-specific Midi Endpoint.
* see midi10.pdf section 6.2.2
*/
-public class UsbACMidiEndpoint extends UsbACEndpoint {
- private static final String TAG = "ACMidiEndpoint";
+public final class UsbACMidiEndpoint extends UsbACEndpoint {
+ private static final String TAG = "UsbACMidiEndpoint";
private byte mNumJacks;
private byte[] mJackIds;
@@ -49,4 +51,15 @@ public class UsbACMidiEndpoint extends UsbACEndpoint {
}
return mLength;
}
-}
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.writeHeader(3, "AC Midi Endpoint: " + ReportCanvas.getHexString(getType())
+ + " Length: " + getLength());
+ canvas.openList();
+ canvas.writeListItem("" + getNumJacks() + " Jacks.");
+ canvas.closeList();
+ }
+} \ No newline at end of file
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACMixerUnit.java b/services/usb/java/com/android/server/usb/descriptors/UsbACMixerUnit.java
index 552b5ae308d6..88faed962a54 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACMixerUnit.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACMixerUnit.java
@@ -15,23 +15,14 @@
*/
package com.android.server.usb.descriptors;
-/**
- * @hide
- * An audio class-specific Mixer Interface.
- * see audio10.pdf section 4.3.2.3
- */
public class UsbACMixerUnit extends UsbACInterface {
- private static final String TAG = "ACMixerUnit";
+ private static final String TAG = "UsbACMixerUnit";
- private byte mUnitID; // 3:1
- private byte mNumInputs; // 4:1 Number of Input Pins of this Unit.
- private byte[] mInputIDs; // 5...:1 ID of the Unit or Terminal to which the Input Pins
- // are connected.
- private byte mNumOutputs; // The number of output channels
- private int mChannelConfig; // Spacial location of output channels
- private byte mChanNameID; // First channel name string descriptor ID
- private byte[] mControls; // bitmasks of which controls are present for each channel
- private byte mNameID; // string descriptor ID of mixer name
+ protected byte mUnitID; // 3:1
+ protected byte mNumInputs; // 4:1 Number of Input Pins of this Unit.
+ protected byte[] mInputIDs; // 5...:1 ID of the Unit or Terminal to which the Input Pins
+ // are connected.
+ protected byte mNumOutputs; // The number of output channels
public UsbACMixerUnit(int length, byte type, byte subtype, byte subClass) {
super(length, type, subtype, subClass);
@@ -53,20 +44,9 @@ public class UsbACMixerUnit extends UsbACInterface {
return mNumOutputs;
}
- public int getChannelConfig() {
- return mChannelConfig;
- }
-
- public byte getChanNameID() {
- return mChanNameID;
- }
-
- public byte[] getControls() {
- return mControls;
- }
-
- public byte getNameID() {
- return mNameID;
+ protected static int calcControlArraySize(int numInputs, int numOutputs) {
+ int totalChannels = numInputs * numOutputs;
+ return (totalChannels + 7) / 8;
}
@Override
@@ -78,22 +58,6 @@ public class UsbACMixerUnit extends UsbACInterface {
mInputIDs[input] = stream.getByte();
}
mNumOutputs = stream.getByte();
- mChannelConfig = stream.unpackUsbWord();
- mChanNameID = stream.getByte();
-
- int controlArraySize;
- int totalChannels = mNumInputs * mNumOutputs;
- if (totalChannels % 8 == 0) {
- controlArraySize = totalChannels / 8;
- } else {
- controlArraySize = totalChannels / 8 + 1;
- }
- mControls = new byte[controlArraySize];
- for (int index = 0; index < controlArraySize; index++) {
- mControls[index] = stream.getByte();
- }
-
- mNameID = stream.getByte();
return mLength;
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACSelectorUnit.java b/services/usb/java/com/android/server/usb/descriptors/UsbACSelectorUnit.java
index b1f60bdcf6ed..b16bc575e806 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACSelectorUnit.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACSelectorUnit.java
@@ -15,13 +15,15 @@
*/
package com.android.server.usb.descriptors;
+// import com.android.server.usb.descriptors.report.ReportCanvas;
+
/**
* @hide
* An audio class-specific Selector Unit Interface.
* see audio10.pdf section 4.3.2.4
*/
-public class UsbACSelectorUnit extends UsbACInterface {
- private static final String TAG = "ACSelectorUnit";
+public final class UsbACSelectorUnit extends UsbACInterface {
+ private static final String TAG = "UsbACSelectorUnit";
private byte mUnitID; // 3:1 Constant uniquely identifying the Unit within the audio function.
// This value is used in all requests to address this Unit.
@@ -62,4 +64,11 @@ public class UsbACSelectorUnit extends UsbACInterface {
return mLength;
}
+
+// @Override
+// public void report(ReportCanvas canvas) {
+// super.report(canvas);
+//
+// //TODO
+// }
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbACTerminal.java b/services/usb/java/com/android/server/usb/descriptors/UsbACTerminal.java
index ea80208ee3f3..2836508581d8 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbACTerminal.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbACTerminal.java
@@ -15,10 +15,15 @@
*/
package com.android.server.usb.descriptors;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+import com.android.server.usb.descriptors.report.UsbStrings;
+
/**
* @hide
*/
public abstract class UsbACTerminal extends UsbACInterface {
+ private static final String TAG = "UsbACTerminal";
+
// Note that these fields are the same for both the
// audio class-specific Output Terminal Interface.(audio10.pdf section 4.3.2.2)
// and audio class-specific Input Terminal interface.(audio10.pdf section 4.3.2.1)
@@ -46,9 +51,21 @@ public abstract class UsbACTerminal extends UsbACInterface {
@Override
public int parseRawDescriptors(ByteStream stream) {
mTerminalID = stream.getByte();
- mTerminalType = stream.unpackUsbWord();
+ mTerminalType = stream.unpackUsbShort();
mAssocTerminal = stream.getByte();
return mLength;
}
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.openList();
+ int terminalType = getTerminalType();
+ canvas.writeListItem("Type: " + ReportCanvas.getHexString(terminalType) + ": "
+ + UsbStrings.getTerminalName(terminalType));
+ canvas.writeListItem("ID: " + ReportCanvas.getHexString(getTerminalID()));
+ canvas.closeList();
+ }
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbASFormat.java b/services/usb/java/com/android/server/usb/descriptors/UsbASFormat.java
index d7c84c6a0965..305ae2f27372 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbASFormat.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbASFormat.java
@@ -15,19 +15,30 @@
*/
package com.android.server.usb.descriptors;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+import com.android.server.usb.descriptors.report.UsbStrings;
+
/**
* @hide
* An audio class-specific Format Interface.
* Subclasses: UsbACFormatI and UsbACFormatII.
* see audio10.pdf section 4.5.3 & & Frmts10.pdf
*/
-public abstract class UsbASFormat extends UsbACInterface {
- private static final String TAG = "ASFormat";
+public class UsbASFormat extends UsbACInterface {
+ private static final String TAG = "UsbASFormat";
private final byte mFormatType; // 3:1 FORMAT_TYPE_*
- public static final byte FORMAT_TYPE_I = 1;
- public static final byte FORMAT_TYPE_II = 2;
+ public static final byte FORMAT_TYPE_I = 1;
+ public static final byte FORMAT_TYPE_II = 2;
+ // these showed up in USB 2.0
+ public static final byte FORMAT_TYPE_III = 3;
+ public static final byte FORMAT_TYPE_IV = 4;
+
+ // "extended" formats
+ public static final byte EXT_FORMAT_TYPE_I = (byte) 0x81;
+ public static final byte EXT_FORMAT_TYPE_II = (byte) 0x82;
+ public static final byte EXT_FORMAT_TYPE_III = (byte) 0x83;
public UsbASFormat(int length, byte type, byte subtype, byte formatType, byte mSubclass) {
super(length, type, subtype, mSubclass);
@@ -38,27 +49,59 @@ public abstract class UsbASFormat extends UsbACInterface {
return mFormatType;
}
+ public int[] getSampleRates() {
+ return null;
+ }
+
+ public int[] getBitDepths() {
+ return null;
+ }
+
+ public int[] getChannelCounts() {
+ return null;
+ }
+
/**
* Allocates the audio-class format subtype associated with the format type read from the
* stream.
*/
- public static UsbDescriptor allocDescriptor(ByteStream stream, int length, byte type,
+ public static UsbDescriptor allocDescriptor(UsbDescriptorParser parser,
+ ByteStream stream, int length, byte type,
byte subtype, byte subclass) {
byte formatType = stream.getByte();
- //TODO
- // There is an issue parsing format descriptors on (some) USB 2.0 pro-audio interfaces
- // Since we don't need this info for headset detection, just skip these descriptors
- // for now to avoid the (low) possibility of an IndexOutOfBounds exception.
+ int acInterfaceSpec = parser.getACInterfaceSpec();
+
switch (formatType) {
-// case FORMAT_TYPE_I:
-// return new UsbASFormatI(length, type, subtype, formatType, subclass);
-//
-// case FORMAT_TYPE_II:
-// return new UsbASFormatII(length, type, subtype, formatType, subclass);
+ case FORMAT_TYPE_I:
+ if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) {
+ return new Usb20ASFormatI(length, type, subtype, formatType, subclass);
+ } else {
+ return new Usb10ASFormatI(length, type, subtype, formatType, subclass);
+ }
+
+ case FORMAT_TYPE_II:
+ if (acInterfaceSpec == UsbDeviceDescriptor.USBSPEC_2_0) {
+ return new Usb20ASFormatII(length, type, subtype, formatType, subclass);
+ } else {
+ return new Usb10ASFormatII(length, type, subtype, formatType, subclass);
+ }
+
+ // USB 2.0 Exclusive Format Types
+ case FORMAT_TYPE_III:
+ return new Usb20ASFormatIII(length, type, subtype, formatType, subclass);
+ case FORMAT_TYPE_IV:
+ //TODO - implement this type.
default:
- return null;
+ return new UsbASFormat(length, type, subtype, formatType, subclass);
}
}
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.write(UsbStrings.getFormatName(getFormatType()));
+ }
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbBinaryParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbBinaryParser.java
index 185cee20b090..9710ac67870f 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbBinaryParser.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbBinaryParser.java
@@ -25,7 +25,7 @@ import com.android.server.usb.descriptors.report.UsbStrings;
* A class that just walks the descriptors and does a hex dump of the contained values.
* Usefull as a debugging tool.
*/
-public class UsbBinaryParser {
+public final class UsbBinaryParser {
private static final String TAG = "UsbBinaryParser";
private static final boolean LOGGING = false;
@@ -33,7 +33,7 @@ public class UsbBinaryParser {
// Log
if (LOGGING) {
- Log.i(TAG, "l:" + length + " t:" + Integer.toHexString(type) + " "
+ Log.i(TAG, "l: " + length + " t: " + Integer.toHexString(type) + " "
+ UsbStrings.getDescriptorName(type));
StringBuilder sb = new StringBuilder();
for (int index = 2; index < length; index++) {
@@ -43,7 +43,7 @@ public class UsbBinaryParser {
} else {
// Screen Dump
builder.append("<p>");
- builder.append("<b> l:" + length
+ builder.append("<b> l: " + length
+ " t:0x" + Integer.toHexString(type) + " "
+ UsbStrings.getDescriptorName(type) + "</b><br>");
for (int index = 2; index < length; index++) {
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
index 8ae6d0f1ee7e..75279c61c4f0 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
@@ -15,13 +15,15 @@
*/
package com.android.server.usb.descriptors;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
/**
* @hide
* An USB Config Descriptor.
* see usb11.pdf section 9.6.2
*/
-public class UsbConfigDescriptor extends UsbDescriptor {
- private static final String TAG = "Config";
+public final class UsbConfigDescriptor extends UsbDescriptor {
+ private static final String TAG = "UsbConfigDescriptor";
private int mTotalLength; // 2:2 Total length in bytes of data returned
private byte mNumInterfaces; // 4:1 Number of Interfaces
@@ -35,6 +37,7 @@ public class UsbConfigDescriptor extends UsbDescriptor {
UsbConfigDescriptor(int length, byte type) {
super(length, type);
+ mHierarchyLevel = 2;
}
public int getTotalLength() {
@@ -63,7 +66,7 @@ public class UsbConfigDescriptor extends UsbDescriptor {
@Override
public int parseRawDescriptors(ByteStream stream) {
- mTotalLength = stream.unpackUsbWord();
+ mTotalLength = stream.unpackUsbShort();
mNumInterfaces = stream.getByte();
mConfigValue = stream.getByte();
mConfigIndex = stream.getByte();
@@ -72,4 +75,15 @@ public class UsbConfigDescriptor extends UsbDescriptor {
return mLength;
}
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.openList();
+ canvas.writeListItem("Config # " + getConfigValue());
+ canvas.writeListItem(getNumInterfaces() + " Interfaces.");
+ canvas.writeListItem("Attributes: " + ReportCanvas.getHexString(getAttribs()));
+ canvas.closeList();
+ }
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptor.java
index 63b2d7f6aed7..8c7565b790d2 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptor.java
@@ -19,6 +19,10 @@ import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDeviceConnection;
import android.util.Log;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+import com.android.server.usb.descriptors.report.Reporting;
+import com.android.server.usb.descriptors.report.UsbStrings;
+
/*
* Some notes about UsbDescriptor and its subclasses.
*
@@ -33,8 +37,10 @@ import android.util.Log;
* @hide
* Common superclass for all USB Descriptors.
*/
-public abstract class UsbDescriptor {
- private static final String TAG = "Descriptor";
+public abstract class UsbDescriptor implements Reporting {
+ private static final String TAG = "UsbDescriptor";
+
+ protected int mHierarchyLevel;
protected final int mLength; // 0:1 bLength Number Size of the Descriptor in Bytes (18 bytes)
// we store this as an int because Java bytes are SIGNED.
@@ -50,11 +56,15 @@ public abstract class UsbDescriptor {
public static final int STATUS_PARSED_OK = 1;
public static final int STATUS_PARSED_UNDERRUN = 2;
public static final int STATUS_PARSED_OVERRUN = 3;
+ public static final int STATUS_PARSE_EXCEPTION = 4;
+
private int mStatus = STATUS_UNPARSED;
private static String[] sStatusStrings = {
"UNPARSED", "PARSED - OK", "PARSED - UNDERRUN", "PARSED - OVERRUN"};
+ private int mOverUnderRunCount;
+
// Descriptor Type IDs
public static final byte DESCRIPTORTYPE_DEVICE = 0x01; // 1
public static final byte DESCRIPTORTYPE_CONFIG = 0x02; // 2
@@ -147,6 +157,10 @@ public abstract class UsbDescriptor {
mStatus = status;
}
+ public int getOverUnderRunCount() {
+ return mOverUnderRunCount;
+ }
+
public String getStatusString() {
return sStatusStrings[mStatus];
}
@@ -165,14 +179,16 @@ public abstract class UsbDescriptor {
// Too cold...
stream.advance(mLength - bytesRead);
mStatus = STATUS_PARSED_UNDERRUN;
+ mOverUnderRunCount = mLength - bytesRead;
Log.w(TAG, "UNDERRUN t:0x" + Integer.toHexString(mType)
- + " r:" + bytesRead + " < l:" + mLength);
+ + " r: " + bytesRead + " < l: " + mLength);
} else if (bytesRead > mLength) {
// Too hot...
stream.reverse(bytesRead - mLength);
mStatus = STATUS_PARSED_OVERRUN;
+ mOverUnderRunCount = bytesRead - mLength;
Log.w(TAG, "OVERRRUN t:0x" + Integer.toHexString(mType)
- + " r:" + bytesRead + " > l:" + mLength);
+ + " r: " + bytesRead + " > l: " + mLength);
} else {
// Just right!
mStatus = STATUS_PARSED_OK;
@@ -220,4 +236,43 @@ public abstract class UsbDescriptor {
}
return usbStr;
}
+
+ private void reportParseStatus(ReportCanvas canvas) {
+ int status = getStatus();
+ switch (status) {
+ case UsbDescriptor.STATUS_PARSED_OK:
+ break; // no need to report
+
+ case UsbDescriptor.STATUS_UNPARSED:
+ case UsbDescriptor.STATUS_PARSED_UNDERRUN:
+ case UsbDescriptor.STATUS_PARSED_OVERRUN:
+ canvas.writeParagraph("status: " + getStatusString()
+ + " [" + getOverUnderRunCount() + "]", true);
+ break;
+ }
+ }
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ String descTypeStr = UsbStrings.getDescriptorName(getType());
+ String text = descTypeStr + ": " + ReportCanvas.getHexString(getType())
+ + " Len: " + getLength();
+ if (mHierarchyLevel != 0) {
+ canvas.writeHeader(mHierarchyLevel, text);
+ } else {
+ canvas.writeParagraph(text, false);
+ }
+
+ if (getStatus() != STATUS_PARSED_OK) {
+ reportParseStatus(canvas);
+ }
+ }
+
+ @Override
+ public void shortReport(ReportCanvas canvas) {
+ String descTypeStr = UsbStrings.getDescriptorName(getType());
+ String text = descTypeStr + ": " + ReportCanvas.getHexString(getType())
+ + " Len: " + getLength();
+ canvas.writeParagraph(text, false);
+ }
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
index d4a0ac4a0da3..ad7bde5c275e 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
@@ -23,8 +23,8 @@ import java.util.ArrayList;
* @hide
* Class for parsing a binary stream of USB Descriptors.
*/
-public class UsbDescriptorParser {
- private static final String TAG = "DescriptorParser";
+public final class UsbDescriptorParser {
+ private static final String TAG = "UsbDescriptorParser";
// Descriptor Objects
private ArrayList<UsbDescriptor> mDescriptors = new ArrayList<UsbDescriptor>();
@@ -32,9 +32,35 @@ public class UsbDescriptorParser {
private UsbDeviceDescriptor mDeviceDescriptor;
private UsbInterfaceDescriptor mCurInterfaceDescriptor;
+ // The AudioClass spec implemented by the AudioClass Interfaces
+ // This may well be different than the overall USB Spec.
+ // Obtained from the first AudioClass Header descriptor.
+ private int mACInterfacesSpec = UsbDeviceDescriptor.USBSPEC_1_0;
+
public UsbDescriptorParser() {}
/**
+ * @return the USB Spec value associated with the Device descriptor for the
+ * descriptors stream being parsed.
+ *
+ * @throws IllegalArgumentException
+ */
+ public int getUsbSpec() {
+ if (mDeviceDescriptor != null) {
+ return mDeviceDescriptor.getSpec();
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ public void setACInterfaceSpec(int spec) {
+ mACInterfacesSpec = spec;
+ }
+
+ public int getACInterfaceSpec() {
+ return mACInterfacesSpec;
+ }
+ /**
* The probability (as returned by getHeadsetProbability() at which we conclude
* the peripheral is a headset.
*/
@@ -44,7 +70,7 @@ public class UsbDescriptorParser {
private UsbDescriptor allocDescriptor(ByteStream stream) {
stream.resetReadCount();
- int length = (int) stream.getByte() & 0x000000FF;
+ int length = stream.getUnsignedByte();
byte type = stream.getByte();
UsbDescriptor descriptor = null;
@@ -99,7 +125,7 @@ public class UsbDescriptorParser {
if (descriptor == null) {
// Unknown Descriptor
- Log.i(TAG, "Unknown Descriptor len:" + length + " type:0x"
+ Log.i(TAG, "Unknown Descriptor len: " + length + " type:0x"
+ Integer.toHexString(type));
descriptor = new UsbUnknown(length, type);
}
@@ -135,14 +161,15 @@ public class UsbDescriptorParser {
try {
descriptor.parseRawDescriptors(stream);
- // Its OK to add the invalid descriptor as the postParse()
- // routine will mark it as invalid.
- mDescriptors.add(descriptor);
-
// Clean up
descriptor.postParse(stream);
} catch (Exception ex) {
Log.e(TAG, "Exception parsing USB descriptors.", ex);
+
+ // Clean up
+ descriptor.setStatus(UsbDescriptor.STATUS_PARSE_EXCEPTION);
+ } finally {
+ mDescriptors.add(descriptor);
}
}
}
@@ -197,7 +224,7 @@ public class UsbDescriptorParser {
list.add(descriptor);
}
} else {
- Log.w(TAG, "Unrecognized Interface l:" + descriptor.getLength()
+ Log.w(TAG, "Unrecognized Interface l: " + descriptor.getLength()
+ " t:0x" + Integer.toHexString(descriptor.getType()));
}
}
@@ -220,7 +247,7 @@ public class UsbDescriptorParser {
list.add(descriptor);
}
} else {
- Log.w(TAG, "Unrecognized Audio Interface l:" + descriptor.getLength()
+ Log.w(TAG, "Unrecognized Audio Interface l: " + descriptor.getLength()
+ " t:0x" + Integer.toHexString(descriptor.getType()));
}
}
@@ -251,7 +278,7 @@ public class UsbDescriptorParser {
return true;
}
} else {
- Log.w(TAG, "Undefined Audio Class Interface l:" + descriptor.getLength()
+ Log.w(TAG, "Undefined Audio Class Interface l: " + descriptor.getLength()
+ " t:0x" + Integer.toHexString(descriptor.getType()));
}
}
@@ -274,8 +301,8 @@ public class UsbDescriptorParser {
acDescriptors = getACInterfaceDescriptors(UsbACInterface.ACI_INPUT_TERMINAL,
UsbACInterface.AUDIO_AUDIOCONTROL);
for (UsbDescriptor descriptor : acDescriptors) {
- if (descriptor instanceof UsbACInputTerminal) {
- UsbACInputTerminal inDescr = (UsbACInputTerminal) descriptor;
+ if (descriptor instanceof UsbACTerminal) {
+ UsbACTerminal inDescr = (UsbACTerminal) descriptor;
if (inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_IN_MIC
|| inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_HEADSET
|| inDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_BIDIR_UNDEFINED
@@ -284,7 +311,7 @@ public class UsbDescriptorParser {
break;
}
} else {
- Log.w(TAG, "Undefined Audio Input terminal l:" + descriptor.getLength()
+ Log.w(TAG, "Undefined Audio Input terminal l: " + descriptor.getLength()
+ " t:0x" + Integer.toHexString(descriptor.getType()));
}
}
@@ -295,8 +322,8 @@ public class UsbDescriptorParser {
getACInterfaceDescriptors(UsbACInterface.ACI_OUTPUT_TERMINAL,
UsbACInterface.AUDIO_AUDIOCONTROL);
for (UsbDescriptor descriptor : acDescriptors) {
- if (descriptor instanceof UsbACOutputTerminal) {
- UsbACOutputTerminal outDescr = (UsbACOutputTerminal) descriptor;
+ if (descriptor instanceof UsbACTerminal) {
+ UsbACTerminal outDescr = (UsbACTerminal) descriptor;
if (outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_OUT_SPEAKER
|| outDescr.getTerminalType()
== UsbTerminalTypes.TERMINAL_OUT_HEADPHONES
@@ -305,7 +332,7 @@ public class UsbDescriptorParser {
break;
}
} else {
- Log.w(TAG, "Undefined Audio Output terminal l:" + descriptor.getLength()
+ Log.w(TAG, "Undefined Audio Output terminal l: " + descriptor.getLength()
+ " t:0x" + Integer.toHexString(descriptor.getType()));
}
}
@@ -328,6 +355,8 @@ public class UsbDescriptorParser {
* to count on the peripheral being a headset.
*/
public boolean isInputHeadset() {
+ // TEMP
+ Log.i(TAG, "---- isInputHeadset() prob:" + (getInputHeadsetProbability() * 100f) + "%");
return getInputHeadsetProbability() >= IN_HEADSET_TRIGGER;
}
@@ -348,8 +377,8 @@ public class UsbDescriptorParser {
getACInterfaceDescriptors(UsbACInterface.ACI_OUTPUT_TERMINAL,
UsbACInterface.AUDIO_AUDIOCONTROL);
for (UsbDescriptor descriptor : acDescriptors) {
- if (descriptor instanceof UsbACOutputTerminal) {
- UsbACOutputTerminal outDescr = (UsbACOutputTerminal) descriptor;
+ if (descriptor instanceof UsbACTerminal) {
+ UsbACTerminal outDescr = (UsbACTerminal) descriptor;
if (outDescr.getTerminalType() == UsbTerminalTypes.TERMINAL_OUT_SPEAKER
|| outDescr.getTerminalType()
== UsbTerminalTypes.TERMINAL_OUT_HEADPHONES
@@ -358,7 +387,7 @@ public class UsbDescriptorParser {
break;
}
} else {
- Log.w(TAG, "Undefined Audio Output terminal l:" + descriptor.getLength()
+ Log.w(TAG, "Undefined Audio Output terminal l: " + descriptor.getLength()
+ " t:0x" + Integer.toHexString(descriptor.getType()));
}
}
@@ -381,6 +410,8 @@ public class UsbDescriptorParser {
* to count on the peripheral being a headset.
*/
public boolean isOutputHeadset() {
+ // TEMP
+ Log.i(TAG, "---- isOutputHeadset() prob:" + (getOutputHeadsetProbability() * 100f) + "%");
return getOutputHeadsetProbability() >= OUT_HEADSET_TRIGGER;
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
index 90848caba852..c8fa69451ac8 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
@@ -15,13 +15,20 @@
*/
package com.android.server.usb.descriptors;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+import com.android.server.usb.descriptors.report.UsbStrings;
+
/**
* @hide
* A USB Device Descriptor.
* see usb11.pdf section 9.6.1
*/
-/* public */ public class UsbDeviceDescriptor extends UsbDescriptor {
- private static final String TAG = "Device";
+public final class UsbDeviceDescriptor extends UsbDescriptor {
+ private static final String TAG = "UsbDeviceDescriptor";
+
+ public static final int USBSPEC_1_0 = 0x0100;
+ public static final int USBSPEC_1_1 = 0x0110;
+ public static final int USBSPEC_2_0 = 0x0200;
private int mSpec; // 2:2 bcdUSB 2 BCD USB Specification Number - BCD
private byte mDevClass; // 4:1 class code
@@ -39,6 +46,7 @@ package com.android.server.usb.descriptors;
UsbDeviceDescriptor(int length, byte type) {
super(length, type);
+ mHierarchyLevel = 1;
}
public int getSpec() {
@@ -91,14 +99,14 @@ package com.android.server.usb.descriptors;
@Override
public int parseRawDescriptors(ByteStream stream) {
- mSpec = stream.unpackUsbWord();
+ mSpec = stream.unpackUsbShort();
mDevClass = stream.getByte();
mDevSubClass = stream.getByte();
mProtocol = stream.getByte();
mPacketSize = stream.getByte();
- mVendorID = stream.unpackUsbWord();
- mProductID = stream.unpackUsbWord();
- mDeviceRelease = stream.unpackUsbWord();
+ mVendorID = stream.unpackUsbShort();
+ mProductID = stream.unpackUsbShort();
+ mDeviceRelease = stream.unpackUsbShort();
mMfgIndex = stream.getByte();
mProductIndex = stream.getByte();
mSerialNum = stream.getByte();
@@ -106,4 +114,35 @@ package com.android.server.usb.descriptors;
return mLength;
}
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.openList();
+
+ int spec = getSpec();
+ canvas.writeListItem("Spec: " + ReportCanvas.getBCDString(spec));
+
+ byte devClass = getDevClass();
+ String classStr = UsbStrings.getClassName(devClass);
+ byte devSubClass = getDevSubClass();
+ String subClasStr = UsbStrings.getClassName(devSubClass);
+ canvas.writeListItem("Class " + devClass + ": " + classStr + " Subclass"
+ + devSubClass + ": " + subClasStr);
+ canvas.writeListItem("Vendor ID: " + getVendorID()
+ + " Product ID: " + getProductID()
+ + " Product Release: " + ReportCanvas.getBCDString(getDeviceRelease()));
+
+ byte mfgIndex = getMfgIndex();
+ String manufacturer =
+ UsbDescriptor.getUsbDescriptorString(canvas.getConnection(), mfgIndex);
+ byte productIndex = getProductIndex();
+ String product =
+ UsbDescriptor.getUsbDescriptorString(canvas.getConnection(), productIndex);
+
+ canvas.writeListItem("Manufacturer " + mfgIndex + ": " + manufacturer
+ + " Product " + productIndex + ": " + product);
+ canvas.closeList();
+ }
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
index def670093e6e..6322fbe8b45b 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
@@ -15,36 +15,38 @@
*/
package com.android.server.usb.descriptors;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
/**
* @hide
* A Usb Endpoint Descriptor.
* see usb11.pdf section 9.6.4
*/
public class UsbEndpointDescriptor extends UsbDescriptor {
- private static final String TAG = "EndPoint";
+ private static final String TAG = "UsbEndpointDescriptor";
- public static final byte MASK_ENDPOINT_ADDRESS = 0b0001111;
- public static final byte MASK_ENDPOINT_DIRECTION = (byte) 0b10000000;
- public static final byte DIRECTION_OUTPUT = 0x00;
- public static final byte DIRECTION_INPUT = (byte) 0x80;
+ public static final byte MASK_ENDPOINT_ADDRESS = 0b0001111;
+ public static final byte MASK_ENDPOINT_DIRECTION = (byte) 0b10000000;
+ public static final byte DIRECTION_OUTPUT = 0x00;
+ public static final byte DIRECTION_INPUT = (byte) 0x80;
public static final byte MASK_ATTRIBS_TRANSTYPE = 0b00000011;
- public static final byte TRANSTYPE_CONTROL = 0x00;
- public static final byte TRANSTYPE_ISO = 0x01;
- public static final byte TRANSTYPE_BULK = 0x02;
- public static final byte TRANSTYPE_INTERRUPT = 0x03;
-
- public static final byte MASK_ATTRIBS_SYNCTYPE = 0b00001100;
- public static final byte SYNCTYPE_NONE = 0b00000000;
- public static final byte SYNCTYPE_ASYNC = 0b00000100;
- public static final byte SYNCTYPE_ADAPTSYNC = 0b00001000;
- public static final byte SYNCTYPE_RESERVED = 0b00001100;
-
- public static final byte MASK_ATTRIBS_USEAGE = 0b00110000;
- public static final byte USEAGE_DATA = 0b00000000;
- public static final byte USEAGE_FEEDBACK = 0b00010000;
- public static final byte USEAGE_EXPLICIT = 0b00100000;
- public static final byte USEAGE_RESERVED = 0b00110000;
+ public static final byte TRANSTYPE_CONTROL = 0x00;
+ public static final byte TRANSTYPE_ISO = 0x01;
+ public static final byte TRANSTYPE_BULK = 0x02;
+ public static final byte TRANSTYPE_INTERRUPT = 0x03;
+
+ public static final byte MASK_ATTRIBS_SYNCTYPE = 0b00001100;
+ public static final byte SYNCTYPE_NONE = 0b00000000;
+ public static final byte SYNCTYPE_ASYNC = 0b00000100;
+ public static final byte SYNCTYPE_ADAPTSYNC = 0b00001000;
+ public static final byte SYNCTYPE_RESERVED = 0b00001100;
+
+ public static final byte MASK_ATTRIBS_USEAGE = 0b00110000;
+ public static final byte USEAGE_DATA = 0b00000000;
+ public static final byte USEAGE_FEEDBACK = 0b00010000;
+ public static final byte USEAGE_EXPLICIT = 0b00100000;
+ public static final byte USEAGE_RESERVED = 0b00110000;
private byte mEndpointAddress; // 2:1 Endpoint Address
// Bits 0..3b Endpoint Number.
@@ -76,6 +78,7 @@ public class UsbEndpointDescriptor extends UsbDescriptor {
public UsbEndpointDescriptor(int length, byte type) {
super(length, type);
+ mHierarchyLevel = 4;
}
public byte getEndpointAddress() {
@@ -106,7 +109,7 @@ public class UsbEndpointDescriptor extends UsbDescriptor {
public int parseRawDescriptors(ByteStream stream) {
mEndpointAddress = stream.getByte();
mAttributes = stream.getByte();
- mPacketSize = stream.unpackUsbWord();
+ mPacketSize = stream.unpackUsbShort();
mInterval = stream.getByte();
if (mLength == 9) {
mRefresh = stream.getByte();
@@ -114,4 +117,76 @@ public class UsbEndpointDescriptor extends UsbDescriptor {
}
return mLength;
}
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.openList();
+
+ byte address = getEndpointAddress();
+ canvas.writeListItem("Address: "
+ + ReportCanvas.getHexString(address & UsbEndpointDescriptor.MASK_ENDPOINT_ADDRESS)
+ + ((address & UsbEndpointDescriptor.MASK_ENDPOINT_DIRECTION)
+ == UsbEndpointDescriptor.DIRECTION_OUTPUT ? " [out]" : " [in]"));
+
+ byte attributes = getAttributes();
+ canvas.openListItem();
+ canvas.write("Attributes: " + ReportCanvas.getHexString(attributes) + " ");
+ switch (attributes & UsbEndpointDescriptor.MASK_ATTRIBS_TRANSTYPE) {
+ case UsbEndpointDescriptor.TRANSTYPE_CONTROL:
+ canvas.write("Control");
+ break;
+ case UsbEndpointDescriptor.TRANSTYPE_ISO:
+ canvas.write("Iso");
+ break;
+ case UsbEndpointDescriptor.TRANSTYPE_BULK:
+ canvas.write("Bulk");
+ break;
+ case UsbEndpointDescriptor.TRANSTYPE_INTERRUPT:
+ canvas.write("Interrupt");
+ break;
+ }
+ canvas.closeListItem();
+
+ // These flags are only relevant for ISO transfer type
+ if ((attributes & UsbEndpointDescriptor.MASK_ATTRIBS_TRANSTYPE)
+ == UsbEndpointDescriptor.TRANSTYPE_ISO) {
+ canvas.openListItem();
+ canvas.write("Aync: ");
+ switch (attributes & UsbEndpointDescriptor.MASK_ATTRIBS_SYNCTYPE) {
+ case UsbEndpointDescriptor.SYNCTYPE_NONE:
+ canvas.write("NONE");
+ break;
+ case UsbEndpointDescriptor.SYNCTYPE_ASYNC:
+ canvas.write("ASYNC");
+ break;
+ case UsbEndpointDescriptor.SYNCTYPE_ADAPTSYNC:
+ canvas.write("ADAPTIVE ASYNC");
+ break;
+ }
+ canvas.closeListItem();
+
+ canvas.openListItem();
+ canvas.write("Useage: ");
+ switch (attributes & UsbEndpointDescriptor.MASK_ATTRIBS_USEAGE) {
+ case UsbEndpointDescriptor.USEAGE_DATA:
+ canvas.write("DATA");
+ break;
+ case UsbEndpointDescriptor.USEAGE_FEEDBACK:
+ canvas.write("FEEDBACK");
+ break;
+ case UsbEndpointDescriptor.USEAGE_EXPLICIT:
+ canvas.write("EXPLICIT FEEDBACK");
+ break;
+ case UsbEndpointDescriptor.USEAGE_RESERVED:
+ canvas.write("RESERVED");
+ break;
+ }
+ canvas.closeListItem();
+ }
+ canvas.writeListItem("Package Size: " + getPacketSize());
+ canvas.writeListItem("Interval: " + getInterval());
+ canvas.closeList();
+ }
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbHIDDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbHIDDescriptor.java
index 56c07ec9a071..b4cc87e096df 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbHIDDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbHIDDescriptor.java
@@ -15,13 +15,15 @@
*/
package com.android.server.usb.descriptors;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
/**
* @hide
* A USB HID (Human Interface Descriptor).
* see HID1_11.pdf - 6.2.1
*/
-public class UsbHIDDescriptor extends UsbDescriptor {
- private static final String TAG = "HID";
+public final class UsbHIDDescriptor extends UsbDescriptor {
+ private static final String TAG = "UsbHIDDescriptor";
private int mRelease; // 2:2 the HID Class Specification release.
private byte mCountryCode; // 4:1 country code of the localized hardware.
@@ -35,6 +37,7 @@ public class UsbHIDDescriptor extends UsbDescriptor {
public UsbHIDDescriptor(int length, byte type) {
super(length, type);
+ mHierarchyLevel = 3;
}
public int getRelease() {
@@ -59,12 +62,24 @@ public class UsbHIDDescriptor extends UsbDescriptor {
@Override
public int parseRawDescriptors(ByteStream stream) {
- mRelease = stream.unpackUsbWord();
+ mRelease = stream.unpackUsbShort();
mCountryCode = stream.getByte();
mNumDescriptors = stream.getByte();
mDescriptorType = stream.getByte();
- mDescriptorLen = stream.unpackUsbWord();
+ mDescriptorLen = stream.unpackUsbShort();
return mLength;
}
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.openList();
+ canvas.writeListItem("Spec: " + ReportCanvas.getBCDString(getRelease()));
+ canvas.writeListItem("Type: " + ReportCanvas.getBCDString(getDescriptorType()));
+ canvas.writeListItem("" + getNumDescriptors() + " Descriptors Len: "
+ + getDescriptorLen());
+ canvas.closeList();
+ }
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceAssoc.java b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceAssoc.java
index 4b18a01b1c8b..d680e543693a 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceAssoc.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceAssoc.java
@@ -15,14 +15,16 @@
*/
package com.android.server.usb.descriptors;
+// import com.android.server.usb.descriptors.report.ReportCanvas;
+
/**
* @hide
* A USB Interface Association Descriptor.
* found this one here: http://www.usb.org/developers/docs/whitepapers/iadclasscode_r10.pdf
* also: https://msdn.microsoft.com/en-us/library/windows/hardware/ff540054(v=vs.85).aspx
*/
-public class UsbInterfaceAssoc extends UsbDescriptor {
- private static final String TAG = "InterfaceAssoc";
+public final class UsbInterfaceAssoc extends UsbDescriptor {
+ private static final String TAG = "UsbInterfaceAssoc";
private byte mFirstInterface;
private byte mInterfaceCount;
@@ -70,4 +72,11 @@ public class UsbInterfaceAssoc extends UsbDescriptor {
return mLength;
}
+
+ // TODO - Report fields
+// @Override
+// public void report(ReportCanvas canvas) {
+// super.report(canvas);
+//
+// }
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java
index 21b5e0cbaa1b..4eef6caf5a60 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java
@@ -15,13 +15,16 @@
*/
package com.android.server.usb.descriptors;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+import com.android.server.usb.descriptors.report.UsbStrings;
+
/**
* @hide
* A common super-class for all USB Interface Descritor subtypes.
* see usb11.pdf section 9.6.3
*/
public class UsbInterfaceDescriptor extends UsbDescriptor {
- private static final String TAG = "Interface";
+ private static final String TAG = "UsbInterfaceDescriptor";
protected byte mInterfaceNumber; // 2:1 Number of Interface
protected byte mAlternateSetting; // 3:1 Value used to select alternative setting
@@ -33,6 +36,7 @@ public class UsbInterfaceDescriptor extends UsbDescriptor {
UsbInterfaceDescriptor(int length, byte type) {
super(length, type);
+ mHierarchyLevel = 3;
}
@Override
@@ -75,4 +79,27 @@ public class UsbInterfaceDescriptor extends UsbDescriptor {
public byte getDescrIndex() {
return mDescrIndex;
}
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ byte usbClass = getUsbClass();
+ byte usbSubclass = getUsbSubclass();
+ byte protocol = getProtocol();
+ String className = UsbStrings.getClassName(usbClass);
+ String subclassName = "";
+ if (usbClass == UsbDescriptor.CLASSID_AUDIO) {
+ subclassName = UsbStrings.getAudioSubclassName(usbSubclass);
+ }
+
+ canvas.openList();
+ canvas.writeListItem("Interface #" + getInterfaceNumber());
+ canvas.writeListItem("Class: " + ReportCanvas.getHexString(usbClass) + ": " + className);
+ canvas.writeListItem("Subclass: "
+ + ReportCanvas.getHexString(usbSubclass) + ": " + subclassName);
+ canvas.writeListItem("Protocol: " + protocol + ": " + ReportCanvas.getHexString(protocol));
+ canvas.writeListItem("Endpoints: " + getNumEndpoints());
+ canvas.closeList();
+ }
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiHeader.java b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiHeader.java
index 4452b23cb6ae..85a3e6802ff7 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiHeader.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiHeader.java
@@ -15,13 +15,15 @@
*/
package com.android.server.usb.descriptors;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
/**
* @hide
* An audio class-specific Midi Streaming Interface.
* see midi10.pdf section 6.1.2.1
*/
-public class UsbMSMidiHeader extends UsbACInterface {
- private static final String TAG = "MSMidiHeader";
+public final class UsbMSMidiHeader extends UsbACInterface {
+ private static final String TAG = "UsbMSMidiHeader";
public UsbMSMidiHeader(int length, byte type, byte subtype, byte subclass) {
super(length, type, subtype, subclass);
@@ -33,4 +35,13 @@ public class UsbMSMidiHeader extends UsbACInterface {
stream.advance(mLength - stream.getReadCount());
return mLength;
}
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.writeHeader(3, "MS Midi Header: " + ReportCanvas.getHexString(getType())
+ + " SubType: " + ReportCanvas.getHexString(getSubclass())
+ + " Length: " + getLength());
+ }
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiInputJack.java b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiInputJack.java
index 2d33ba7727dd..1d5cbf2b5c99 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiInputJack.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiInputJack.java
@@ -15,13 +15,15 @@
*/
package com.android.server.usb.descriptors;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
/**
* @hide
* An audio class-specific Midi Input Jack Interface.
* see midi10.pdf section B.4.3
*/
-public class UsbMSMidiInputJack extends UsbACInterface {
- private static final String TAG = "MSMidiInputJack";
+public final class UsbMSMidiInputJack extends UsbACInterface {
+ private static final String TAG = "UsbMSMidiInputJack";
UsbMSMidiInputJack(int length, byte type, byte subtype, byte subclass) {
super(length, type, subtype, subclass);
@@ -33,4 +35,13 @@ public class UsbMSMidiInputJack extends UsbACInterface {
stream.advance(mLength - stream.getReadCount());
return mLength;
}
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.writeHeader(3, "MS Midi Input Jack: " + ReportCanvas.getHexString(getType())
+ + " SubType: " + ReportCanvas.getHexString(getSubclass())
+ + " Length: " + getLength());
+ }
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiOutputJack.java b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiOutputJack.java
index bd2dc11d57df..9f50240a94ca 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiOutputJack.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbMSMidiOutputJack.java
@@ -15,13 +15,15 @@
*/
package com.android.server.usb.descriptors;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
/**
* @hide
* An audio class-specific Midi Output Jack Interface.
* see midi10.pdf section B.4.4
*/
-public class UsbMSMidiOutputJack extends UsbACInterface {
- private static final String TAG = "MSMidiOutputJack";
+public final class UsbMSMidiOutputJack extends UsbACInterface {
+ private static final String TAG = "UsbMSMidiOutputJack";
public UsbMSMidiOutputJack(int length, byte type, byte subtype, byte subclass) {
super(length, type, subtype, subclass);
@@ -33,4 +35,13 @@ public class UsbMSMidiOutputJack extends UsbACInterface {
stream.advance(mLength - stream.getReadCount());
return mLength;
}
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ super.report(canvas);
+
+ canvas.writeHeader(3, "MS Midi Output Jack: " + ReportCanvas.getHexString(getType())
+ + " SubType: " + ReportCanvas.getHexString(getSubclass())
+ + " Length: " + getLength());
+ }
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbTerminalTypes.java b/services/usb/java/com/android/server/usb/descriptors/UsbTerminalTypes.java
index b5214625126a..9bd6cb942888 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbTerminalTypes.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbTerminalTypes.java
@@ -20,8 +20,8 @@ package com.android.server.usb.descriptors;
* A class for decoding information in Terminal Descriptors.
* see termt10.pdf
*/
-public class UsbTerminalTypes {
- private static final String TAG = "TerminalTypes";
+public final class UsbTerminalTypes {
+ private static final String TAG = "UsbTerminalTypes";
// USB
public static final int TERMINAL_USB_STREAMING = 0x0101;
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbUnknown.java b/services/usb/java/com/android/server/usb/descriptors/UsbUnknown.java
index a6fe8bba3508..6e6dccf00613 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbUnknown.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbUnknown.java
@@ -19,8 +19,8 @@ package com.android.server.usb.descriptors;
* @hide
* A holder for any unrecognized descriptor encountered in the descriptor stream.
*/
-public class UsbUnknown extends UsbDescriptor {
- static final String TAG = "Unknown";
+public final class UsbUnknown extends UsbDescriptor {
+ static final String TAG = "UsbUnknown";
public UsbUnknown(int length, byte type) {
super(length, type);
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java b/services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java
new file mode 100644
index 000000000000..99ebccade735
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors.report;
+
+import android.hardware.usb.UsbDeviceConnection;
+
+/**
+ * @hide
+ * A concrete implementation of ReportCanvas class which generates HTML.
+ */
+public final class HTMLReportCanvas extends ReportCanvas {
+ private static final String TAG = "HTMLReportCanvas";
+
+ private final StringBuilder mStringBuilder;
+
+ /**
+ * Constructor. Connects HTML output to the provided StringBuilder.
+ * @param connection The USB connection object used to retrieve strings
+ * from the USB device.
+ * @param stringBuilder Generated output gets written into this object.
+ */
+ public HTMLReportCanvas(UsbDeviceConnection connection, StringBuilder stringBuilder) {
+ super(connection);
+
+ mStringBuilder = stringBuilder;
+ }
+
+ @Override
+ public void write(String text) {
+ mStringBuilder.append(text);
+ }
+
+ @Override
+ public void openHeader(int level) {
+ mStringBuilder.append("<h").append(level).append('>');
+ }
+
+ @Override
+ public void closeHeader(int level) {
+ mStringBuilder.append("</h").append(level).append('>');
+ }
+
+ // we can be cleverer (more clever?) with styles, but this will do for now.
+ @Override
+ public void openParagraph(boolean emphasis) {
+ if (emphasis) {
+ mStringBuilder.append("<p style=\"color:red\">");
+ } else {
+ mStringBuilder.append("<p>");
+ }
+ }
+
+ @Override
+ public void closeParagraph() {
+ mStringBuilder.append("</p>");
+ }
+
+ @Override
+ public void writeParagraph(String text, boolean inRed) {
+ openParagraph(inRed);
+ mStringBuilder.append(text);
+ closeParagraph();
+ }
+
+ @Override
+ public void openList() {
+ mStringBuilder.append("<ul>");
+ }
+
+ @Override
+ public void closeList() {
+ mStringBuilder.append("</ul>");
+ }
+
+ @Override
+ public void openListItem() {
+ mStringBuilder.append("<li>");
+ }
+
+ @Override
+ public void closeListItem() {
+ mStringBuilder.append("</li>");
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/HTMLReporter.java b/services/usb/java/com/android/server/usb/descriptors/report/HTMLReporter.java
deleted file mode 100644
index c98789d880a0..000000000000
--- a/services/usb/java/com/android/server/usb/descriptors/report/HTMLReporter.java
+++ /dev/null
@@ -1,572 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.usb.descriptors.report;
-
-import android.hardware.usb.UsbDeviceConnection;
-
-import com.android.server.usb.descriptors.UsbACAudioControlEndpoint;
-import com.android.server.usb.descriptors.UsbACAudioStreamEndpoint;
-import com.android.server.usb.descriptors.UsbACFeatureUnit;
-import com.android.server.usb.descriptors.UsbACHeader;
-import com.android.server.usb.descriptors.UsbACInputTerminal;
-import com.android.server.usb.descriptors.UsbACInterface;
-import com.android.server.usb.descriptors.UsbACMidiEndpoint;
-import com.android.server.usb.descriptors.UsbACMixerUnit;
-import com.android.server.usb.descriptors.UsbACOutputTerminal;
-import com.android.server.usb.descriptors.UsbACSelectorUnit;
-import com.android.server.usb.descriptors.UsbACTerminal;
-import com.android.server.usb.descriptors.UsbASFormat;
-import com.android.server.usb.descriptors.UsbASFormatI;
-import com.android.server.usb.descriptors.UsbASFormatII;
-import com.android.server.usb.descriptors.UsbASGeneral;
-import com.android.server.usb.descriptors.UsbConfigDescriptor;
-import com.android.server.usb.descriptors.UsbDescriptor;
-import com.android.server.usb.descriptors.UsbDeviceDescriptor;
-import com.android.server.usb.descriptors.UsbEndpointDescriptor;
-import com.android.server.usb.descriptors.UsbHIDDescriptor;
-import com.android.server.usb.descriptors.UsbInterfaceAssoc;
-import com.android.server.usb.descriptors.UsbInterfaceDescriptor;
-import com.android.server.usb.descriptors.UsbMSMidiHeader;
-import com.android.server.usb.descriptors.UsbMSMidiInputJack;
-import com.android.server.usb.descriptors.UsbMSMidiOutputJack;
-import com.android.server.usb.descriptors.UsbUnknown;
-
-/**
- * Implements the Reporter inteface to provide HTML reporting for UsbDescriptor subclasses.
- */
-public class HTMLReporter implements Reporter {
- private final StringBuilder mStringBuilder;
- private final UsbDeviceConnection mConnection;
-
- public HTMLReporter(StringBuilder stringBuilder, UsbDeviceConnection connection) {
- mStringBuilder = stringBuilder;
- mConnection = connection;
- }
-
- /*
- * HTML Helpers
- */
- private void writeHeader(int level, String text) {
- mStringBuilder
- .append("<h").append(level).append('>')
- .append(text)
- .append("</h").append(level).append('>');
- }
-
- private void openParagraph() {
- mStringBuilder.append("<p>");
- }
-
- private void closeParagraph() {
- mStringBuilder.append("</p>");
- }
-
- private void writeParagraph(String text) {
- openParagraph();
- mStringBuilder.append(text);
- closeParagraph();
- }
-
- private void openList() {
- mStringBuilder.append("<ul>");
- }
-
- private void closeList() {
- mStringBuilder.append("</ul>");
- }
-
- private void openListItem() {
- mStringBuilder.append("<li>");
- }
-
- private void closeListItem() {
- mStringBuilder.append("</li>");
- }
-
- private void writeListItem(String text) {
- openListItem();
- mStringBuilder.append(text);
- closeListItem();
- }
-
- /*
- * Data Formating Helpers
- */
- private static String getHexString(byte value) {
- return "0x" + Integer.toHexString(((int) value) & 0xFF).toUpperCase();
- }
-
- private static String getBCDString(int value) {
- int major = value >> 8;
- int minor = (value >> 4) & 0x0F;
- int subminor = value & 0x0F;
-
- return "" + major + "." + minor + subminor;
- }
-
- private static String getHexString(int value) {
- int intValue = value & 0xFFFF;
- return "0x" + Integer.toHexString(intValue).toUpperCase();
- }
-
- private void dumpHexArray(byte[] rawData, StringBuilder builder) {
- if (rawData != null) {
- // Assume the type and Length and perhaps sub-type have been displayed
- openParagraph();
- for (int index = 0; index < rawData.length; index++) {
- builder.append(getHexString(rawData[index]) + " ");
- }
- closeParagraph();
- }
- }
-
- /**
- * Decode ACTUAL UsbDescriptor sub classes and call type-specific report methods.
- */
- @Override
- public void report(UsbDescriptor descriptor) {
- if (descriptor instanceof UsbDeviceDescriptor) {
- tsReport((UsbDeviceDescriptor) descriptor);
- } else if (descriptor instanceof UsbConfigDescriptor) {
- tsReport((UsbConfigDescriptor) descriptor);
- } else if (descriptor instanceof UsbInterfaceDescriptor) {
- tsReport((UsbInterfaceDescriptor) descriptor);
- } else if (descriptor instanceof UsbEndpointDescriptor) {
- tsReport((UsbEndpointDescriptor) descriptor);
- } else if (descriptor instanceof UsbHIDDescriptor) {
- tsReport((UsbHIDDescriptor) descriptor);
- } else if (descriptor instanceof UsbACAudioControlEndpoint) {
- tsReport((UsbACAudioControlEndpoint) descriptor);
- } else if (descriptor instanceof UsbACAudioStreamEndpoint) {
- tsReport((UsbACAudioStreamEndpoint) descriptor);
- } else if (descriptor instanceof UsbACHeader) {
- tsReport((UsbACHeader) descriptor);
- } else if (descriptor instanceof UsbACFeatureUnit) {
- tsReport((UsbACFeatureUnit) descriptor);
- } else if (descriptor instanceof UsbACInputTerminal) {
- tsReport((UsbACInputTerminal) descriptor);
- } else if (descriptor instanceof UsbACOutputTerminal) {
- tsReport((UsbACOutputTerminal) descriptor);
- } else if (descriptor instanceof UsbACMidiEndpoint) {
- tsReport((UsbACMidiEndpoint) descriptor);
- } else if (descriptor instanceof UsbACMixerUnit) {
- tsReport((UsbACMixerUnit) descriptor);
- } else if (descriptor instanceof UsbACSelectorUnit) {
- tsReport((UsbACSelectorUnit) descriptor);
- } else if (descriptor instanceof UsbASFormatI) {
- tsReport((UsbASFormatI) descriptor);
- } else if (descriptor instanceof UsbASFormatII) {
- tsReport((UsbASFormatII) descriptor);
- } else if (descriptor instanceof UsbASFormat) {
- tsReport((UsbASFormat) descriptor);
- } else if (descriptor instanceof UsbASGeneral) {
- tsReport((UsbASGeneral) descriptor);
- } else if (descriptor instanceof UsbInterfaceAssoc) {
- tsReport((UsbInterfaceAssoc) descriptor);
- } else if (descriptor instanceof UsbMSMidiHeader) {
- tsReport((UsbMSMidiHeader) descriptor);
- } else if (descriptor instanceof UsbMSMidiInputJack) {
- tsReport((UsbMSMidiInputJack) descriptor);
- } else if (descriptor instanceof UsbMSMidiOutputJack) {
- tsReport((UsbMSMidiOutputJack) descriptor);
- } else if (descriptor instanceof UsbUnknown) {
- tsReport((UsbUnknown) descriptor);
- } else if (descriptor instanceof UsbACInterface) {
- tsReport((UsbACInterface) descriptor);
- } else if (descriptor instanceof UsbDescriptor) {
- tsReport((UsbDescriptor) descriptor);
- }
- }
-
- //
- // Type-specific report() implementations
- //
- private void tsReport(UsbDescriptor descriptor) {
- int length = descriptor.getLength();
- byte type = descriptor.getType();
- int status = descriptor.getStatus();
-
- String descTypeStr = UsbStrings.getDescriptorName(type);
- writeParagraph(descTypeStr + ":" + type + " l:" + length + " s:" + status);
- }
-
- private void tsReport(UsbDeviceDescriptor descriptor) {
- writeHeader(1, "Device len:" + descriptor.getLength());
- openList();
-
- int spec = descriptor.getSpec();
- writeListItem("spec:" + getBCDString(spec));
-
- byte devClass = descriptor.getDevClass();
- String classStr = UsbStrings.getClassName(devClass);
- byte devSubClass = descriptor.getDevSubClass();
- String subClasStr = UsbStrings.getClassName(devSubClass);
- writeListItem("class " + devClass + ":" + classStr + " subclass"
- + devSubClass + ":" + subClasStr);
- writeListItem("vendorID:" + descriptor.getVendorID()
- + " prodID:" + descriptor.getProductID()
- + " prodRel:" + getBCDString(descriptor.getDeviceRelease()));
-
- byte mfgIndex = descriptor.getMfgIndex();
- String manufacturer = UsbDescriptor.getUsbDescriptorString(mConnection, mfgIndex);
- byte productIndex = descriptor.getProductIndex();
- String product = UsbDescriptor.getUsbDescriptorString(mConnection, productIndex);
-
- writeListItem("mfg " + mfgIndex + ":" + manufacturer
- + " prod " + productIndex + ":" + product);
- closeList();
- }
-
- private void tsReport(UsbConfigDescriptor descriptor) {
- writeHeader(2, "Config #" + descriptor.getConfigValue()
- + " len:" + descriptor.getLength());
-
- openList();
- writeListItem(descriptor.getNumInterfaces() + " interfaces.");
- writeListItem("attribs:" + getHexString(descriptor.getAttribs()));
- closeList();
- }
-
- private void tsReport(UsbInterfaceDescriptor descriptor) {
- byte usbClass = descriptor.getUsbClass();
- byte usbSubclass = descriptor.getUsbSubclass();
- String descr = UsbStrings.getDescriptorName(descriptor.getType());
- String className = UsbStrings.getClassName(usbClass);
- String subclassName = "";
- if (usbClass == UsbDescriptor.CLASSID_AUDIO) {
- subclassName = UsbStrings.getAudioSubclassName(usbSubclass);
- }
-
- writeHeader(2, descr + " #" + descriptor.getInterfaceNumber()
- + " len:" + descriptor.getLength());
- String descrStr =
- UsbDescriptor.getUsbDescriptorString(mConnection, descriptor.getDescrIndex());
- if (descrStr.length() > 0) {
- mStringBuilder.append("<br>" + descrStr);
- }
- openList();
- writeListItem("class " + getHexString(usbClass) + ":" + className
- + " subclass " + getHexString(usbSubclass) + ":" + subclassName);
- writeListItem("" + descriptor.getNumEndpoints() + " endpoints");
- closeList();
- }
-
- private void tsReport(UsbEndpointDescriptor descriptor) {
- writeHeader(3, "Endpoint " + getHexString(descriptor.getType())
- + " len:" + descriptor.getLength());
- openList();
-
- byte address = descriptor.getEndpointAddress();
- writeListItem("address:"
- + getHexString(address & UsbEndpointDescriptor.MASK_ENDPOINT_ADDRESS)
- + ((address & UsbEndpointDescriptor.MASK_ENDPOINT_DIRECTION)
- == UsbEndpointDescriptor.DIRECTION_OUTPUT ? " [out]" : " [in]"));
-
- byte attributes = descriptor.getAttributes();
- openListItem();
- mStringBuilder.append("attribs:" + getHexString(attributes) + " ");
- switch (attributes & UsbEndpointDescriptor.MASK_ATTRIBS_TRANSTYPE) {
- case UsbEndpointDescriptor.TRANSTYPE_CONTROL:
- mStringBuilder.append("Control");
- break;
- case UsbEndpointDescriptor.TRANSTYPE_ISO:
- mStringBuilder.append("Iso");
- break;
- case UsbEndpointDescriptor.TRANSTYPE_BULK:
- mStringBuilder.append("Bulk");
- break;
- case UsbEndpointDescriptor.TRANSTYPE_INTERRUPT:
- mStringBuilder.append("Interrupt");
- break;
- }
- closeListItem();
-
- // These flags are only relevant for ISO transfer type
- if ((attributes & UsbEndpointDescriptor.MASK_ATTRIBS_TRANSTYPE)
- == UsbEndpointDescriptor.TRANSTYPE_ISO) {
- openListItem();
- mStringBuilder.append("sync:");
- switch (attributes & UsbEndpointDescriptor.MASK_ATTRIBS_SYNCTYPE) {
- case UsbEndpointDescriptor.SYNCTYPE_NONE:
- mStringBuilder.append("NONE");
- break;
- case UsbEndpointDescriptor.SYNCTYPE_ASYNC:
- mStringBuilder.append("ASYNC");
- break;
- case UsbEndpointDescriptor.SYNCTYPE_ADAPTSYNC:
- mStringBuilder.append("ADAPTIVE ASYNC");
- break;
- }
- closeListItem();
-
- openListItem();
- mStringBuilder.append("useage:");
- switch (attributes & UsbEndpointDescriptor.MASK_ATTRIBS_USEAGE) {
- case UsbEndpointDescriptor.USEAGE_DATA:
- mStringBuilder.append("DATA");
- break;
- case UsbEndpointDescriptor.USEAGE_FEEDBACK:
- mStringBuilder.append("FEEDBACK");
- break;
- case UsbEndpointDescriptor.USEAGE_EXPLICIT:
- mStringBuilder.append("EXPLICIT FEEDBACK");
- break;
- case UsbEndpointDescriptor.USEAGE_RESERVED:
- mStringBuilder.append("RESERVED");
- break;
- }
- closeListItem();
- }
- writeListItem("package size:" + descriptor.getPacketSize());
- writeListItem("interval:" + descriptor.getInterval());
- closeList();
- }
-
- private void tsReport(UsbHIDDescriptor descriptor) {
- String descr = UsbStrings.getDescriptorName(descriptor.getType());
- writeHeader(2, descr + " len:" + descriptor.getLength());
- openList();
- writeListItem("spec:" + getBCDString(descriptor.getRelease()));
- writeListItem("type:" + getBCDString(descriptor.getDescriptorType()));
- writeListItem("descriptor.getNumDescriptors() descriptors len:"
- + descriptor.getDescriptorLen());
- closeList();
- }
-
- private void tsReport(UsbACAudioControlEndpoint descriptor) {
- writeHeader(3, "AC Audio Control Endpoint:" + getHexString(descriptor.getType())
- + " length:" + descriptor.getLength());
- }
-
- private void tsReport(UsbACAudioStreamEndpoint descriptor) {
- writeHeader(3, "AC Audio Streaming Endpoint:"
- + getHexString(descriptor.getType())
- + " length:" + descriptor.getLength());
- }
-
- private void tsReport(UsbACHeader descriptor) {
- tsReport((UsbACInterface) descriptor);
-
- openList();
- writeListItem("spec:" + getBCDString(descriptor.getADCRelease()));
- int numInterfaces = descriptor.getNumInterfaces();
- writeListItem("" + numInterfaces + " interfaces");
- if (numInterfaces > 0) {
- openListItem();
- mStringBuilder.append("[");
- byte[] interfaceNums = descriptor.getInterfaceNums();
- if (numInterfaces != 0 && interfaceNums != null) {
- for (int index = 0; index < numInterfaces; index++) {
- mStringBuilder.append("" + interfaceNums[index]);
- if (index < numInterfaces - 1) {
- mStringBuilder.append(" ");
- }
- }
- }
- mStringBuilder.append("]");
- closeListItem();
- }
- writeListItem("controls:" + getHexString(descriptor.getControls()));
- closeList();
- }
-
- private void tsReport(UsbACFeatureUnit descriptor) {
- tsReport((UsbACInterface) descriptor);
- }
-
- private void tsReport(UsbACInterface descriptor) {
- String subClassName =
- descriptor.getSubclass() == UsbDescriptor.AUDIO_AUDIOCONTROL
- ? "AC Control"
- : "AC Streaming";
- byte subtype = descriptor.getSubtype();
- String subTypeStr = UsbStrings.getACControlInterfaceName(subtype);
- writeHeader(4, subClassName + " - " + getHexString(subtype)
- + ":" + subTypeStr + " len:" + descriptor.getLength());
- }
-
- private void tsReport(UsbACTerminal descriptor) {
- tsReport((UsbACInterface) descriptor);
- }
-
- private void tsReport(UsbACInputTerminal descriptor) {
- tsReport((UsbACTerminal) descriptor);
-
- openList();
- writeListItem("ID:" + getHexString(descriptor.getTerminalID()));
- int terminalType = descriptor.getTerminalType();
- writeListItem("Type:<b>" + getHexString(terminalType) + ":"
- + UsbStrings.getTerminalName(terminalType) + "</b>");
- writeListItem("AssocTerminal:" + getHexString(descriptor.getAssocTerminal()));
- writeListItem("" + descriptor.getNrChannels() + " chans. config:"
- + getHexString(descriptor.getChannelConfig()));
- closeList();
- }
-
- private void tsReport(UsbACOutputTerminal descriptor) {
- tsReport((UsbACTerminal) descriptor);
-
- openList();
- writeListItem("ID:" + getHexString(descriptor.getTerminalID()));
- int terminalType = descriptor.getTerminalType();
- writeListItem("Type:<b>" + getHexString(terminalType) + ":"
- + UsbStrings.getTerminalName(terminalType) + "</b>");
- writeListItem("AssocTerminal:" + getHexString(descriptor.getAssocTerminal()));
- writeListItem("Source:" + getHexString(descriptor.getSourceID()));
- closeList();
- }
-
- private void tsReport(UsbACMidiEndpoint descriptor) {
- writeHeader(3, "AC Midi Endpoint:" + getHexString(descriptor.getType())
- + " length:" + descriptor.getLength());
- openList();
- writeListItem("" + descriptor.getNumJacks() + " jacks.");
- closeList();
- }
-
- private void tsReport(UsbACMixerUnit descriptor) {
- tsReport((UsbACInterface) descriptor);
- openList();
-
- writeListItem("Unit ID:" + getHexString(descriptor.getUnitID()));
- byte numInputs = descriptor.getNumInputs();
- byte[] inputIDs = descriptor.getInputIDs();
- openListItem();
- mStringBuilder.append("Num Inputs:" + numInputs + " [");
- for (int input = 0; input < numInputs; input++) {
- mStringBuilder.append("" + getHexString(inputIDs[input]));
- if (input < numInputs - 1) {
- mStringBuilder.append(" ");
- }
- }
- mStringBuilder.append("]");
- closeListItem();
-
- writeListItem("Num Outputs:" + descriptor.getNumOutputs());
- writeListItem("Chan Config:" + getHexString(descriptor.getChannelConfig()));
-
- byte[] controls = descriptor.getControls();
- openListItem();
- mStringBuilder.append("controls:" + controls.length + " [");
- for (int ctrl = 0; ctrl < controls.length; ctrl++) {
- mStringBuilder.append("" + controls[ctrl]);
- if (ctrl < controls.length - 1) {
- mStringBuilder.append(" ");
- }
- }
- mStringBuilder.append("]");
- closeListItem();
- closeList();
- // byte mChanNameID; // First channel name string descriptor ID
- // byte mNameID; // string descriptor ID of mixer name
- }
-
- private void tsReport(UsbACSelectorUnit descriptor) {
- tsReport((UsbACInterface) descriptor);
- }
-
- private void tsReport(UsbASFormat descriptor) {
- writeHeader(4, "AC Streaming Format "
- + (descriptor.getFormatType() == UsbASFormat.FORMAT_TYPE_I ? "I" : "II")
- + " - " + getHexString(descriptor.getSubtype()) + ":"
- + " len:" + descriptor.getLength());
- }
-
- private void tsReport(UsbASFormatI descriptor) {
- tsReport((UsbASFormat) descriptor);
- openList();
- writeListItem("chans:" + descriptor.getNumChannels());
- writeListItem("subframe size:" + descriptor.getSubframeSize());
- writeListItem("bit resolution:" + descriptor.getBitResolution());
- byte sampleFreqType = descriptor.getSampleFreqType();
- int[] sampleRates = descriptor.getSampleRates();
- writeListItem("sample freq type:" + sampleFreqType);
- if (sampleFreqType == 0) {
- openList();
- writeListItem("min:" + sampleRates[0]);
- writeListItem("max:" + sampleRates[1]);
- closeList();
- } else {
- openList();
- for (int index = 0; index < sampleFreqType; index++) {
- writeListItem("" + sampleRates[index]);
- }
- closeList();
- }
- closeList();
- }
-
- private void tsReport(UsbASFormatII descriptor) {
- tsReport((UsbASFormat) descriptor);
- openList();
- writeListItem("max bit rate:" + descriptor.getMaxBitRate());
- writeListItem("samples per frame:" + descriptor.getMaxBitRate());
- byte sampleFreqType = descriptor.getSamFreqType();
- int[] sampleRates = descriptor.getSampleRates();
- writeListItem("sample freq type:" + sampleFreqType);
- if (sampleFreqType == 0) {
- openList();
- writeListItem("min:" + sampleRates[0]);
- writeListItem("max:" + sampleRates[1]);
- closeList();
- } else {
- openList();
- for (int index = 0; index < sampleFreqType; index++) {
- writeListItem("" + sampleRates[index]);
- }
- closeList();
- }
-
- closeList();
- }
-
- private void tsReport(UsbASGeneral descriptor) {
- tsReport((UsbACInterface) descriptor);
- openList();
- int formatTag = descriptor.getFormatTag();
- writeListItem("fmt:" + UsbStrings.getAudioFormatName(formatTag) + " - "
- + getHexString(formatTag));
- closeList();
- }
-
- private void tsReport(UsbInterfaceAssoc descriptor) {
- tsReport((UsbDescriptor) descriptor);
- }
-
- private void tsReport(UsbMSMidiHeader descriptor) {
- writeHeader(3, "MS Midi Header:" + getHexString(descriptor.getType())
- + " subType:" + getHexString(descriptor.getSubclass())
- + " length:" + descriptor.getSubclass());
- }
-
- private void tsReport(UsbMSMidiInputJack descriptor) {
- writeHeader(3, "MS Midi Input Jack:" + getHexString(descriptor.getType())
- + " subType:" + getHexString(descriptor.getSubclass())
- + " length:" + descriptor.getSubclass());
- }
-
- private void tsReport(UsbMSMidiOutputJack descriptor) {
- writeHeader(3, "MS Midi Output Jack:" + getHexString(descriptor.getType())
- + " subType:" + getHexString(descriptor.getSubclass())
- + " length:" + descriptor.getSubclass());
- }
-
- private void tsReport(UsbUnknown descriptor) {
- writeParagraph("<i><b>Unknown Descriptor " + getHexString(descriptor.getType())
- + " len:" + descriptor.getLength() + "</b></i>");
- dumpHexArray(descriptor.getRawData(), mStringBuilder);
- }
-}
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java b/services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java
new file mode 100644
index 000000000000..9e0adf55d87b
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors.report;
+
+import android.hardware.usb.UsbDeviceConnection;
+
+/**
+ * @hide
+ * Defines a class for generating report data in a variety of potential formats.
+ */
+public abstract class ReportCanvas {
+ private static final String TAG = "ReportCanvas";
+
+ private final UsbDeviceConnection mConnection;
+
+ /**
+ * Constructor.
+ * @param connection The USB connection object used to retrieve strings
+ * from the USB device.
+ */
+ public ReportCanvas(UsbDeviceConnection connection) {
+ mConnection = connection;
+ }
+
+ /**
+ * @returns the UsbDeviceConnection member (mConnection).
+ */
+ public UsbDeviceConnection getConnection() {
+ return mConnection;
+ }
+
+ /**
+ * Writes a plain string to the output.
+ */
+ public abstract void write(String text);
+
+ /**
+ * Opens a "header" formatted section in the output.
+ * @param level Specifies the logical level of the header.
+ */
+ public abstract void openHeader(int level);
+
+ /**
+ * Closes a "header" formatted section in the output.
+ * @param level Specifies the logical level of the header.
+ */
+ public abstract void closeHeader(int level);
+
+ /**
+ * Writes a "header" formatted string to the output.
+ * @param level Specifies the logical level of the header.
+ * @param text Specifies the text to display in the header.
+ */
+ public void writeHeader(int level, String text) {
+ openHeader(level);
+ write(text);
+ closeHeader(level);
+ }
+
+ /**
+ * Opens a paragraph construct in the output.
+ * @param emphasis Specifies whether the text in the paragraph should
+ * be displayed with "emphasis" formatting.
+ */
+ public abstract void openParagraph(boolean emphasis);
+
+ /**
+ * Closes a paragraph construct in the output.
+ */
+ public abstract void closeParagraph();
+
+ /**
+ * Writes a paragraph construct to the output.
+ * @param text The text to display with "paragraph" formatting.
+ * @param emphasis Specifies whether the text in the paragraph should
+ * be displayed with "emphasis" formatting.
+ */
+ public abstract void writeParagraph(String text, boolean emphasis);
+
+ /**
+ * Opens a "list" formatted section in the output.
+ */
+ public abstract void openList();
+
+ /**
+ * Closes a "list" formatted section in the output.
+ */
+ public abstract void closeList();
+
+ /**
+ * Opens a "list item" formatted section in the output.
+ */
+ public abstract void openListItem();
+
+ /**
+ * Closes a "list item" formatted section in the output.
+ */
+ public abstract void closeListItem();
+
+ /**
+ * Writes a "list item" formatted section in the output.
+ * @param text Specifies the text of the list item.
+ */
+ public void writeListItem(String text) {
+ openListItem();
+ write(text);
+ closeListItem();
+ }
+
+ /*
+ * Data Formating Helpers
+ */
+ /**
+ * Generates a hex representation of the specified byte value.
+ * @param value The value to format.
+ */
+ //TODO Look into renaming the "getHexString()" functions to be more
+ // representative of the types they handle.
+ public static String getHexString(byte value) {
+ return "0x" + Integer.toHexString(((int) value) & 0xFF).toUpperCase();
+ }
+
+ /**
+ * Generates a string representing a USB Binary-Coded Decimal value.
+ * @param valueBCD The value to format.
+ */
+ public static String getBCDString(int valueBCD) {
+ int major = (valueBCD >> 8) & 0x0F;
+ int minor = (valueBCD >> 4) & 0x0F;
+ int subminor = valueBCD & 0x0F;
+
+ return "" + major + "." + minor + subminor;
+ }
+
+ /**
+ * Generates a hex representation of the specified 16-bit integer value.
+ * @param value The value to format.
+ */
+ //TODO Look into renaming the "getHexString()" functions to be more
+ // representative of the types they handle.
+ public static String getHexString(int value) {
+ int intValue = value & 0xFFFF;
+ return "0x" + Integer.toHexString(intValue).toUpperCase();
+ }
+
+ /**
+ * Writes out the specified byte array to the provided StringBuilder.
+ * @param rawData The byte values.
+ * @param builder The StringBuilder to write text into.
+ */
+ public void dumpHexArray(byte[] rawData, StringBuilder builder) {
+ if (rawData != null) {
+ // Assume the type and Length and perhaps sub-type have been displayed
+ openParagraph(false);
+ for (int index = 0; index < rawData.length; index++) {
+ builder.append(getHexString(rawData[index]) + " ");
+ }
+ closeParagraph();
+ }
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/Reporter.java b/services/usb/java/com/android/server/usb/descriptors/report/Reporter.java
deleted file mode 100644
index 2944c10796f6..000000000000
--- a/services/usb/java/com/android/server/usb/descriptors/report/Reporter.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.usb.descriptors.report;
-
-import com.android.server.usb.descriptors.UsbDescriptor;
-
-/**
- * Declares the Reporter interface to provide HTML reporting for UsbDescriptor (sub)classes.
- *
- * NOTE: It is the responsibility of the implementor of this interface to correctly
- * interpret/decode the SPECIFIC UsbDescriptor subclass (perhaps with 'instanceof') that is
- * passed and handle that in the appropriate manner. This appears to be a
- * not very object-oriented approach, and that is true. This approach DOES however move the
- * complexity and 'plumbing' of reporting into the Reporter implementation and avoids needing
- * a (trivial) type-specific call to 'report()' in each UsbDescriptor (sub)class, instead
- * having just one in the top-level UsbDescriptor class. It also removes the need to add new
- * type-specific 'report()' methods to be added to Reporter interface whenever a
- * new UsbDescriptor subclass is defined. This seems like a pretty good trade-off.
- *
- * See HTMLReporter.java in this package for an example of type decoding.
- */
-public interface Reporter {
- /**
- * Generate report for this UsbDescriptor descriptor
- */
- void report(UsbDescriptor descriptor);
-}
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/Reporting.java b/services/usb/java/com/android/server/usb/descriptors/report/Reporting.java
index c13111b3e81c..be7c12e4a521 100644
--- a/services/usb/java/com/android/server/usb/descriptors/report/Reporting.java
+++ b/services/usb/java/com/android/server/usb/descriptors/report/Reporting.java
@@ -16,12 +16,16 @@
package com.android.server.usb.descriptors.report;
/**
- * Declares the interface for classes that provide reporting functionality.
- * (This is the double-indirection aspect of the "Visitor" pattern.
+ * @hide
*/
public interface Reporting {
/**
- * Declares the report method that UsbDescriptor subclasses call.
+ * TBD
*/
- void report(Reporter reporter);
+ void report(ReportCanvas canvas);
+
+ /**
+ * TBD
+ */
+ void shortReport(ReportCanvas canvas);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java b/services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java
new file mode 100644
index 000000000000..33746ba82bc6
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors.report;
+
+import android.hardware.usb.UsbDeviceConnection;
+
+/**
+ * @hide
+ * A concrete implementation of ReportCanvas class which generates "Plain Text" output.
+ */
+public final class TextReportCanvas extends ReportCanvas {
+ private static final String TAG = "TextReportCanvas";
+
+ private final StringBuilder mStringBuilder;
+ private int mListIndent;
+ private static final int LIST_INDENT_AMNT = 2;
+
+ /**
+ * Constructor. Connects plain-text output to the provided StringBuilder.
+ * @param connection The USB connection object used to retrieve strings
+ * from the USB device.
+ * @param stringBuilder Generated output gets written into this object.
+ */
+ public TextReportCanvas(UsbDeviceConnection connection, StringBuilder stringBuilder) {
+ super(connection);
+
+ mStringBuilder = stringBuilder;
+ }
+
+ @Override
+ public void write(String text) {
+ mStringBuilder.append(text);
+ }
+
+ @Override
+ public void openHeader(int level) {
+ mStringBuilder.append("[" + level + " - ");
+ }
+
+ @Override
+ public void closeHeader(int level) {
+ mStringBuilder.append("]\n");
+ }
+
+ @Override
+ public void openParagraph(boolean inRed) {
+ }
+
+ @Override
+ public void closeParagraph() {
+ mStringBuilder.append("\n");
+ }
+
+ @Override
+ public void writeParagraph(String text, boolean inRed) {
+ openParagraph(inRed);
+ if (inRed) {
+ mStringBuilder.append("*" + text + "*");
+ } else {
+ mStringBuilder.append(text);
+ }
+ closeParagraph();
+ }
+
+ private void writeListIndent() {
+ for (int space = 0; space < mListIndent; space++) {
+ mStringBuilder.append(" ");
+ }
+ }
+
+ @Override
+ public void openList() {
+ mListIndent += LIST_INDENT_AMNT;
+ writeListIndent();
+ mStringBuilder.append("---->\n");
+ }
+
+ @Override
+ public void closeList() {
+ writeListIndent();
+ mListIndent -= LIST_INDENT_AMNT;
+ mStringBuilder.append("<----\n");
+ }
+
+ @Override
+ public void openListItem() {
+ writeListIndent();
+ mStringBuilder.append(" - ");
+ }
+
+ @Override
+ public void closeListItem() {
+ mStringBuilder.append("\n");
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/UsbStrings.java b/services/usb/java/com/android/server/usb/descriptors/report/UsbStrings.java
index 0461150abd27..ff58a2672b3f 100644
--- a/services/usb/java/com/android/server/usb/descriptors/report/UsbStrings.java
+++ b/services/usb/java/com/android/server/usb/descriptors/report/UsbStrings.java
@@ -16,6 +16,7 @@
package com.android.server.usb.descriptors.report;
import com.android.server.usb.descriptors.UsbACInterface;
+import com.android.server.usb.descriptors.UsbASFormat;
import com.android.server.usb.descriptors.UsbDescriptor;
import com.android.server.usb.descriptors.UsbTerminalTypes;
@@ -25,7 +26,7 @@ import java.util.HashMap;
* @hide
* A class to provide human-readable strings for various USB constants.
*/
-public class UsbStrings {
+public final class UsbStrings {
private static final String TAG = "UsbStrings";
private static HashMap<Byte, String> sDescriptorNames;
@@ -35,6 +36,7 @@ public class UsbStrings {
private static HashMap<Byte, String> sAudioSubclassNames;
private static HashMap<Integer, String> sAudioEncodingNames;
private static HashMap<Integer, String> sTerminalNames;
+ private static HashMap<Integer, String> sFormatNames;
private static void initDescriptorNames() {
sDescriptorNames = new HashMap<Byte, String>();
@@ -70,6 +72,11 @@ public class UsbStrings {
sACControlInterfaceNames.put(UsbACInterface.ACI_FEATURE_UNIT, "Feature Unit");
sACControlInterfaceNames.put(UsbACInterface.ACI_PROCESSING_UNIT, "Processing Unit");
sACControlInterfaceNames.put(UsbACInterface.ACI_EXTENSION_UNIT, "Extension Unit");
+ sACControlInterfaceNames.put(UsbACInterface.ACI_CLOCK_SOURCE, "Clock Source");
+ sACControlInterfaceNames.put(UsbACInterface.ACI_CLOCK_SELECTOR, "Clock Selector");
+ sACControlInterfaceNames.put(UsbACInterface.ACI_CLOCK_MULTIPLIER, "Clock Multiplier");
+ sACControlInterfaceNames.put(UsbACInterface.ACI_SAMPLE_RATE_CONVERTER,
+ "Sample Rate Converter");
}
private static void initACStreamingInterfaceNames() {
@@ -213,6 +220,29 @@ public class UsbStrings {
? name
: "Unknown Terminal Type 0x" + Integer.toHexString(terminalType);
}
+
+ private static void initFormatNames() {
+ sFormatNames = new HashMap<Integer, String>();
+
+ sFormatNames.put((int) UsbASFormat.FORMAT_TYPE_I, "FORMAT_TYPE_I");
+ sFormatNames.put((int) UsbASFormat.FORMAT_TYPE_II, "FORMAT_TYPE_II");
+ sFormatNames.put((int) UsbASFormat.FORMAT_TYPE_III, "FORMAT_TYPE_III");
+ sFormatNames.put((int) UsbASFormat.FORMAT_TYPE_IV, "FORMAT_TYPE_IV");
+ sFormatNames.put((int) UsbASFormat.EXT_FORMAT_TYPE_I, "EXT_FORMAT_TYPE_I");
+ sFormatNames.put((int) UsbASFormat.EXT_FORMAT_TYPE_II, "EXT_FORMAT_TYPE_II");
+ sFormatNames.put((int) UsbASFormat.EXT_FORMAT_TYPE_III, "EXT_FORMAT_TYPE_III");
+ }
+
+ /**
+ * Retrieves the name for the specified format (encoding) type ID.
+ */
+ public static String getFormatName(int format) {
+ String name = sFormatNames.get(format);
+ return name != null
+ ? name
+ : "Unknown Format Type 0x" + Integer.toHexString(format);
+ }
+
/**
* Initializes string tables.
*/
@@ -224,10 +254,11 @@ public class UsbStrings {
initAudioSubclassNames();
initAudioEncodingNames();
initTerminalNames();
+ initFormatNames();
}
/**
- * Initializes string tables.
+ * Deinitializes string tables.
*/
public static void releaseUsbStrings() {
sDescriptorNames = null;
@@ -309,4 +340,11 @@ public class UsbStrings {
: "Unknown Format (encoding) ID [0x" + Integer.toHexString(formatID) + ":"
+ formatID + "]";
}
+
+ /**
+ * Retrieves the name for the specified USB audio interface subclass ID.
+ */
+ public static String getACInterfaceSubclassName(byte subClassID) {
+ return subClassID == UsbDescriptor.AUDIO_AUDIOCONTROL ? "AC Control" : "AC Streaming";
+ }
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsACInterfaceNode.java b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsACInterfaceNode.java
new file mode 100644
index 000000000000..49caca5c8dd0
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsACInterfaceNode.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors.tree;
+
+import com.android.server.usb.descriptors.UsbACInterface;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
+/**
+ * @hide
+ * A tree node containing some sort-of Audio Class Descriptor.
+ */
+public final class UsbDescriptorsACInterfaceNode extends UsbDescriptorsTreeNode {
+ private static final String TAG = "UsbDescriptorsACInterfaceNode";
+
+ private final UsbACInterface mACInterface;
+
+ /**
+ * Constructor.
+ * @param acInterface The Audio Class Inteface object wrapped by this tree node.
+ */
+ public UsbDescriptorsACInterfaceNode(UsbACInterface acInterface) {
+ mACInterface = acInterface;
+ }
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ canvas.openListItem();
+ canvas.writeParagraph("AC Interface type:0x"
+ + Integer.toHexString(mACInterface.getSubtype()), false);
+ mACInterface.report(canvas);
+ canvas.closeListItem();
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsConfigNode.java b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsConfigNode.java
new file mode 100644
index 000000000000..64f9496ae7c8
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsConfigNode.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors.tree;
+
+import com.android.server.usb.descriptors.UsbConfigDescriptor;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
+import java.util.ArrayList;
+
+/**
+ * @hide
+ * Represents a configuration in the descriptors tree.
+ */
+public final class UsbDescriptorsConfigNode extends UsbDescriptorsTreeNode {
+ private static final String TAG = "UsbDescriptorsConfigNode";
+
+ private final UsbConfigDescriptor mConfigDescriptor;
+
+ private final ArrayList<UsbDescriptorsInterfaceNode> mInterfaceNodes = new ArrayList<>();
+
+ /**
+ * Constructor.
+ * @param configDescriptor The Config Descriptor object wrapped by this tree node.
+ */
+ public UsbDescriptorsConfigNode(UsbConfigDescriptor configDescriptor) {
+ mConfigDescriptor = configDescriptor;
+ }
+
+ /**
+ * Adds the inteface node logical contained in this configuration.
+ * @param interfaceNode The inteface treenode to assocate with this configuration.
+ */
+ public void addInterfaceNode(UsbDescriptorsInterfaceNode interfaceNode) {
+ mInterfaceNodes.add(interfaceNode);
+ }
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ mConfigDescriptor.report(canvas);
+
+ canvas.openList();
+
+ // Interfaces
+ for (UsbDescriptorsInterfaceNode node : mInterfaceNodes) {
+ node.report(canvas);
+ }
+
+ canvas.closeList();
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsDeviceNode.java b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsDeviceNode.java
new file mode 100644
index 000000000000..898a06ecdafc
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsDeviceNode.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors.tree;
+
+import com.android.server.usb.descriptors.UsbDeviceDescriptor;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
+import java.util.ArrayList;
+
+/**
+ * @hide
+ * A class to contain THE device descriptor at the root of the tree.
+ */
+public final class UsbDescriptorsDeviceNode extends UsbDescriptorsTreeNode {
+ private static final String TAG = "UsbDescriptorsDeviceNode";
+
+ private final UsbDeviceDescriptor mDeviceDescriptor;
+
+ private final ArrayList<UsbDescriptorsConfigNode> mConfigNodes = new ArrayList<>();
+
+ /**
+ * Constructor.
+ * @param deviceDescriptor The Device Descriptor object wrapped by this tree node.
+ */
+ public UsbDescriptorsDeviceNode(UsbDeviceDescriptor deviceDescriptor) {
+ mDeviceDescriptor = deviceDescriptor;
+ }
+
+ /**
+ * Adds a Configuration node to the assocated device node.
+ */
+ public void addConfigDescriptorNode(UsbDescriptorsConfigNode configNode) {
+ mConfigNodes.add(configNode);
+ }
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ mDeviceDescriptor.report(canvas);
+ for (UsbDescriptorsConfigNode node : mConfigNodes) {
+ node.report(canvas);
+ }
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsEndpointNode.java b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsEndpointNode.java
new file mode 100644
index 000000000000..72864172147e
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsEndpointNode.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors.tree;
+
+import com.android.server.usb.descriptors.UsbEndpointDescriptor;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
+/**
+ * @hide
+ * Represents an endpoint in the descriptors tree.
+ */
+public final class UsbDescriptorsEndpointNode extends UsbDescriptorsTreeNode {
+ private static final String TAG = "UsbDescriptorsEndpointNode";
+
+ private final UsbEndpointDescriptor mEndpointDescriptor;
+
+ /**
+ * Constructor.
+ * @param endpointDescriptor The Device Descriptor object wrapped by this tree node.
+ */
+ public UsbDescriptorsEndpointNode(UsbEndpointDescriptor endpointDescriptor) {
+ mEndpointDescriptor = endpointDescriptor;
+ }
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ mEndpointDescriptor.report(canvas);
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsInterfaceNode.java b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsInterfaceNode.java
new file mode 100644
index 000000000000..d49d88db9882
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsInterfaceNode.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors.tree;
+
+import com.android.server.usb.descriptors.UsbInterfaceDescriptor;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
+import java.util.ArrayList;
+
+/**
+ * @hide
+ * Represents an interface in the descriptors tree.
+ */
+public final class UsbDescriptorsInterfaceNode extends UsbDescriptorsTreeNode {
+ private static final String TAG = "UsbDescriptorsInterfaceNode";
+
+ private final UsbInterfaceDescriptor mInterfaceDescriptor;
+
+ private final ArrayList<UsbDescriptorsEndpointNode> mEndpointNodes = new ArrayList<>();
+ private final ArrayList<UsbDescriptorsACInterfaceNode> mACInterfaceNodes = new ArrayList<>();
+
+ /**
+ * Constructor.
+ * @param interfaceDescriptor The Interface Descriptor object wrapped by this tree node.
+ */
+ public UsbDescriptorsInterfaceNode(UsbInterfaceDescriptor interfaceDescriptor) {
+ mInterfaceDescriptor = interfaceDescriptor;
+ }
+
+ /**
+ * Adds an endpoint descriptor as a child of this interface node.
+ * @param endpointNode The endpoint descriptor node to add to this interface node.
+ */
+ public void addEndpointNode(UsbDescriptorsEndpointNode endpointNode) {
+ mEndpointNodes.add(endpointNode);
+ }
+
+ /**
+ * Adds an Audio-class interface descriptor as a child of this interface node.
+ * @param acInterfaceNode The audio-class descriptor node to add to this interface node.
+ */
+ public void addACInterfaceNode(UsbDescriptorsACInterfaceNode acInterfaceNode) {
+ mACInterfaceNodes.add(acInterfaceNode);
+ }
+
+ @Override
+ public void report(ReportCanvas canvas) {
+ mInterfaceDescriptor.report(canvas);
+
+ // Audio Class Interfaces
+ if (mACInterfaceNodes.size() > 0) {
+ canvas.writeParagraph("Audio Class Interfaces", false);
+ canvas.openList();
+ for (UsbDescriptorsACInterfaceNode node : mACInterfaceNodes) {
+ node.report(canvas);
+ }
+ canvas.closeList();
+ }
+
+ // Endpoints
+ if (mEndpointNodes.size() > 0) {
+ canvas.writeParagraph("Endpoints", false);
+ canvas.openList();
+ for (UsbDescriptorsEndpointNode node : mEndpointNodes) {
+ node.report(canvas);
+ }
+ canvas.closeList();
+ }
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsTree.java b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsTree.java
new file mode 100644
index 000000000000..1aa30fa94f42
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsTree.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors.tree;
+
+import com.android.server.usb.descriptors.UsbACInterface;
+import com.android.server.usb.descriptors.UsbConfigDescriptor;
+import com.android.server.usb.descriptors.UsbDescriptor;
+import com.android.server.usb.descriptors.UsbDescriptorParser;
+import com.android.server.usb.descriptors.UsbDeviceDescriptor;
+import com.android.server.usb.descriptors.UsbEndpointDescriptor;
+import com.android.server.usb.descriptors.UsbInterfaceDescriptor;
+import com.android.server.usb.descriptors.report.ReportCanvas;
+
+import java.util.ArrayList;
+
+/*
+ * The general layout of the tree looks like this, though no guarentee about
+ * ordering of descriptors beyond the Device -> Config -> Interface.
+ *
+ * Device Descriptor
+ * +- Config Descriptor
+ * +- Interface Descriptor
+ * | +- Audio Class Interface
+ * | +- Audio Class Interface
+ * | +- Audio Class Interface
+ * | +- Endpoint Descriptor
+ * | +- Endpoint Descriptor
+ * +- Interface Descriptor
+ * +- Endpoint Descriptor
+ */
+/**
+ * @hide
+ *
+ * A class which builds a tree representation from the results of a (linear)
+ * parse of USB descriptors.
+ *
+ * @see {@link com.android.server.usb.descriptors.UsbDescriptorsParser UsbDescriptorsParser}
+ */
+public final class UsbDescriptorsTree {
+ private static final String TAG = "UsbDescriptorsTree";
+
+ private UsbDescriptorsDeviceNode mDeviceNode;
+ private UsbDescriptorsConfigNode mConfigNode; // being parsed
+ private UsbDescriptorsInterfaceNode mInterfaceNode; // being parsed
+
+ /**
+ * Adds THE device descriptor as the root of the tree.
+ */
+ private void addDeviceDescriptor(UsbDeviceDescriptor deviceDescriptor) {
+ mDeviceNode = new UsbDescriptorsDeviceNode(deviceDescriptor);
+ }
+
+ /**
+ * Adds A config descriptor to the tree.
+ */
+ private void addConfigDescriptor(UsbConfigDescriptor configDescriptor) {
+ mConfigNode = new UsbDescriptorsConfigNode(configDescriptor);
+ mDeviceNode.addConfigDescriptorNode(mConfigNode);
+ }
+
+ /**
+ * Adds AN interface descriptor to the current configuration in the tree.
+ */
+ private void addInterfaceDescriptor(UsbInterfaceDescriptor interfaceDescriptor) {
+ mInterfaceNode = new UsbDescriptorsInterfaceNode(interfaceDescriptor);
+ mConfigNode.addInterfaceNode(mInterfaceNode);
+ }
+
+ /**
+ * Adds an endpoint descriptor to the current interface in the tree.
+ */
+ private void addEndpointDescriptor(UsbEndpointDescriptor endpointDescriptor) {
+ mInterfaceNode.addEndpointNode(new UsbDescriptorsEndpointNode(endpointDescriptor));
+ }
+
+ /**
+ * Adds an audio-class interface descriptor to the current interface in the tree.
+ */
+ private void addACInterface(UsbACInterface acInterface) {
+ mInterfaceNode.addACInterfaceNode(new UsbDescriptorsACInterfaceNode(acInterface));
+ }
+
+ /**
+ * Parses the linear descriptor list contained in the parser argument, into a tree
+ * representation corresponding to the logical structure of the USB descriptors.
+ */
+ public void parse(UsbDescriptorParser parser) {
+
+ ArrayList<UsbDescriptor> descriptors = parser.getDescriptors();
+
+ for (int descrIndex = 0; descrIndex < descriptors.size(); descrIndex++) {
+ UsbDescriptor descriptor = descriptors.get(descrIndex);
+ switch (descriptor.getType()) {
+ //
+ // Basic Descriptors
+ //
+ case UsbDescriptor.DESCRIPTORTYPE_DEVICE:
+ addDeviceDescriptor((UsbDeviceDescriptor) descriptor);
+ break;
+
+ case UsbDescriptor.DESCRIPTORTYPE_CONFIG:
+ addConfigDescriptor((UsbConfigDescriptor) descriptor);
+ break;
+
+ case UsbDescriptor.DESCRIPTORTYPE_INTERFACE:
+ addInterfaceDescriptor((UsbInterfaceDescriptor) descriptor);
+ break;
+
+ case UsbDescriptor.DESCRIPTORTYPE_ENDPOINT:
+ addEndpointDescriptor((UsbEndpointDescriptor) descriptor);
+ break;
+
+ //
+ // Audio Class Descriptors
+ //
+ case UsbDescriptor.DESCRIPTORTYPE_AUDIO_INTERFACE:
+ addACInterface((UsbACInterface) descriptor);
+ break;
+
+ case UsbDescriptor.DESCRIPTORTYPE_AUDIO_ENDPOINT:
+ break;
+ }
+ }
+ }
+
+ /**
+ * Generate a report of the descriptors tree.
+ */
+ public void report(ReportCanvas canvas) {
+ mDeviceNode.report(canvas);
+ }
+}
diff --git a/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsTreeNode.java b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsTreeNode.java
new file mode 100644
index 000000000000..aca3cd907372
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/descriptors/tree/UsbDescriptorsTreeNode.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.usb.descriptors.tree;
+
+import com.android.server.usb.descriptors.report.ReportCanvas;
+import com.android.server.usb.descriptors.report.Reporting;
+
+/**
+ * @hide
+ * A shared super class for UsbDescriptor tree nodes.
+ */
+public class UsbDescriptorsTreeNode implements Reporting {
+ private static final String TAG = "UsbDescriptorsTreeNode";
+
+ /**
+ * Implements generate a comprehehensive report of descriptor.
+ */
+ @Override
+ public void report(ReportCanvas canvas) {
+ }
+
+ /**
+ * Implements generate an abreviated report of descriptor.
+ */
+ @Override
+ public void shortReport(ReportCanvas canvas) {
+ }
+}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 4ffacfd7056a..1569ac32128b 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -183,7 +183,7 @@ public class VoiceInteractionManagerService extends SystemService {
private final boolean mEnableService;
VoiceInteractionManagerServiceStub() {
- mEnableService = shouldEnableService(mContext.getResources());
+ mEnableService = shouldEnableService(mContext);
}
// TODO: VI Make sure the caller is the current user or profile
@@ -348,10 +348,15 @@ public class VoiceInteractionManagerService extends SystemService {
}
}
- private boolean shouldEnableService(Resources res) {
- // VoiceInteractionService should not be enabled on low ram devices unless it has the config flag.
- return !ActivityManager.isLowRamDeviceStatic() ||
- getForceVoiceInteractionServicePackage(res) != null;
+ private boolean shouldEnableService(Context context) {
+ // VoiceInteractionService should not be enabled on any low RAM devices
+ // or devices that have not declared the recognition feature, unless the
+ // device's configuration has explicitly set the config flag for a fixed
+ // voice interaction service.
+ return (!ActivityManager.isLowRamDeviceStatic()
+ && context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_VOICE_RECOGNIZERS)) ||
+ getForceVoiceInteractionServicePackage(context.getResources()) != null;
}
private String getForceVoiceInteractionServicePackage(Resources res) {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 735f09b57efb..8e4f48772b9b 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -346,14 +346,29 @@ public class CarrierConfigManager {
public static final String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string";
/**
- * Flag indicating whether we should downgrade/terminate VT calls and disable VT when
- * data enabled changed (e.g. reach data limit or turn off data).
+ * When {@code true}, changes to the mobile data enabled switch will not cause the VT
+ * registration state to change. That is, turning on or off mobile data will not cause VT to be
+ * enabled or disabled.
+ * When {@code false}, disabling mobile data will cause VT to be de-registered.
+ * <p>
+ * See also {@link #KEY_VILTE_DATA_IS_METERED_BOOL}.
* @hide
*/
public static final String KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS =
"ignore_data_enabled_changed_for_video_calls";
/**
+ * Flag indicating whether data used for a video call over LTE is metered or not.
+ * <p>
+ * When {@code true}, if the device hits the data limit or data is disabled during a ViLTE call,
+ * the call will be downgraded to audio-only (or paused if
+ * {@link #KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL} is {@code true}).
+ *
+ * @hide
+ */
+ public static final String KEY_VILTE_DATA_IS_METERED_BOOL = "vilte_data_is_metered_bool";
+
+ /**
* Flag specifying whether WFC over IMS should be available for carrier: independent of
* carrier provisioning. If false: hard disabled. If true: then depends on carrier
* provisioning, availability etc.
@@ -825,8 +840,6 @@ public class CarrierConfigManager {
* If user has explicitly disabled some packages in the list, won't re-enable.
* Other carrier specific apps which are not in this list may be disabled for current carrier,
* and only be re-enabled when this config for another carrier includes it.
- *
- * @hide
*/
public static final String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array";
@@ -1569,7 +1582,8 @@ public class CarrierConfigManager {
sDefaults.putBoolean(KEY_NOTIFY_HANDOVER_VIDEO_FROM_WIFI_TO_LTE_BOOL, false);
sDefaults.putBoolean(KEY_SUPPORT_DOWNGRADE_VT_TO_AUDIO_BOOL, true);
sDefaults.putString(KEY_DEFAULT_VM_NUMBER_STRING, "");
- sDefaults.putBoolean(KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS, false);
+ sDefaults.putBoolean(KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS, true);
+ sDefaults.putBoolean(KEY_VILTE_DATA_IS_METERED_BOOL, true);
sDefaults.putBoolean(KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL, false);
diff --git a/telephony/java/com/android/ims/ImsConferenceState.java b/telephony/java/com/android/ims/ImsConferenceState.java
index c57ef98abb4d..0afde88b8918 100644
--- a/telephony/java/com/android/ims/ImsConferenceState.java
+++ b/telephony/java/com/android/ims/ImsConferenceState.java
@@ -79,6 +79,8 @@ public class ImsConferenceState implements Parcelable {
public static final String STATUS_DISCONNECTED = "disconnected";
public static final String STATUS_MUTED_VIA_FOCUS = "muted-via-focus";
public static final String STATUS_CONNECT_FAIL = "connect-fail";
+ public static final String STATUS_SEND_ONLY = "sendonly";
+ public static final String STATUS_SEND_RECV = "sendrecv";
/**
* conference-info : SIP status code (integer)
@@ -156,15 +158,53 @@ public class ImsConferenceState implements Parcelable {
} else if (status.equals(STATUS_ALERTING) ||
status.equals(STATUS_DIALING_OUT)) {
return Connection.STATE_DIALING;
- } else if (status.equals(STATUS_ON_HOLD)) {
+ } else if (status.equals(STATUS_ON_HOLD) ||
+ status.equals(STATUS_SEND_ONLY)) {
return Connection.STATE_HOLDING;
} else if (status.equals(STATUS_CONNECTED) ||
status.equals(STATUS_MUTED_VIA_FOCUS) ||
- status.equals(STATUS_DISCONNECTING)) {
+ status.equals(STATUS_DISCONNECTING) ||
+ status.equals(STATUS_SEND_RECV)) {
return Connection.STATE_ACTIVE;
} else if (status.equals(STATUS_DISCONNECTED)) {
return Connection.STATE_DISCONNECTED;
}
return Call.STATE_ACTIVE;
}
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ sb.append(ImsConferenceState.class.getSimpleName());
+ sb.append(" ");
+ if (mParticipants.size() > 0) {
+ Set<Entry<String, Bundle>> entries = mParticipants.entrySet();
+
+ if (entries != null) {
+ Iterator<Entry<String, Bundle>> iterator = entries.iterator();
+ sb.append("<");
+ while (iterator.hasNext()) {
+ Entry<String, Bundle> entry = iterator.next();
+ sb.append(entry.getKey());
+ sb.append(": ");
+ Bundle participantData = entry.getValue();
+
+ for (String key : participantData.keySet()) {
+ sb.append(key);
+ sb.append("=");
+ if (ENDPOINT.equals(key) || USER.equals(key)) {
+ sb.append(android.telecom.Log.pii(participantData.get(key)));
+ } else {
+ sb.append(participantData.get(key));
+ }
+ sb.append(", ");
+ }
+ }
+ sb.append(">");
+ }
+ }
+ sb.append("]");
+ return sb.toString();
+ }
}
diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java
index e7b22bdfadcc..cf4c47bf541f 100644
--- a/telephony/java/com/android/ims/ImsConfig.java
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -524,6 +524,7 @@ public class ImsConfig {
* Defines IMS feature value.
*/
public static class FeatureValueConstants {
+ public static final int ERROR = -1;
public static final int OFF = 0;
public static final int ON = 1;
}
diff --git a/telephony/java/com/android/internal/telephony/ExponentialBackoff.java b/telephony/java/com/android/internal/telephony/ExponentialBackoff.java
new file mode 100644
index 000000000000..80958c077d6a
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ExponentialBackoff.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.annotation.NonNull;
+import android.os.Handler;
+import android.os.Looper;
+
+/** The implementation of exponential backoff with jitter applied. */
+public class ExponentialBackoff {
+ private int mRetryCounter;
+ private long mStartDelayMs;
+ private long mMaximumDelayMs;
+ private long mCurrentDelayMs;
+ private int mMultiplier;
+ private Runnable mRunnable;
+ private Handler mHandler;
+
+ public ExponentialBackoff(
+ long initialDelayMs,
+ long maximumDelayMs,
+ int multiplier,
+ @NonNull Looper looper,
+ @NonNull Runnable runnable) {
+ this(initialDelayMs, maximumDelayMs, multiplier, new Handler(looper), runnable);
+ }
+
+ public ExponentialBackoff(
+ long initialDelayMs,
+ long maximumDelayMs,
+ int multiplier,
+ @NonNull Handler handler,
+ @NonNull Runnable runnable) {
+ mRetryCounter = 0;
+ mStartDelayMs = initialDelayMs;
+ mMaximumDelayMs = maximumDelayMs;
+ mMultiplier = multiplier;
+ mHandler = handler;
+ mRunnable = runnable;
+ }
+
+ /** Starts the backoff, the runnable will be executed after {@link #mStartDelayMs}. */
+ public void start() {
+ mRetryCounter = 0;
+ mCurrentDelayMs = mStartDelayMs;
+ mHandler.removeCallbacks(mRunnable);
+ mHandler.postDelayed(mRunnable, mCurrentDelayMs);
+ }
+
+ /** Stops the backoff, all pending messages will be removed from the message queue. */
+ public void stop() {
+ mRetryCounter = 0;
+ mHandler.removeCallbacks(mRunnable);
+ }
+
+ /** Should call when the retry action has failed and we want to retry after a longer delay. */
+ public void notifyFailed() {
+ mRetryCounter++;
+ long temp = Math.min(
+ mMaximumDelayMs, (long) (mStartDelayMs * Math.pow(mMultiplier, mRetryCounter)));
+ mCurrentDelayMs = (long) (((1 + Math.random()) / 2) * temp);
+ mHandler.removeCallbacks(mRunnable);
+ mHandler.postDelayed(mRunnable, mCurrentDelayMs);
+ }
+
+ /** Returns the delay for the most recently posted message. */
+ public long getCurrentDelay() {
+ return mCurrentDelayMs;
+ }
+}
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
index ceb3993e1705..0f4960887a33 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
@@ -117,46 +117,6 @@ public class ActivityTestMain extends Activity {
}
}
- private void addThumbnail(LinearLayout container, Bitmap bm,
- final ActivityManager.RecentTaskInfo task,
- final ActivityManager.TaskThumbnail thumbs) {
- ImageView iv = new ImageView(this);
- if (bm != null) {
- iv.setImageBitmap(bm);
- }
- iv.setBackgroundResource(android.R.drawable.gallery_thumb);
- int w = getResources().getDimensionPixelSize(android.R.dimen.thumbnail_width);
- int h = getResources().getDimensionPixelSize(android.R.dimen.thumbnail_height);
- container.addView(iv, new LinearLayout.LayoutParams(w, h));
-
- iv.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (task.id >= 0 && thumbs != null) {
- mAm.moveTaskToFront(task.id, ActivityManager.MOVE_TASK_WITH_HOME);
- } else {
- try {
- startActivity(task.baseIntent);
- } catch (ActivityNotFoundException e) {
- Log.w("foo", "Unable to start task: " + e);
- }
- }
- buildUi();
- }
- });
- iv.setOnLongClickListener(new View.OnLongClickListener() {
- @Override
- public boolean onLongClick(View v) {
- if (task.id >= 0 && thumbs != null) {
- mAm.removeTask(task.id);
- buildUi();
- return true;
- }
- return false;
- }
- });
- }
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -600,7 +560,6 @@ public class ActivityTestMain extends Activity {
if (recents != null) {
for (int i=0; i<recents.size(); i++) {
ActivityManager.RecentTaskInfo r = recents.get(i);
- ActivityManager.TaskThumbnail tt = mAm.getTaskThumbnail(r.persistentId);
TextView tv = new TextView(this);
tv.setText(r.baseIntent.getComponent().flattenToShortString());
top.addView(tv, new LinearLayout.LayoutParams(
@@ -608,7 +567,6 @@ public class ActivityTestMain extends Activity {
LinearLayout.LayoutParams.WRAP_CONTENT));
LinearLayout item = new LinearLayout(this);
item.setOrientation(LinearLayout.HORIZONTAL);
- addThumbnail(item, tt != null ? tt.mainThumbnail : null, r, tt);
top.addView(item, new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
diff --git a/tests/net/java/android/net/NetworkStatsHistoryTest.java b/tests/net/java/android/net/NetworkStatsHistoryTest.java
index e7b91b568d74..1c0c14eac08b 100644
--- a/tests/net/java/android/net/NetworkStatsHistoryTest.java
+++ b/tests/net/java/android/net/NetworkStatsHistoryTest.java
@@ -485,6 +485,21 @@ public class NetworkStatsHistoryTest extends AndroidTestCase {
assertTrue(stats.intersects(Long.MIN_VALUE, TEST_START + 1));
}
+ public void testSetValues() throws Exception {
+ stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
+ stats.recordData(TEST_START, TEST_START + 1,
+ new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L));
+
+ assertEquals(1024L + 2048L, stats.getTotalBytes());
+
+ final NetworkStatsHistory.Entry entry = stats.getValues(0, null);
+ entry.rxBytes /= 2;
+ entry.txBytes *= 2;
+ stats.setValues(0, entry);
+
+ assertEquals(512L + 4096L, stats.getTotalBytes());
+ }
+
private static void assertIndexBeforeAfter(
NetworkStatsHistory stats, int before, int after, long time) {
assertEquals("unexpected before", before, stats.getIndexBefore(time));
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
index 2a32b73d56da..0c2ad38a11fe 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
@@ -17,26 +17,35 @@
package com.android.server.net;
import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.NetworkStats.SET_ALL;
import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
+import static android.net.NetworkStatsHistory.FIELD_ALL;
import static android.net.NetworkTemplate.buildTemplateMobileAll;
+import static android.os.Process.myUid;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import android.content.res.Resources;
import android.net.NetworkIdentity;
import android.net.NetworkStats;
+import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.os.Process;
import android.os.UserHandle;
+import android.telephony.SubscriptionPlan;
import android.telephony.TelephonyManager;
-import android.support.test.filters.SmallTest;
import android.test.AndroidTestCase;
import android.test.MoreAsserts;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.format.DateUtils;
import com.android.frameworks.tests.net.R;
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
@@ -44,9 +53,9 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
-
-import libcore.io.IoUtils;
-import libcore.io.Streams;
+import java.time.ZonedDateTime;
+import java.util.ArrayList;
+import java.util.List;
/**
* Tests for {@link NetworkStatsCollection}.
@@ -57,6 +66,10 @@ public class NetworkStatsCollectionTest extends AndroidTestCase {
private static final String TEST_FILE = "test.bin";
private static final String TEST_IMSI = "310260000000000";
+ private static final long TIME_A = 1326088800000L; // UTC: Monday 9th January 2012 06:00:00 AM
+ private static final long TIME_B = 1326110400000L; // UTC: Monday 9th January 2012 12:00:00 PM
+ private static final long TIME_C = 1326132000000L; // UTC: Monday 9th January 2012 06:00:00 PM
+
@Override
public void setUp() throws Exception {
super.setUp();
@@ -198,11 +211,11 @@ public class NetworkStatsCollectionTest extends AndroidTestCase {
collection.getRelevantUids(NetworkStatsAccess.Level.DEVICE));
// Verify security check in getHistory.
- assertNotNull(collection.getHistory(buildTemplateMobileAll(TEST_IMSI), myUid, SET_DEFAULT,
- TAG_NONE, 0, NetworkStatsAccess.Level.DEFAULT));
+ assertNotNull(collection.getHistory(buildTemplateMobileAll(TEST_IMSI), null, myUid, SET_DEFAULT,
+ TAG_NONE, 0, 0L, 0L, NetworkStatsAccess.Level.DEFAULT, myUid));
try {
- collection.getHistory(buildTemplateMobileAll(TEST_IMSI), otherUidInSameUser,
- SET_DEFAULT, TAG_NONE, 0, NetworkStatsAccess.Level.DEFAULT);
+ collection.getHistory(buildTemplateMobileAll(TEST_IMSI), null, otherUidInSameUser,
+ SET_DEFAULT, TAG_NONE, 0, 0L, 0L, NetworkStatsAccess.Level.DEFAULT, myUid);
fail("Should have thrown SecurityException for accessing different UID");
} catch (SecurityException e) {
// expected
@@ -217,6 +230,213 @@ public class NetworkStatsCollectionTest extends AndroidTestCase {
0, NetworkStatsAccess.Level.DEVICE);
}
+ public void testAugmentPlan() throws Exception {
+ final File testFile = new File(getContext().getFilesDir(), TEST_FILE);
+ stageFile(R.raw.netstats_v1, testFile);
+
+ final NetworkStatsCollection emptyCollection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
+ final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
+ collection.readLegacyNetwork(testFile);
+
+ // Test a bunch of plans that should result in no augmentation
+ final List<SubscriptionPlan> plans = new ArrayList<>();
+
+ // No plan
+ plans.add(null);
+ // No usage anchor
+ plans.add(SubscriptionPlan.Builder
+ .createRecurringMonthly(ZonedDateTime.parse("2011-01-14T00:00:00.00Z")).build());
+ // Usage anchor far in past
+ plans.add(SubscriptionPlan.Builder
+ .createRecurringMonthly(ZonedDateTime.parse("2011-01-14T00:00:00.00Z"))
+ .setDataUsage(1000L, TIME_A - DateUtils.YEAR_IN_MILLIS).build());
+ // Usage anchor far in future
+ plans.add(SubscriptionPlan.Builder
+ .createRecurringMonthly(ZonedDateTime.parse("2011-01-14T00:00:00.00Z"))
+ .setDataUsage(1000L, TIME_A + DateUtils.YEAR_IN_MILLIS).build());
+ // Usage anchor near but outside cycle
+ plans.add(SubscriptionPlan.Builder
+ .createNonrecurring(ZonedDateTime.parse("2012-01-09T09:00:00.00Z"),
+ ZonedDateTime.parse("2012-01-09T15:00:00.00Z"))
+ .setDataUsage(1000L, TIME_C).build());
+
+ for (SubscriptionPlan plan : plans) {
+ int i;
+ NetworkStatsHistory history;
+
+ // Empty collection should be untouched
+ history = getHistory(emptyCollection, plan, TIME_A, TIME_C);
+ assertEquals(0L, history.getTotalBytes());
+
+ // Normal collection should be untouched
+ history = getHistory(collection, plan, TIME_A, TIME_C); i = 0;
+ assertEntry(100647, 197, 23649, 185, history.getValues(i++, null));
+ assertEntry(100647, 196, 23648, 185, history.getValues(i++, null));
+ assertEntry(18323, 76, 15032, 76, history.getValues(i++, null));
+ assertEntry(18322, 75, 15031, 75, history.getValues(i++, null));
+ assertEntry(527798, 761, 78570, 652, history.getValues(i++, null));
+ assertEntry(527797, 760, 78570, 651, history.getValues(i++, null));
+ assertEntry(10747, 50, 16838, 55, history.getValues(i++, null));
+ assertEntry(10747, 49, 16838, 54, history.getValues(i++, null));
+ assertEntry(89191, 151, 18021, 140, history.getValues(i++, null));
+ assertEntry(89190, 150, 18020, 139, history.getValues(i++, null));
+ assertEntry(3821, 22, 4525, 26, history.getValues(i++, null));
+ assertEntry(3820, 22, 4524, 26, history.getValues(i++, null));
+ assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
+ assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
+ assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
+ assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
+ assertEntry(113914, 174, 18364, 157, history.getValues(i++, null));
+ assertEntry(113913, 173, 18364, 157, history.getValues(i++, null));
+ assertEntry(11378, 49, 9261, 49, history.getValues(i++, null));
+ assertEntry(11377, 48, 9261, 49, history.getValues(i++, null));
+ assertEntry(201765, 328, 41808, 291, history.getValues(i++, null));
+ assertEntry(201765, 328, 41807, 290, history.getValues(i++, null));
+ assertEntry(106106, 218, 39917, 201, history.getValues(i++, null));
+ assertEntry(106105, 217, 39917, 201, history.getValues(i++, null));
+ assertEquals(history.size(), i);
+
+ // Slice from middle should be untouched
+ history = getHistory(collection, plan, TIME_B - HOUR_IN_MILLIS,
+ TIME_B + HOUR_IN_MILLIS); i = 0;
+ assertEntry(3821, 22, 4525, 26, history.getValues(i++, null));
+ assertEntry(3820, 22, 4524, 26, history.getValues(i++, null));
+ assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
+ assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
+ assertEquals(history.size(), i);
+ }
+
+ // Lower anchor in the middle of plan
+ {
+ int i;
+ NetworkStatsHistory history;
+
+ final SubscriptionPlan plan = SubscriptionPlan.Builder
+ .createNonrecurring(ZonedDateTime.parse("2012-01-09T09:00:00.00Z"),
+ ZonedDateTime.parse("2012-01-09T15:00:00.00Z"))
+ .setDataUsage(200000L, TIME_B).build();
+
+ // Empty collection should be augmented
+ history = getHistory(emptyCollection, plan, TIME_A, TIME_C);
+ assertEquals(200000L, history.getTotalBytes());
+
+ // Normal collection should be augmented
+ history = getHistory(collection, plan, TIME_A, TIME_C); i = 0;
+ assertEntry(100647, 197, 23649, 185, history.getValues(i++, null));
+ assertEntry(100647, 196, 23648, 185, history.getValues(i++, null));
+ assertEntry(18323, 76, 15032, 76, history.getValues(i++, null));
+ assertEntry(18322, 75, 15031, 75, history.getValues(i++, null));
+ assertEntry(527798, 761, 78570, 652, history.getValues(i++, null));
+ assertEntry(527797, 760, 78570, 651, history.getValues(i++, null));
+ // Cycle point; start data normalization
+ assertEntry(7507, 0, 11763, 0, history.getValues(i++, null));
+ assertEntry(7507, 0, 11763, 0, history.getValues(i++, null));
+ assertEntry(62309, 0, 12589, 0, history.getValues(i++, null));
+ assertEntry(62309, 0, 12588, 0, history.getValues(i++, null));
+ assertEntry(2669, 0, 3161, 0, history.getValues(i++, null));
+ assertEntry(2668, 0, 3160, 0, history.getValues(i++, null));
+ // Anchor point; end data normalization
+ assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
+ assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
+ assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
+ assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
+ assertEntry(113914, 174, 18364, 157, history.getValues(i++, null));
+ assertEntry(113913, 173, 18364, 157, history.getValues(i++, null));
+ // Cycle point
+ assertEntry(11378, 49, 9261, 49, history.getValues(i++, null));
+ assertEntry(11377, 48, 9261, 49, history.getValues(i++, null));
+ assertEntry(201765, 328, 41808, 291, history.getValues(i++, null));
+ assertEntry(201765, 328, 41807, 290, history.getValues(i++, null));
+ assertEntry(106106, 218, 39917, 201, history.getValues(i++, null));
+ assertEntry(106105, 217, 39917, 201, history.getValues(i++, null));
+ assertEquals(history.size(), i);
+
+ // Slice from middle should be augmented
+ history = getHistory(collection, plan, TIME_B - HOUR_IN_MILLIS,
+ TIME_B + HOUR_IN_MILLIS); i = 0;
+ assertEntry(2669, 0, 3161, 0, history.getValues(i++, null));
+ assertEntry(2668, 0, 3160, 0, history.getValues(i++, null));
+ assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
+ assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
+ assertEquals(history.size(), i);
+ }
+
+ // Higher anchor in the middle of plan
+ {
+ int i;
+ NetworkStatsHistory history;
+
+ final SubscriptionPlan plan = SubscriptionPlan.Builder
+ .createNonrecurring(ZonedDateTime.parse("2012-01-09T09:00:00.00Z"),
+ ZonedDateTime.parse("2012-01-09T15:00:00.00Z"))
+ .setDataUsage(400000L, TIME_B + MINUTE_IN_MILLIS).build();
+
+ // Empty collection should be augmented
+ history = getHistory(emptyCollection, plan, TIME_A, TIME_C);
+ assertEquals(400000L, history.getTotalBytes());
+
+ // Normal collection should be augmented
+ history = getHistory(collection, plan, TIME_A, TIME_C); i = 0;
+ assertEntry(100647, 197, 23649, 185, history.getValues(i++, null));
+ assertEntry(100647, 196, 23648, 185, history.getValues(i++, null));
+ assertEntry(18323, 76, 15032, 76, history.getValues(i++, null));
+ assertEntry(18322, 75, 15031, 75, history.getValues(i++, null));
+ assertEntry(527798, 761, 78570, 652, history.getValues(i++, null));
+ assertEntry(527797, 760, 78570, 651, history.getValues(i++, null));
+ // Cycle point; start data normalization
+ assertEntry(15015, 0, 23526, 0, history.getValues(i++, null));
+ assertEntry(15015, 0, 23526, 0, history.getValues(i++, null));
+ assertEntry(124619, 0, 25179, 0, history.getValues(i++, null));
+ assertEntry(124618, 0, 25177, 0, history.getValues(i++, null));
+ assertEntry(5338, 0, 6322, 0, history.getValues(i++, null));
+ assertEntry(5337, 0, 6320, 0, history.getValues(i++, null));
+ // Anchor point; end data normalization
+ assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
+ assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
+ assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
+ assertEntry(8289, 35, 6863, 38, history.getValues(i++, null));
+ assertEntry(113914, 174, 18364, 157, history.getValues(i++, null));
+ assertEntry(113913, 173, 18364, 157, history.getValues(i++, null));
+ // Cycle point
+ assertEntry(11378, 49, 9261, 49, history.getValues(i++, null));
+ assertEntry(11377, 48, 9261, 49, history.getValues(i++, null));
+ assertEntry(201765, 328, 41808, 291, history.getValues(i++, null));
+ assertEntry(201765, 328, 41807, 290, history.getValues(i++, null));
+ assertEntry(106106, 218, 39917, 201, history.getValues(i++, null));
+ assertEntry(106105, 217, 39917, 201, history.getValues(i++, null));
+
+ // Slice from middle should be augmented
+ history = getHistory(collection, plan, TIME_B - HOUR_IN_MILLIS,
+ TIME_B + HOUR_IN_MILLIS); i = 0;
+ assertEntry(5338, 0, 6322, 0, history.getValues(i++, null));
+ assertEntry(5337, 0, 6320, 0, history.getValues(i++, null));
+ assertEntry(91686, 159, 18575, 146, history.getValues(i++, null));
+ assertEntry(91685, 159, 18575, 146, history.getValues(i++, null));
+ assertEquals(history.size(), i);
+ }
+ }
+
+ public void testRounding() throws Exception {
+ final NetworkStatsCollection coll = new NetworkStatsCollection(HOUR_IN_MILLIS);
+
+ // Special values should remain unchanged
+ for (long time : new long[] {
+ Long.MIN_VALUE, Long.MAX_VALUE, SubscriptionPlan.TIME_UNKNOWN
+ }) {
+ assertEquals(time, coll.roundUp(time));
+ assertEquals(time, coll.roundDown(time));
+ }
+
+ assertEquals(TIME_A, coll.roundUp(TIME_A));
+ assertEquals(TIME_A, coll.roundDown(TIME_A));
+
+ assertEquals(TIME_A + HOUR_IN_MILLIS, coll.roundUp(TIME_A + 1));
+ assertEquals(TIME_A, coll.roundDown(TIME_A + 1));
+
+ assertEquals(TIME_A, coll.roundUp(TIME_A - 1));
+ assertEquals(TIME_A - HOUR_IN_MILLIS, coll.roundDown(TIME_A - 1));
+ }
+
/**
* Copy a {@link Resources#openRawResource(int)} into {@link File} for
* testing purposes.
@@ -235,28 +455,50 @@ public class NetworkStatsCollectionTest extends AndroidTestCase {
}
}
+ private static NetworkStatsHistory getHistory(NetworkStatsCollection collection,
+ SubscriptionPlan augmentPlan, long start, long end) {
+ return collection.getHistory(buildTemplateMobileAll(TEST_IMSI), augmentPlan, UID_ALL,
+ SET_ALL, TAG_NONE, FIELD_ALL, start, end, NetworkStatsAccess.Level.DEVICE, myUid());
+ }
+
private static void assertSummaryTotal(NetworkStatsCollection collection,
NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets,
@NetworkStatsAccess.Level int accessLevel) {
- final NetworkStats.Entry entry = collection.getSummary(
- template, Long.MIN_VALUE, Long.MAX_VALUE, accessLevel)
+ final NetworkStats.Entry actual = collection.getSummary(
+ template, Long.MIN_VALUE, Long.MAX_VALUE, accessLevel, myUid())
.getTotal(null);
- assertEntry(entry, rxBytes, rxPackets, txBytes, txPackets);
+ assertEntry(rxBytes, rxPackets, txBytes, txPackets, actual);
}
private static void assertSummaryTotalIncludingTags(NetworkStatsCollection collection,
NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets) {
- final NetworkStats.Entry entry = collection.getSummary(
- template, Long.MIN_VALUE, Long.MAX_VALUE, NetworkStatsAccess.Level.DEVICE)
+ final NetworkStats.Entry actual = collection.getSummary(
+ template, Long.MIN_VALUE, Long.MAX_VALUE, NetworkStatsAccess.Level.DEVICE, myUid())
.getTotalIncludingTags(null);
- assertEntry(entry, rxBytes, rxPackets, txBytes, txPackets);
+ assertEntry(rxBytes, rxPackets, txBytes, txPackets, actual);
+ }
+
+ private static void assertEntry(long rxBytes, long rxPackets, long txBytes, long txPackets,
+ NetworkStats.Entry actual) {
+ assertEntry(new NetworkStats.Entry(rxBytes, rxPackets, txBytes, txPackets, 0L), actual);
+ }
+
+ private static void assertEntry(long rxBytes, long rxPackets, long txBytes, long txPackets,
+ NetworkStatsHistory.Entry actual) {
+ assertEntry(new NetworkStats.Entry(rxBytes, rxPackets, txBytes, txPackets, 0L), actual);
+ }
+
+ private static void assertEntry(NetworkStats.Entry expected,
+ NetworkStatsHistory.Entry actual) {
+ assertEntry(expected, new NetworkStats.Entry(actual.rxBytes, actual.rxPackets,
+ actual.txBytes, actual.txPackets, 0L));
}
- private static void assertEntry(
- NetworkStats.Entry entry, long rxBytes, long rxPackets, long txBytes, long txPackets) {
- assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes);
- assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets);
- assertEquals("unexpected txBytes", txBytes, entry.txBytes);
- assertEquals("unexpected txPackets", txPackets, entry.txPackets);
+ private static void assertEntry(NetworkStats.Entry expected,
+ NetworkStats.Entry actual) {
+ assertEquals("unexpected rxBytes", expected.rxBytes, actual.rxBytes);
+ assertEquals("unexpected rxPackets", expected.rxPackets, actual.rxPackets);
+ assertEquals("unexpected txBytes", expected.txBytes, actual.txBytes);
+ assertEquals("unexpected txPackets", expected.txPackets, actual.txPackets);
}
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index fa997958ba6d..814a62663333 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -46,19 +46,17 @@ import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
-import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
import static com.android.internal.util.TestUtils.waitForIdleHandler;
+import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Mockito.when;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.app.AlarmManager;
import android.app.usage.NetworkStatsManager;
@@ -79,24 +77,21 @@ import android.net.NetworkTemplate;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
-import android.os.INetworkManagementService;
import android.os.IBinder;
+import android.os.INetworkManagementService;
import android.os.Looper;
-import android.os.Messenger;
-import android.os.MessageQueue;
-import android.os.MessageQueue.IdleHandler;
import android.os.Message;
+import android.os.Messenger;
import android.os.PowerManager;
import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.telephony.TelephonyManager;
-import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
import android.util.TrustedTime;
import com.android.internal.net.VpnInfo;
import com.android.internal.util.test.BroadcastInterceptingContext;
-import com.android.server.net.NetworkStatsService;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;
@@ -112,9 +107,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.io.File;
-import java.util.ArrayList;
import java.util.Objects;
-import java.util.List;
/**
* Tests for {@link NetworkStatsService}.
@@ -983,7 +976,7 @@ public class NetworkStatsServiceTest {
// verify summary API
final NetworkStats stats = mSession.getSummaryForNetwork(template, start, end);
- assertValues(stats, IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_NO,
+ assertValues(stats, IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL,
rxBytes, rxPackets, txBytes, txPackets, operations);
}
@@ -1107,28 +1100,25 @@ public class NetworkStatsServiceTest {
int tag, int metered, int roaming, long rxBytes, long rxPackets, long txBytes,
long txPackets, int operations) {
final NetworkStats.Entry entry = new NetworkStats.Entry();
- List<Integer> sets = new ArrayList<>();
- if (set == SET_DEFAULT || set == SET_ALL) {
- sets.add(SET_DEFAULT);
- }
- if (set == SET_FOREGROUND || set == SET_ALL) {
- sets.add(SET_FOREGROUND);
+ final int[] sets;
+ if (set == SET_ALL) {
+ sets = new int[] { SET_ALL, SET_DEFAULT, SET_FOREGROUND };
+ } else {
+ sets = new int[] { set };
}
- List<Integer> roamings = new ArrayList<>();
- if (roaming == ROAMING_NO || roaming == ROAMING_ALL) {
- roamings.add(ROAMING_NO);
- }
- if (roaming == ROAMING_YES || roaming == ROAMING_ALL) {
- roamings.add(ROAMING_YES);
+ final int[] roamings;
+ if (roaming == ROAMING_ALL) {
+ roamings = new int[] { ROAMING_ALL, ROAMING_YES, ROAMING_NO };
+ } else {
+ roamings = new int[] { roaming };
}
- List<Integer> meterings = new ArrayList<>();
- if (metered == METERED_NO || metered == METERED_ALL) {
- meterings.add(METERED_NO);
- }
- if (metered == METERED_YES || metered == METERED_ALL) {
- meterings.add(METERED_YES);
+ final int[] meterings;
+ if (metered == METERED_ALL) {
+ meterings = new int[] { METERED_ALL, METERED_YES, METERED_NO };
+ } else {
+ meterings = new int[] { metered };
}
for (int s : sets) {
diff --git a/tools/aapt/AaptXml.cpp b/tools/aapt/AaptXml.cpp
index b04a55d91b9c..6801a4ec7325 100644
--- a/tools/aapt/AaptXml.cpp
+++ b/tools/aapt/AaptXml.cpp
@@ -99,24 +99,40 @@ String8 getResolvedAttribute(const ResTable& resTable, const ResXMLTree& tree,
if (idx < 0) {
return String8();
}
+
Res_value value;
- if (tree.getAttributeValue(idx, &value) != NO_ERROR) {
- if (value.dataType == Res_value::TYPE_STRING) {
- size_t len;
- const char16_t* str = tree.getAttributeStringValue(idx, &len);
- return str ? String8(str, len) : String8();
+ if (tree.getAttributeValue(idx, &value) == BAD_TYPE) {
+ if (outError != NULL) {
+ *outError = "attribute value is corrupt";
}
- resTable.resolveReference(&value, 0);
- if (value.dataType != Res_value::TYPE_STRING) {
- if (outError != NULL) {
- *outError = "attribute is not a string value";
- }
- return String8();
+ return String8();
+ }
+
+ // Check if the string is inline in the XML.
+ if (value.dataType == Res_value::TYPE_STRING) {
+ size_t len;
+ const char16_t* str = tree.getAttributeStringValue(idx, &len);
+ return str ? String8(str, len) : String8();
+ }
+
+ // Resolve the reference if there is one.
+ ssize_t block = resTable.resolveReference(&value, 0);
+ if (block < 0) {
+ if (outError != NULL) {
+ *outError = "attribute value reference does not exist";
+ }
+ return String8();
+ }
+
+ if (value.dataType != Res_value::TYPE_STRING) {
+ if (outError != NULL) {
+ *outError = "attribute is not a string value";
}
+ return String8();
}
+
size_t len;
- const Res_value* value2 = &value;
- const char16_t* str = resTable.valueToString(value2, 0, NULL, &len);
+ const char16_t* str = resTable.valueToString(&value, static_cast<size_t>(block), NULL, &len);
return str ? String8(str, len) : String8();
}
diff --git a/tools/aapt/SdkConstants.h b/tools/aapt/SdkConstants.h
index bf56ec024699..b982d0d2ea63 100644
--- a/tools/aapt/SdkConstants.h
+++ b/tools/aapt/SdkConstants.h
@@ -43,6 +43,7 @@ enum {
SDK_NOUGAT_MR1 = 25,
SDK_O = 26,
SDK_O_MR1 = 27,
+ SDK_P = 10000, // STOPSHIP Replace with the real version.
};
#endif // H_AAPT_SDK_CONSTANTS
diff --git a/tools/aapt2/SdkConstants.h b/tools/aapt2/SdkConstants.h
index 5c32ed4fd849..13584c0bf840 100644
--- a/tools/aapt2/SdkConstants.h
+++ b/tools/aapt2/SdkConstants.h
@@ -53,6 +53,7 @@ enum : ApiVersion {
SDK_NOUGAT_MR1 = 25,
SDK_O = 26,
SDK_O_MR1 = 27,
+ SDK_P = 10000, // STOPSHIP Replace with the real version.
};
ApiVersion FindAttributeSdkLevel(const ResourceId& id);
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index 84b79274b9a6..887803e147da 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -323,11 +323,13 @@ int Optimize(const std::vector<StringPiece>& args) {
std::vector<std::string> configs;
std::vector<std::string> split_args;
bool verbose = false;
+ bool print_only = false;
Flags flags =
Flags()
.OptionalFlag("-o", "Path to the output APK.", &options.output_path)
.OptionalFlag("-d", "Path to the output directory (for splits).", &options.output_dir)
.OptionalFlag("-x", "Path to XML configuration file.", &config_path)
+ .OptionalSwitch("-p", "Print the multi APK artifacts and exit.", &print_only)
.OptionalFlag(
"--target-densities",
"Comma separated list of the screen densities that the APK will be optimized for.\n"
@@ -372,12 +374,12 @@ int Optimize(const std::vector<StringPiece>& args) {
}
context.SetVerbose(verbose);
+ IDiagnostics* diag = context.GetDiagnostics();
if (target_densities) {
// Parse the target screen densities.
for (const StringPiece& config_str : util::Tokenize(target_densities.value(), ',')) {
- Maybe<uint16_t> target_density =
- ParseTargetDensityParameter(config_str, context.GetDiagnostics());
+ Maybe<uint16_t> target_density = ParseTargetDensityParameter(config_str, diag);
if (!target_density) {
return 1;
}
@@ -387,7 +389,7 @@ int Optimize(const std::vector<StringPiece>& args) {
std::unique_ptr<IConfigFilter> filter;
if (!configs.empty()) {
- filter = ParseConfigFilterParameters(configs, context.GetDiagnostics());
+ filter = ParseConfigFilterParameters(configs, diag);
if (filter == nullptr) {
return 1;
}
@@ -398,26 +400,45 @@ int Optimize(const std::vector<StringPiece>& args) {
for (const std::string& split_arg : split_args) {
options.split_paths.emplace_back();
options.split_constraints.emplace_back();
- if (!ParseSplitParameter(split_arg, context.GetDiagnostics(), &options.split_paths.back(),
+ if (!ParseSplitParameter(split_arg, diag, &options.split_paths.back(),
&options.split_constraints.back())) {
return 1;
}
}
if (config_path) {
- if (!options.output_dir) {
- context.GetDiagnostics()->Error(
- DiagMessage() << "Output directory is required when using a configuration file");
- return 1;
- }
std::string& path = config_path.value();
Maybe<ConfigurationParser> for_path = ConfigurationParser::ForPath(path);
if (for_path) {
- options.configuration = for_path.value().WithDiagnostics(context.GetDiagnostics()).Parse();
+ options.configuration = for_path.value().WithDiagnostics(diag).Parse();
} else {
- context.GetDiagnostics()->Error(DiagMessage() << "Could not parse config file " << path);
+ diag->Error(DiagMessage() << "Could not parse config file " << path);
+ return 1;
+ }
+
+ if (print_only) {
+ std::vector<std::string> names;
+ const PostProcessingConfiguration& config = options.configuration.value();
+ if (!config.AllArtifactNames(file::GetFilename(apk_path), &names, diag)) {
+ diag->Error(DiagMessage() << "Failed to generate output artifact list");
+ return 1;
+ }
+
+ for (const auto& name : names) {
+ std::cout << name << std::endl;
+ }
+ return 0;
+ }
+
+ // Since we know that we are going to process the APK (not just print targets), make sure we
+ // have somewhere to write them to.
+ if (!options.output_dir) {
+ diag->Error(DiagMessage() << "Output directory is required when using a configuration file");
return 1;
}
+ } else if (print_only) {
+ diag->Error(DiagMessage() << "Asked to print artifacts without providing a configurations");
+ return 1;
}
if (!ExtractAppDataFromManifest(&context, apk.get(), &options)) {
diff --git a/tools/aapt2/configuration/ConfigurationParser.cpp b/tools/aapt2/configuration/ConfigurationParser.cpp
index 424e9be3ef09..1735a504e553 100644
--- a/tools/aapt2/configuration/ConfigurationParser.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser.cpp
@@ -30,6 +30,7 @@
#include "io/File.h"
#include "io/FileSystem.h"
#include "io/StringInputStream.h"
+#include "util/Files.h"
#include "util/Maybe.h"
#include "util/Util.h"
#include "xml/XmlActionExecutor.h"
@@ -149,23 +150,48 @@ static bool ReplacePlaceholder(const StringPiece& placeholder, const Maybe<Strin
return true;
}
-Maybe<std::string> Artifact::ToArtifactName(const StringPiece& format, IDiagnostics* diag,
- const StringPiece& base_name,
- const StringPiece& ext) const {
- std::string result = format.to_string();
+/**
+ * Returns the common artifact base name from a template string.
+ */
+Maybe<std::string> ToBaseName(std::string result, const StringPiece& apk_name, IDiagnostics* diag) {
+ const StringPiece ext = file::GetExtension(apk_name);
+ size_t end_index = apk_name.to_string().rfind(ext.to_string());
+ const std::string base_name =
+ (end_index != std::string::npos) ? std::string{apk_name.begin(), end_index} : "";
- Maybe<StringPiece> maybe_base_name =
- base_name.empty() ? Maybe<StringPiece>{} : Maybe<StringPiece>{base_name};
- if (!ReplacePlaceholder("${basename}", maybe_base_name, &result, diag)) {
- return {};
+ // Base name is optional.
+ if (result.find("${basename}") != std::string::npos) {
+ Maybe<StringPiece> maybe_base_name =
+ base_name.empty() ? Maybe<StringPiece>{} : Maybe<StringPiece>{base_name};
+ if (!ReplacePlaceholder("${basename}", maybe_base_name, &result, diag)) {
+ return {};
+ }
}
// Extension is optional.
if (result.find("${ext}") != std::string::npos) {
- if (!ReplacePlaceholder("${ext}", {ext}, &result, diag)) {
+ // Make sure we disregard the '.' in the extension when replacing the placeholder.
+ if (!ReplacePlaceholder("${ext}", {ext.substr(1)}, &result, diag)) {
return {};
}
+ } else {
+ // If no extension is specified, and the name template does not end in the current extension,
+ // add the existing extension.
+ if (!util::EndsWith(result, ext)) {
+ result.append(ext.to_string());
+ }
+ }
+
+ return result;
+}
+
+Maybe<std::string> Artifact::ToArtifactName(const StringPiece& format, const StringPiece& apk_name,
+ IDiagnostics* diag) const {
+ Maybe<std::string> base = ToBaseName(format.to_string(), apk_name, diag);
+ if (!base) {
+ return {};
}
+ std::string result = std::move(base.value());
if (!ReplacePlaceholder("${abi}", abi_group, &result, diag)) {
return {};
@@ -194,29 +220,37 @@ Maybe<std::string> Artifact::ToArtifactName(const StringPiece& format, IDiagnost
return result;
}
-Maybe<std::string> Artifact::Name(const StringPiece& base_name, const StringPiece& ext,
- IDiagnostics* diag) const {
+Maybe<std::string> Artifact::Name(const StringPiece& apk_name, IDiagnostics* diag) const {
if (!name) {
return {};
}
- std::string result = name.value();
+ return ToBaseName(name.value(), apk_name, diag);
+}
- // Base name is optional.
- if (result.find("${basename}") != std::string::npos) {
- if (!ReplacePlaceholder("${basename}", {base_name}, &result, diag)) {
- return {};
+bool PostProcessingConfiguration::AllArtifactNames(const StringPiece& apk_name,
+ std::vector<std::string>* artifact_names,
+ IDiagnostics* diag) const {
+ for (const auto& artifact : artifacts) {
+ Maybe<std::string> name;
+ if (artifact.name) {
+ name = artifact.Name(apk_name, diag);
+ } else {
+ if (!artifact_format) {
+ diag->Error(DiagMessage() << "No global artifact template and an artifact name is missing");
+ return false;
+ }
+ name = artifact.ToArtifactName(artifact_format.value(), apk_name, diag);
}
- }
- // Extension is optional.
- if (result.find("${ext}") != std::string::npos) {
- if (!ReplacePlaceholder("${ext}", {ext}, &result, diag)) {
- return {};
+ if (!name) {
+ return false;
}
+
+ artifact_names->push_back(std::move(name.value()));
}
- return result;
+ return true;
}
} // namespace configuration
diff --git a/tools/aapt2/configuration/ConfigurationParser.h b/tools/aapt2/configuration/ConfigurationParser.h
index 6259ce8e28ea..a58685e3b8a6 100644
--- a/tools/aapt2/configuration/ConfigurationParser.h
+++ b/tools/aapt2/configuration/ConfigurationParser.h
@@ -51,13 +51,11 @@ struct Artifact {
Maybe<std::string> gl_texture_group;
/** Convert an artifact name template into a name string based on configuration contents. */
- Maybe<std::string> ToArtifactName(const android::StringPiece& format, IDiagnostics* diag,
- const android::StringPiece& base_name = "",
- const android::StringPiece& ext = "apk") const;
+ Maybe<std::string> ToArtifactName(const android::StringPiece& format,
+ const android::StringPiece& apk_name, IDiagnostics* diag) const;
/** Convert an artifact name template into a name string based on configuration contents. */
- Maybe<std::string> Name(const android::StringPiece& base_name, const android::StringPiece& ext,
- IDiagnostics* diag) const;
+ Maybe<std::string> Name(const android::StringPiece& apk_name, IDiagnostics* diag) const;
};
/** Enumeration of currently supported ABIs. */
@@ -139,6 +137,10 @@ struct PostProcessingConfiguration {
Group<AndroidSdk> android_sdk_groups;
Group<DeviceFeature> device_feature_groups;
Group<GlTexture> gl_texture_groups;
+
+ /** Helper method that generates a list of artifact names and returns true on success. */
+ bool AllArtifactNames(const android::StringPiece& apk_name,
+ std::vector<std::string>* artifact_names, IDiagnostics* diag) const;
};
} // namespace configuration
diff --git a/tools/aapt2/configuration/ConfigurationParser_test.cpp b/tools/aapt2/configuration/ConfigurationParser_test.cpp
index ece70a9e42ba..d3bfd330fe9d 100644
--- a/tools/aapt2/configuration/ConfigurationParser_test.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser_test.cpp
@@ -414,16 +414,36 @@ TEST(ArtifactTest, Simple) {
Artifact x86;
x86.abi_group = {"x86"};
- auto x86_result = x86.ToArtifactName("something.${abi}.apk", &diag);
+ auto x86_result = x86.ToArtifactName("something.${abi}.apk", "", &diag);
ASSERT_TRUE(x86_result);
EXPECT_EQ(x86_result.value(), "something.x86.apk");
Artifact arm;
arm.abi_group = {"armeabi-v7a"};
- auto arm_result = arm.ToArtifactName("app.${abi}.apk", &diag);
- ASSERT_TRUE(arm_result);
- EXPECT_EQ(arm_result.value(), "app.armeabi-v7a.apk");
+ {
+ auto arm_result = arm.ToArtifactName("app.${abi}.apk", "", &diag);
+ ASSERT_TRUE(arm_result);
+ EXPECT_EQ(arm_result.value(), "app.armeabi-v7a.apk");
+ }
+
+ {
+ auto arm_result = arm.ToArtifactName("app.${abi}.apk", "different_name.apk", &diag);
+ ASSERT_TRUE(arm_result);
+ EXPECT_EQ(arm_result.value(), "app.armeabi-v7a.apk");
+ }
+
+ {
+ auto arm_result = arm.ToArtifactName("${basename}.${abi}.apk", "app.apk", &diag);
+ ASSERT_TRUE(arm_result);
+ EXPECT_EQ(arm_result.value(), "app.armeabi-v7a.apk");
+ }
+
+ {
+ auto arm_result = arm.ToArtifactName("app.${abi}.${ext}", "app.apk", &diag);
+ ASSERT_TRUE(arm_result);
+ EXPECT_EQ(arm_result.value(), "app.armeabi-v7a.apk");
+ }
}
TEST(ArtifactTest, Complex) {
@@ -436,10 +456,40 @@ TEST(ArtifactTest, Complex) {
artifact.locale_group = {"en-AU"};
artifact.android_sdk_group = {"26"};
- auto result = artifact.ToArtifactName(
- "app.${density}_${locale}_${feature}_${gl}.sdk${sdk}.${abi}.apk", &diag);
- ASSERT_TRUE(result);
- EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.sdk26.mips64.apk");
+ {
+ auto result = artifact.ToArtifactName(
+ "app.${density}_${locale}_${feature}_${gl}.sdk${sdk}.${abi}.apk", "", &diag);
+ ASSERT_TRUE(result);
+ EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.sdk26.mips64.apk");
+ }
+
+ {
+ auto result = artifact.ToArtifactName(
+ "app.${density}_${locale}_${feature}_${gl}.sdk${sdk}.${abi}.apk", "app.apk", &diag);
+ ASSERT_TRUE(result);
+ EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.sdk26.mips64.apk");
+ }
+
+ {
+ auto result = artifact.ToArtifactName(
+ "${basename}.${density}_${locale}_${feature}_${gl}.sdk${sdk}.${abi}.apk", "app.apk", &diag);
+ ASSERT_TRUE(result);
+ EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.sdk26.mips64.apk");
+ }
+
+ {
+ auto result = artifact.ToArtifactName(
+ "app.${density}_${locale}_${feature}_${gl}.sdk${sdk}.${abi}.${ext}", "app.apk", &diag);
+ ASSERT_TRUE(result);
+ EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.sdk26.mips64.apk");
+ }
+
+ {
+ auto result = artifact.ToArtifactName(
+ "${basename}.${density}_${locale}_${feature}_${gl}.sdk${sdk}.${abi}", "app.apk", &diag);
+ ASSERT_TRUE(result);
+ EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.sdk26.mips64.apk");
+ }
}
TEST(ArtifactTest, Missing) {
@@ -447,16 +497,20 @@ TEST(ArtifactTest, Missing) {
Artifact x86;
x86.abi_group = {"x86"};
- EXPECT_FALSE(x86.ToArtifactName("something.${density}.apk", &diag));
- EXPECT_FALSE(x86.ToArtifactName("something.apk", &diag));
+ EXPECT_FALSE(x86.ToArtifactName("something.${density}.apk", "", &diag));
+ EXPECT_FALSE(x86.ToArtifactName("something.apk", "", &diag));
+ EXPECT_FALSE(x86.ToArtifactName("something.${density}.apk", "something.apk", &diag));
+ EXPECT_FALSE(x86.ToArtifactName("something.apk", "something.apk", &diag));
}
TEST(ArtifactTest, Empty) {
StdErrDiagnostics diag;
Artifact artifact;
- EXPECT_FALSE(artifact.ToArtifactName("something.${density}.apk", &diag));
- EXPECT_TRUE(artifact.ToArtifactName("something.apk", &diag));
+ EXPECT_FALSE(artifact.ToArtifactName("something.${density}.apk", "", &diag));
+ EXPECT_TRUE(artifact.ToArtifactName("something.apk", "", &diag));
+ EXPECT_FALSE(artifact.ToArtifactName("something.${density}.apk", "something.apk", &diag));
+ EXPECT_TRUE(artifact.ToArtifactName("something.apk", "something.apk", &diag));
}
TEST(ArtifactTest, Repeated) {
@@ -464,8 +518,9 @@ TEST(ArtifactTest, Repeated) {
Artifact artifact;
artifact.screen_density_group = {"mdpi"};
- ASSERT_TRUE(artifact.ToArtifactName("something.${density}.apk", &diag));
- EXPECT_FALSE(artifact.ToArtifactName("something.${density}.${density}.apk", &diag));
+ ASSERT_TRUE(artifact.ToArtifactName("something.${density}.apk", "", &diag));
+ EXPECT_FALSE(artifact.ToArtifactName("something.${density}.${density}.apk", "", &diag));
+ ASSERT_TRUE(artifact.ToArtifactName("something.${density}.apk", "something.apk", &diag));
}
TEST(ArtifactTest, Nesting) {
@@ -473,9 +528,9 @@ TEST(ArtifactTest, Nesting) {
Artifact x86;
x86.abi_group = {"x86"};
- EXPECT_FALSE(x86.ToArtifactName("something.${abi${density}}.apk", &diag));
+ EXPECT_FALSE(x86.ToArtifactName("something.${abi${density}}.apk", "", &diag));
- const Maybe<std::string>& name = x86.ToArtifactName("something.${abi${abi}}.apk", &diag);
+ const Maybe<std::string>& name = x86.ToArtifactName("something.${abi${abi}}.apk", "", &diag);
ASSERT_TRUE(name);
EXPECT_EQ(name.value(), "something.${abix86}.apk");
}
@@ -486,12 +541,12 @@ TEST(ArtifactTest, Recursive) {
artifact.device_feature_group = {"${gl}"};
artifact.gl_texture_group = {"glx1"};
- EXPECT_FALSE(artifact.ToArtifactName("app.${feature}.${gl}.apk", &diag));
+ EXPECT_FALSE(artifact.ToArtifactName("app.${feature}.${gl}.apk", "", &diag));
artifact.device_feature_group = {"df1"};
artifact.gl_texture_group = {"${feature}"};
{
- const auto& result = artifact.ToArtifactName("app.${feature}.${gl}.apk", &diag);
+ const auto& result = artifact.ToArtifactName("app.${feature}.${gl}.apk", "", &diag);
ASSERT_TRUE(result);
EXPECT_EQ(result.value(), "app.df1.${feature}.apk");
}
@@ -501,7 +556,7 @@ TEST(ArtifactTest, Recursive) {
artifact.device_feature_group = {"${gl}"};
artifact.gl_texture_group = {"glx1"};
{
- const auto& result = artifact.ToArtifactName("app.${feature}.apk", &diag);
+ const auto& result = artifact.ToArtifactName("app.${feature}.apk", "", &diag);
ASSERT_TRUE(result);
EXPECT_EQ(result.value(), "app.glx1.apk");
}
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index a0ffefad1e1c..6fb1793d90ed 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -293,6 +293,7 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
manifest_action["instrumentation"]["meta-data"] = meta_data_action;
manifest_action["original-package"];
+ manifest_action["overlay"];
manifest_action["protected-broadcast"];
manifest_action["uses-permission"];
manifest_action["uses-permission-sdk-23"];
diff --git a/tools/aapt2/optimize/MultiApkGenerator.cpp b/tools/aapt2/optimize/MultiApkGenerator.cpp
index f413ee960264..e7a4f8578529 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator.cpp
@@ -44,11 +44,11 @@ bool MultiApkGenerator::FromBaseApk(const std::string& out_dir,
const PostProcessingConfiguration& config,
const TableFlattenerOptions& table_flattener_options) {
// TODO(safarmer): Handle APK version codes for the generated APKs.
- // TODO(safarmer): Handle explicit outputs/generating an output file list for other tools.
+ IDiagnostics* diag = context_->GetDiagnostics();
- const std::string& apk_path = apk_->GetSource().path;
- const StringPiece ext = file::GetExtension(apk_path);
- const std::string base_name = apk_path.substr(0, apk_path.rfind(ext.to_string()));
+ const std::string& apk_name = file::GetFilename(apk_->GetSource().path).to_string();
+ const StringPiece ext = file::GetExtension(apk_name);
+ const std::string base_name = apk_name.substr(0, apk_name.rfind(ext.to_string()));
// For now, just write out the stripped APK since ABI splitting doesn't modify anything else.
for (const Artifact& artifact : config.artifacts) {
@@ -57,20 +57,17 @@ bool MultiApkGenerator::FromBaseApk(const std::string& out_dir,
AxisConfigFilter axis_filter;
if (!artifact.name && !config.artifact_format) {
- context_->GetDiagnostics()->Error(
+ diag->Error(
DiagMessage() << "Artifact does not have a name and no global name template defined");
return false;
}
Maybe<std::string> artifact_name =
- (artifact.name)
- ? artifact.Name(base_name, ext.substr(1), context_->GetDiagnostics())
- : artifact.ToArtifactName(config.artifact_format.value(), context_->GetDiagnostics(),
- base_name, ext.substr(1));
+ (artifact.name) ? artifact.Name(apk_name, diag)
+ : artifact.ToArtifactName(config.artifact_format.value(), apk_name, diag);
if (!artifact_name) {
- context_->GetDiagnostics()->Error(DiagMessage()
- << "Could not determine split APK artifact name");
+ diag->Error(DiagMessage() << "Could not determine split APK artifact name");
return false;
}
@@ -80,8 +77,7 @@ bool MultiApkGenerator::FromBaseApk(const std::string& out_dir,
auto group = config.abi_groups.find(group_name);
// TODO: Remove validation when configuration parser ensures referential integrity.
if (group == config.abi_groups.end()) {
- context_->GetDiagnostics()->Error(DiagMessage() << "could not find referenced ABI group '"
- << group_name << "'");
+ diag->Error(DiagMessage() << "could not find referenced ABI group '" << group_name << "'");
return false;
}
filters.AddFilter(AbiFilter::FromAbiList(group->second));
@@ -93,8 +89,7 @@ bool MultiApkGenerator::FromBaseApk(const std::string& out_dir,
auto group = config.screen_density_groups.find(group_name);
// TODO: Remove validation when configuration parser ensures referential integrity.
if (group == config.screen_density_groups.end()) {
- context_->GetDiagnostics()->Error(DiagMessage() << "could not find referenced group '"
- << group_name << "'");
+ diag->Error(DiagMessage() << "could not find referenced group '" << group_name << "'");
return false;
}
@@ -109,8 +104,7 @@ bool MultiApkGenerator::FromBaseApk(const std::string& out_dir,
auto group = config.locale_groups.find(group_name);
// TODO: Remove validation when configuration parser ensures referential integrity.
if (group == config.locale_groups.end()) {
- context_->GetDiagnostics()->Error(DiagMessage() << "could not find referenced group '"
- << group_name << "'");
+ diag->Error(DiagMessage() << "could not find referenced group '" << group_name << "'");
return false;
}
@@ -122,17 +116,20 @@ bool MultiApkGenerator::FromBaseApk(const std::string& out_dir,
std::unique_ptr<ResourceTable> table = apk_->GetResourceTable()->Clone();
+
TableSplitter splitter{{}, splits};
splitter.SplitTable(table.get());
std::string out = out_dir;
+ if (!file::mkdirs(out)) {
+ context_->GetDiagnostics()->Warn(DiagMessage() << "could not create out dir: " << out);
+ }
file::AppendPath(&out, artifact_name.value());
- std::unique_ptr<IArchiveWriter> writer =
- CreateZipFileArchiveWriter(context_->GetDiagnostics(), out);
+ std::unique_ptr<IArchiveWriter> writer = CreateZipFileArchiveWriter(diag, out);
if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage() << "Writing output: " << out);
+ diag->Note(DiagMessage() << "Writing output: " << out);
}
if (!apk_->WriteToArchive(context_, table.get(), table_flattener_options, &filters,